其实一年前就已经接触了爬虫,当时是想上手Python,然后想着在实践中学习是一种比较快的上手方式,看了下Python比较适合写爬虫,于是学会了怎样爬取一些反爬不那么厉害的网页。当初是看的MOOC课程视频,涵盖了入门所需的知识,这一年来不时会用到一些爬虫,有时一些爬虫代码让一些事情方便了许多。之前一直记在笔记本上,现在既然在简书上建了一个爬虫的文集,那么我就简单把笔记总结一下,放到这篇文章里面
这里只包含最基本的爬虫笔记,有了这些可以爬取一些反爬措施不那么严格的网站,后续进阶的话还有很多需要接触,像Scrapy框架,手机抓包,异步爬虫,处理JavaScript加密的表单数据等
发送请求
requests
这个库让发送请求变得十分简单,想要访问某个页面,使用
r = requests.get(url)
就可以实现,之后,可以进行下列的一些操作:
- 查看访问的状态码:
r.status_code
,一般200
代表成功访问 - 指定解析页面用的编码:
r.encoding = 'gbk'
- 获得访问之后定向到的链接,比如访问之后有重定向,就可以用这个语句获取重定向的链接:
r.url
- 获取页面内容,有了页面内容之后才能进行爬取:
r.text
或者r.content
,如果页面是json格式的数据,还可以用r.json()
直接将内容转化为json形式方便解析
这是最基本的获取一个页面的内容的方式,还可以有更多的设置,比如:
r = requests.get(url,headers=header,timeout=5)
可以设置超时时间,以及自定义发送的请求头headers
,一种最基本的反爬虫措施是验证请求时的headers
,如果访问时状态码不是200
,不妨试试加上headers,这是一个Python字典,像这样:
headers = {
"Host": "www.jianshu.com",
"Referer": "https://www.jianshu.com",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36",
}
requests.get(url,headers=headers)
使用requests
还可以下载网页的内容,如果某个链接是一张图片,或者视频音频,可以用requests
直接访问之后写入文件就可以保存下来,比如:
r = requests.get(url)
with open("file.jpg",'w') as f:
f.write(r.content)
当然,如果视频很大,那么在第一行requests的时候就要等很久,因此可以用下面这种方式以传输流的形式下载:
r = requests.get(url,stream=True) #只获取头信息,而不缓存整个页面内容
content_size = int(r.headers['content-length']) #获得页面信息比如大小
for data in r.iter_content(): #开始传输内容
f.write(data) #len(data)代表当前传输的数据大小
解析页面内容
通过requests
成功访问,并且通过r.text
获取到页面的内容之后,我们可以开始对这些内容进行解析,提取出想要的那部分数据,可以直接用正则表达式进行匹配,也可以使用BeautifulSoup
库,使用pip install bs4
就可以安装,使用from bs4 import BeautifulSoup
导入。首先,使用
soup = BeautifulSoup(r.text,'html.parser')
之后就可以在这个soup
中查找元素了,所有的html标签都可以查找,有以下用法:
- 查找某个html标签:
element = soup.find('ul',attrs={'id':'item_list'})
,这个语句的作用是查找页面中第一个ul
标签,并且它的id是“item_list” - 查找所有标签:
element = soup.find_all('ul')
,这个语句会返回一个列表,里面包含了所有ul
标签的内容
以上返回得到的element
仍然是soup对象,我们还可以继续用find
和find_all
查找下去,对于以上找到的element
,还可以用以下的语句查找一些内容: -
element.href
或element["href"]
可以获得这个标签的一些属性,比如链接 -
element.string
可以获得这个标签中的文本 -
element.ul
可以继续寻找子元素
对于网页解析来说,按标签查找这种方式比较直观,当我们打开网页审查元素时就能清晰地定位到我们想要的元素处于哪一层:
然后在代码中使用BeautifulSoup
就可以定位到我们想要的地方获取信息了
抓包
我主要用chrome自带的开发者工具(F12)进行抓包,如果我们想要做的不只是爬取静态页面内容那么简单,而是涉及到自动对网页进行一些操作(登录、查询...),或者页面内容是动态加载的,那么我们就需要抓包看一下需要发送哪些请求
比如登录,登录GitHub的时候,准备好开发者工具:
点击登录,就会显示出所有的请求,并且发现登录的请求是这个:
所以想要实现模拟登录GitHub,我们就要在程序中使用
requests
帮助我们模拟出这个请求,看到这个请求的方法是POST,那么找到请求的URL以及请求所发送的data:然后就可以构造请求了:
r = requests.post(url,data=form_data)
,其中url
就是“Request Url”,form_data
是自己构造的一个字典,里面存放了"Form Data"里面的数据。这个请求就实现了模拟登录,完了之后可以用r.url
检查是不是跳转到了登录之后的链接(GitHub用户的主页)想要对页面发出查询请求或者获取动态加载的内容也是一样的,先在浏览器中进行一次操作,抓包,然后看发出的请求,找到最关键的那个请求,比如获取知乎回答的内容:
这里捕获到的URL其实就是获取回答的API,观察以下这个链接,可以对其进行一定的简化:
https://www.zhihu.com/api/v4/questions/23819007/answers?include=data%5B%2A%5D.is_normal%2Ccontent%2Ceditable_content%2Cvoteup_count&limit=5&offset=5&platform=desktop&sort_by=default
这个链接返回的是JSON格式的数据:
那么,首先用GET方法请求这个API:
r = requests.get(url,headers=headers)
一般API会检测
headers
,添加了headers
才能成功访问,然后,由于这个请求得到的是JSON数据格式,直接用page_content = r.json()
就可以对其进行进一步处理了
使用requests.session()
刚刚在模拟登录GitHub的过程中,可以看到提交的表单数据“Form Data”里面有一项“authenticity_token”,这个东西找到它很简单,复制“authenticity_token”然后在审查页面元素里面搜索就可以找到了:
在代码中定位这个token可以用下面这种写法:
import requests
from lxml import etree
ses = requests.session()
check_data = ses.get(login_url,).content
selector=etree.HTML(check_data)
authenticity_token = selector.xpath('//input[@name="authenticity_token"]/@value')[0]
这里为什么要用“session”来发送请求呢,因为你每次关掉浏览器,再打开GitHub,就会有一个不同的“authenticity_token”,而如果直接用requests.get
先获得这个“authenticity_token”,再用requests.post
发送包含“authenticity_token”的表单数据,那么是无法登录成功的。而使用“session”相当于开了一个浏览器,保持着你和GitHub的会话,所以在使用“session”的时候,你的“authenticity_token”是不会变的,其他时候比如请求验证码等等也是同理
一年前当有人建议我直接通过爬虫来上手Python的时候,稳扎稳打看教材学C++的我是无法理解的,但是后来发现用Python写爬虫确实不难,主要是有很多方便易用的库,直接调用就好了。刚开始的时候爬一些简单的网站,给我带来了许多成就感,也在写代码的过程中不断熟悉了Python和爬虫。一开始的时候,我甚至兴奋地在GitHub上面创建了我的第一个repository,是一个计算自动登录并计算绩点的repository,后来,我也帮同学解决了一个shua-piao的问题成功用爬虫装逼。再后来,我发现我也没有什么需求和动力继续进阶更深更有难度的爬虫,我的爬虫知识不算多但还算够用,总是写一些基础的对自己的能力提高也没有帮助。于是我就只有在需要的时候才写爬虫程序,开始学习其他的方向了