前言:
最近在学习Python网络爬虫,在这里分享一下自己的学习成果,通过几个函数梳理下网络爬虫的过程,网络爬虫就是用自己的电脑去web服务器(另一台电脑)上下载东西,其中涉及到两个问题:
(1)怎么让自己的电脑和web服务器连接
(2)正常连接之后,怎么把想要的信息提取出来
爬虫相关函数:
def get_html_text(url): #解决第一个问题
pass
def get_info_list(html): #解决第二个问题
pass
def print_info_list(info_list): #def download_info_list(info_list):
pass
接下来,就让我们围绕这两个问题和三个函数,去看看Python是怎么解决的。
示例代码:列举了6个实际的爬虫例子(基本只用到上面三个函数)
requests获取html:
我们想要的资源,比如文字、图片等,其实都在html里面。一个网页的url,对应一个html,我们可以通过requests库,轻松地和服务器上的url建立连接,得到html信息。通过Response对象的status_code、text、encoding、content等方法,查看这次连接的情况如何。
def get_html_text(url):
try:
r = requests.get(url, timeout=30)
r.raise_for_status
r.encoding = r.apparent_encoding
return r.text
except:
return "requests error"
但是,该函数返回的是一个str类型的html,这是非常不方便我们获取信息的
BeautifulSoup解析html:
html页面得到了,我们的爬虫就完成了一半了。。。哈哈,开玩笑的,其实爬虫最难的地方就在定位信息,特别是定位大量信息的时候。不过不着急,BeautifulSoup很好地帮我们解决了这个问题。它可以解析我们通过requests获得的str类型的html,使其成为一个真正的html,我们可以通过标签的属性或名称去定位标签,可以定位标签之后,获取信息就方便多了。
def get_info_list(html):
"""
获取目标图片的url链接
"""
soup = BeautifulSoup(html,"html.parser")
img_tags = soup.find_all("noscript")
img_urls = []
for tag in img_tags:
try:
img_urls.append(re.findall(r'src=".*?"',tag.get_text())[0][5:-1])
except:
continue
return img_urls
在上面的代码中,除了用标签名字定位标签外,还使用了正则表达式来辅助我们找到想要的信息。上图可以看出,图片url在src属性上,可以愉快地下载小姐姐的美照了。
值得注意的是,定位标签是网络爬虫中很重要的一件事,我给出的几个爬虫demo中都有体现。通过要找的信息,到跟信息相关的标签,再到标签之间的逻辑关系,都值得我们仔细思考。选取哪个标签,才能通过一次遍历就可以得到我们想要的所有的信息,而且还没有冗余信息呢?
再举一个例子说明这个问题
def get_info_list(html):
ulist = []
soup = BeautifulSoup(html,'html.parser')
for tr in soup.find('tbody').children:
if isinstance(tr,bs4.element.Tag):
tds = tr.find_all('td')
ulist.append([tds[0].string,tds[1].string,tds[2].string])
return ulist
这个例子是爬取中国大学的排名信息,从图中可以看出所有大学的信息都在tbody一个标签里,而tbody有好多子标签tr,每一个tr存储的是一个学校的各种信息,那么逻辑就很清楚了,只要遍历tbody的每一个子标签tr,就可以通过一个循环,得到我们想要的所有信息了。
print or download?
接下来的事就比较简单了,数据量较少可以选择打印出来,数据如果是图片等二进制文件可以选择下载到本地
def print_info_list(ulist,num):
tplt = '{0:^10}\t{1:{3}^10}\t{2:^10}\t'
print(tplt.format('排名','学校名称','省份',chr(12288)))
for i in range(num):
u = ulist[i]
print(tplt.format(u[0],u[1],u[2],chr(12288)))
def download_imgs(img_urls):
start_name = 0
root = "./images001/"
for url in img_urls:
if not os.path.exists(root):
os.mkdir(root)
path = root + str(start_name) + ".jpg"
r = requests.get(url)
with open(path, "wb") as f:
f.write(r.content)
start_name += 1
进阶:
在爬取Github Python Trending和知乎图片的时候,涉及到几个有趣的问题:
(1)在爬取到一个url的时候,我们可以通过python命令的方式打开这个链接,而不需要手动打开,是不是很酷呢,通过webbrowser.open就可以实现。
(2)爬取网页的时候,我们可能需要模拟鼠标滑动的操作,来获取更多信息,这个时候需要用到selenium,来自动运行JS脚本,完成鼠标滑动的操作
展望:
(1)在与web服务器连接的时候,公司肯定会设置很多障碍(robots协议等)。因为如果让别人无限制爬虫的话,对公司的网站是有很大影响的。在以后的学习里,反爬技巧和分布式爬虫(框架如Scrapy等)是我们要研究的,从而可以更好更快的爬取想要的信息
(2)在与网页的交互中,会涉及到大量的JS函数,要想爬虫更加顺利,对JS函数要很熟悉
(3)数据的存储问题,数据量大的话,肯定要存在数据库里里的