使用Requests库来进行爬虫的方式
目录
- 使用
- 各种请求方式
- 基本get请求
- 基本写法
- 带参数get
- 解析json
- 获取二进制数据
- 添加headers
- 基本POST请求
- 响应
- response属性
- 状态码判断
- 高级操作
- 文件上传
- 获取cookie
- 会话维持
- 证书验证
- 代理设置
- 超时设置
- 认证设置
- 异常处理
Requests是用Python编写,基于urllib,采用Apache2 Licensed开源协议的HTTP库。
它比urllib更方便,可以节约我们大量的工作,完全满足HTTP测试需求。
安装:
pip3 install requests
使用
实例:
import requests response=requests.get('https://www.baidu.com') print(type(response)) print(response.status_code) print(type(response.text)) print(response.text) print(response.cookies)
各种请求方式
import requests requests.post('http://httpbin.org/post') requests.put('http://httpbin.org/put') requests.delete('http://httpbin.org/delete') requests.head('http://httpbin.org/get') requests.options('http://httpbin.org/get')
我们执行以上命令后,可以在这个网址进行验证:
http://httpbin.org 这可以作为一个测试网址,它可以反馈一些我们请求时的信息。例如:
可以查看我们请求时的ip地址。
基本get请求
基本写法
import requests response=requests.get('http://httpbin.org/get')#用get方式发送请求并获得响应 print(response.text)#用text查看响应内容
带参数get
import requests response=requests.get('http://httpbin.org/get?name=zhuzhu&age=23') #将参数拼接到url后面,用问号分隔,参数间用&来分隔 print(response.text)
可以看到返回的args信息中包含了我们的get参数。但是这种方法使用得不是很方便,再看下面的方式:
import requests data={ 'name':'zhuzhu', 'age':23 } response=requests.get('http://httpbin.org/get',params=data) #用字典的形式传递给params参数,不需要自己写url编码 print(response.text)
得到的结果与上面的方法是一样的,但是方便了许多~
解析json
import requests response=requests.get("http://httpbin.org/get") print(type(response.text)) print(response.json())#把返回结果编码成一个json对象 print(type(response.json()))
这个方法在返回一些AJEX请求时是比较常用的。
获取二进制数据
在下载一些内容(图片、视频)的时候常用的一个方法。
试试看,我们想要获取一个github的图标:
import requests response=requests.get("https://github.com/favicon.ico") print(type(response.text),type(response.content)) print(response.text) print(response.content)#可以使用content属性来获取二进制内容
可以看到,在响应中,text的类型是string,而content的内容是bytes,也就是二进制形式。
怎么把这个图标保存到本地呢?我们已经知道怎么获取它的二进制内容,现在只需要写入文件就可以了:
import requests response=requests.get("https://github.com/favicon.ico") with open('favicon.ico','wb')as f: f.write(response.content) f.close()
哈哈,成功保存在运行目录下了~
添加headers
headers在爬虫中是非常必要的,很多时候如果请求不加headers,那么你可能会被禁掉或出现服务器错误…
比如我们现在想爬取知乎上的数据,但是不加headers:
import requests response=requests.get("https://www.zhihu.com/explore") print(response.text)
那么就会报错,因为知乎是要识别你的浏览器信息的。
我们现在加入headers试试看(做一个浏览器的伪装),只需要向get方法传入headers参数就好了:
import requests headers={ 'User-Agent':'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)AppleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36' } response=requests.get("https://www.zhihu.com/explore",headers=headers) print(response.text)
运行结果成功返回了响应信息。
基本POST请求
直接用字典构造一个data并传入方法,就可以实现post请求了,省去了编码步骤,比起urllib方便许多:
import requests data={'name':'zhuzhu','age':'23'} response=requests.post("http://httpbin.org/post",data=data) print(response.text)
再加入headers:
import requests data={'name':'zhuzhu','age':'23'} headers={ 'User-Agent':'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)AppleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36' } response=requests.post("http://httpbin.org/post",data=data,headers=headers) print(response.json())
可以看到,返回的json形式的响应中,我们成功添加了data和headers的信息。
总结:get和post请求使用都很方便,区别只是换一下方法而已。
响应
response属性
下面列出了常用的response属性:
import requests response=requests.get("http://www.jianshu.com") print(type(response.status_code),response.status_code)#状态码 print(type(response.headers),response.headers) print(type(response.cookies),response.cookies) print(type(response.url),response.url) print(type(response.history),response.history)
状态码判断
常见的网页状态码:
100: (‘continue’,),
101: (‘switching_protocols’,),
102: (‘processing’,),
103: (‘checkpoint’,),
122: (‘uri_too_long’, ‘request_uri_too_long’),
200: (‘ok’, ‘okay’, ‘all_ok’, ‘all_okay’, ‘all_good’, ‘\o/’, ‘✓’),
201: (‘created’,),
202: (‘accepted’,),
203: (‘non_authoritative_info’, ‘non_authoritative_information’),
204: (‘no_content’,),
205: (‘reset_content’, ‘reset’),
206: (‘partial_content’, ‘partial’),
207: (‘multi_status’, ‘multiple_status’, ‘multi_stati’, ‘multiple_stati’),
208: (‘already_reported’,),
226: (‘im_used’,),Redirection.
300: (‘multiple_choices’,),
301: (‘moved_permanently’, ‘moved’, ‘\o-’),
302: (‘found’,),
303: (‘see_other’, ‘other’),
304: (‘not_modified’,),
305: (‘use_proxy’,),
306: (‘switch_proxy’,),
307: (‘temporary_redirect’, ‘temporary_moved’, ‘temporary’),
308: (‘permanent_redirect’,
‘resume_incomplete’, ‘resume’,), # These 2 to be removed in 3.0Client Error.
400: (‘bad_request’, ‘bad’),
401: (‘unauthorized’,),
402: (‘payment_required’, ‘payment’),
403: (‘forbidden’,),
404: (‘not_found’, ‘-o-’),
405: (‘method_not_allowed’, ‘not_allowed’),
406: (‘not_acceptable’,),
407: (‘proxy_authentication_required’, ‘proxy_auth’, ‘proxy_authentication’),
408: (‘request_timeout’, ‘timeout’),
409: (‘conflict’,),
410: (‘gone’,),
411: (‘length_required’,),
412: (‘precondition_failed’, ‘precondition’),
413: (‘request_entity_too_large’,),
414: (‘request_uri_too_large’,),
415: (‘unsupported_media_type’, ‘unsupported_media’, ‘media_type’),
416: (‘requested_range_not_satisfiable’, ‘requested_range’, ‘range_not_satisfiable’),
417: (‘expectation_failed’,),
418: (‘im_a_teapot’, ‘teapot’, ‘i_am_a_teapot’),
421: (‘misdirected_request’,),
422: (‘unprocessable_entity’, ‘unprocessable’),
423: (‘locked’,),
424: (‘failed_dependency’, ‘dependency’),
425: (‘unordered_collection’, ‘unordered’),
426: (‘upgrade_required’, ‘upgrade’),
428: (‘precondition_required’, ‘precondition’),
429: (‘too_many_requests’, ‘too_many’),
431: (‘header_fields_too_large’, ‘fields_too_large’),
444: (‘no_response’, ‘none’),
449: (‘retry_with’, ‘retry’),
450: (‘blocked_by_windows_parental_controls’, ‘parental_controls’),
451: (‘unavailable_for_legal_reasons’, ‘legal_reasons’),
499: (‘client_closed_request’,),Server Error.
500: (‘internal_server_error’, ‘server_error’, ‘/o\’, ‘✗’),
501: (‘not_implemented’,),
502: (‘bad_gateway’,),
503: (‘service_unavailable’, ‘unavailable’),
504: (‘gateway_timeout’,),
505: (‘http_version_not_supported’, ‘http_version’),
506: (‘variant_also_negotiates’,),
507: (‘insufficient_storage’,),
509: (‘bandwidth_limit_exceeded’, ‘bandwidth’),
510: (‘not_extended’,),
511: (‘network_authentication_required’, ‘network_auth’, ‘network_authentication’),
示例:
import requests response=requests.get("http://www.baidu.com") exit() if not response.status_code==200 else print("Requests Successfully")
这说明这次请求的状态码为200.
另一种写法就是把数字200换位相应的字符串内容,详细的对应方式见上面列出的关系。
比如200对应着其中一个字符串是“ok”,我们试试:
import requests response=requests.get("http://www.baidu.com") exit() if not response.status_code==requests.codes.ok else print("Requests Successfully")
可以看到效果是一样的,可以根据实际情况选用。
高级操作
文件上传
import requests files={'file':open('favicon.ico','rb')} #通过files参数传入post方法中,实现文件的上传 response=requests.post("http://httpbin.org/post",files=files) print(response.text)
这样通过post请求,我们就完成了文件的上传,下图file显示的就是文件的字节流了:
获取cookie
上面提到过,可以直接使用response.cookies就可以打印出cookie了。
实际上cookies是一个列表的形式,我们可以用for循环把每一个cookie取出来并且打印其key-value:
import requests response=requests.get("http://www.baidu.com") print(response.cookies) for key,value in response.cookies.items(): print(key+'='+value)
如上图,非常方便地获取到了cookie信息。这比起urllib可要方便不少~
会话维持
基本上为了实现“模拟登录”的功能。
来看例子:
import requests requests.get('http://httpbin.org/cookies/set/number/123456789') #通过cookies/set方法来设置cookie response=requests.get('http://httpbin.org/cookies') print(response.text)
咦,cookies为空,和我们想象的不太一样。这是因为上面那段代码中发起了两次get请求,相当于两个浏览器,相互独立,所以第二次get并不能得到第一次的cookie。
那么需要采用下面的方法,通过声明Session对象来发起两次get请求,视为一个浏览器中进行的操作:
import requests s=requests.Session() s.get('http://httpbin.org/cookies/set/number/123456789') #通过cookies/set方法来设置cookie response=s.get('http://httpbin.org/cookies') print(response.text)
这回就成功了~
这个方法是比较常用的,用来模拟一个登录会话并维持之,这样就可以获取登录后的页面了。
证书验证
如果我们要爬取的是一个https协议的网站,那么网站首先会检查证书是否是合法的,若非法,会直接抛出SSLError错误。如果要避免这种错误的话,可以把这个参数:verify设置为False就可以了(默认是True)。
先看未设置的:
import requests response=requests.get('https://www.12306.cn') print(response.status_code)
抛出了SSLError错误。
再看设置过的:
import requests response=requests.get('https://www.12306.cn',verify=False)#把verify参数置否 print(response.status_code)
如此就返回了200的状态码,说明这个请求是正常的,没有进行证书认证。
但是仍然会有警告信息,提示你最好加上证书验证。那么怎么消除这个警告信息呢?
可以从原生包中导入urllib3并使用其中的禁用警告这个方法:
import requests from requests.packages import urllib3 urllib3.disable_warnings()#禁用警告信息 response=requests.get('https://www.12306.cn',verify=False) print(response.status_code)
这样就不会有警告信息了。
怎么手动添加证书呢?
示例:通过cert来指定本地证书
import requests response=requests.get('https://www.12306.cn',cert=('/path/server.crt','/path/key')) print(response.status_code)
但由于我这儿没有本地证书,就不进行演示了。
代理设置
可以通过字典形式构造一个参数,字典里是你已经开通的代理ip。再把参数传入get方法即可。
import requests proxies={ "http":"http://127.0.0.1:9743", "https":"https://127.0.0.1:9743" } response=requests.get("https://www.taobao.com",proxies=proxies) print(response.status_code)
如果代理需要用户名和密码的时候怎么办呢?
我们可以在代理的url前面直接传一个user:password,后面加个@符号,这样我们就能传入用户名和密码这个认证信息了:
proxies={ "http":"http://uesr:password@127.0.0.1:9743/", }
那如果代理方式不是https,而是一个socks类型的呢?
首先需要安装,在命令行执行(windows环境下):
pip3 install request[socks]
安装之后就可以使用这种形式的代理了。
import requests proxies={ "http":"sock5://127.0.0.1:9743", "https":"socks5://127.0.0.1:9743" } response=requests.get("https://www.taobao.com",proxies=proxies) print(response.status_code)
超时设置
import requests response=requests.get("https://www.taobao.com",timeout=1) #设置一个时间限制,必须在1秒内得到应答 print(response.status_code)
如果时间超出了限制,就会抛出异常。怎么捕获这个异常呢?
import requests from requests.exceptions import ReadTimeout try: response=requests.get("https://httpbin.org/get",timeout=0.5) print(response.status_code) except ReadTimeout: print('Timeout')
成功捕获了这个异常,并进行处理(报信息)。
认证设置
有的网站在访问时需要输入用户名和密码,输入之后才能看到网站的内容。
如果遇到这种网站,我们可以通过auth参数,把用户名和密码传入。
import requests from requests.auth import HTTPBasicAuth r=requests.get('http://120.27.34.24:9001',auth=HTTPBasicAuth('user','123')) #通过auth参数传入。 print(r.status_code)
这样就可以完成一个正常的请求,如果把auth参数去掉,那么就会返回401参数(请求被禁止)。
异常处理
异常处理的部分还是比较重要的,它可以保证你的爬虫不间断地运行。
原则还是先捕获子类异常,再捕捉父类异常(RequestException)。
import requests from requests.exceptions import ReadTimeout,HTTPError,RequestException try: response=requests.get('http://httpbin.org/get',timeout=0.5) print(response.status_code) except ReadTimeout:#捕获超时异常 print('Timeout') except HTTPError:#捕获HTTP异常 print('Http error') except ConnectionError:#捕获连接异常 print('Connection error') except RequestException:#捕获父类异常 print('Error')
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。