最基础的HTTP 库有urllib 、httplib2 、requests 、treq 等。Python提供了这些功能齐全的类库来帮助我们完成模拟浏览器向服务器发出请求。
requests的一些高级用法,如文件上传、Cookies 设置、代理设置等。
文件上传——files参数
import requests files = { 'file':open('favicon.ico','rb') } r = requests.post('http://httpbin.org/post',files=files) print(r.text)
结果:
得到了返回响应,里面包含files 这个字段,而form 字段是空的,这证明文件上传部分会单独有一个files 字段来标识。
Cookies
requests获取和设置Cookies 只需一步即可完成。
获取Cookies
import requests r = requests.get('http://www.baidu.com') print(r.cookies) for key,value in r.cookies.items(): print(key+' = '+value)
这里我们首先调用cookies 属性即可成功得到Cookies,可以发现它是RequestCookieJar 类型。然后用items()方法将其转化为元组组成的列表, 遍历输出每一个Cookie 的名称和值, 实现Cookie的遍历解析。
用Cookie来维持登录状态。以知乎为例,首先登陆知乎,将Headers中的Cookie内容复制下来,添加到header参数中即可
import requests headers = { 'Cookie': '_zap=7f0fbd5c-3ac0-4779-92d3-a88eb2544abc; _xsrf=Snj6jFbrJnvDBrQ2j6V2921FaZQc5FPn; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1620095986; d_c0="AJDdimZjDROPTkh9-N-QWMMCvSVmcMmDZno=|1620095986"; captcha_session_v2="2|1:0|10:1620632376|18:captcha_session_v2|88:SkhoVlZwT2lhR3oxSkU0SGQwbVZoaGdOalMwcjIrOGhJbXdVTWF5RUhuZk82eGFFRXdlMitxQ1VaYzhPaTVObw==|222bffbd4da388599ac9e21db9ac6c001e17a5a852be5a6dfa4651f8c212e088"; __snaker__id=IKIKtEROjOe76jDw', 'host':'www.zhihu.com', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0' } r = requests.get('http://www.zhihu.com',headers=headers) print(r.text)
当然,你也可以通过cookies 参数来设置,不过这样就需要构造RequestsCookieJar对象,而且需要分割一下cookies。这相对烦琐,不过效果是相同的
import requests Cookie = '_zap=7f0fbd5c-3ac0-4779-92d3-a88eb2544abc; _xsrf=Snj6jFbrJnvDBrQ2j6V2921FaZQc5FPn; Hm_lvt_98beee57fd2ef70ccdd5ca52b9740c49=1620095986; d_c0="AJDdimZjDROPTkh9-N-QWMMCvSVmcMmDZno=|1620095986"; captcha_session_v2="2|1:0|10:1620632376|18:captcha_session_v2|88:SkhoVlZwT2lhR3oxSkU0SGQwbVZoaGdOalMwcjIrOGhJbXdVTWF5RUhuZk82eGFFRXdlMitxQ1VaYzhPaTVObw==|222bffbd4da388599ac9e21db9ac6c001e17a5a852be5a6dfa4651f8c212e088"; __snaker__id=IKIKtEROjOe76jDw' jar = requests.cookies.RequestsCookieJar() for cookie in cookies.split(';'): key,value = cookie.split('=',1) jar.set(key,value) headers ={'host':'www.zhihu.com', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:88.0) Gecko/20100101 Firefox/88.0'} r = requests.get('http://www.zhihu.com',cookies=jar,headers=headers) print(r.text)
这里我们首先新建了一个RequestCookieJar 对象,然后将复制下来的cookies 利用split()方法分剖,接着利用set()方法设置好每个Cookie 的key 和value ,然后通过调用requests 的get()方法并传递给cookies 参数即可。当然,由于知乎本身的限制,headers 参数也不能少,只不过不需要在原来的headers 参数里面设置cookie 字段了。
会话维持——Session对象
在requests 中,如果直接利用get()或post()等方法的确可以做到模拟网页的请求,但是这实际上是相当于不同的会话,也就是说相当于你用了两个浏览器打开了不同的页面。除了可以设置相同的Cookies之外,更简单快捷的方法就是用Session对象。
利用Session对象,我们可以方便地维护一个会话,而且不用担心cookies 的问题,它会帮我们自动处理好。
import requests requests.get('http://httpbin.org/cookies/set/number/123456789') r = requests.get('http://httpbin.org/cookies') print(r.text)
结果:{
“cookies”: {}
}
这里我们请求了一个测试网址http://httpbin.org/cookies/set/number/123456789。请求这个网址时,可以设置一个cookie ,名称叫作number ,内容是123456789,随后又请求了http://httpbin.org/cookies,此网址可以获取当前的Cookies 。但是从结果来看并没有获取到第一次请求带的cookies。
import requests s = requests.Session() s.get('http://httpbin.org/cookies/set/number/123456789') r = s.get('http://httpbin.org/cookies') print(r.text)
结果成功获取到了第一次请求的cookies:
{
“cookies”: {
“number”: “123456789”
}
}
所以,利用Session,可以做到模拟同一个会话而不用担心Cookies 的问题。它通常用于模拟登录成功之后再进行下一步的操作,打开同一站点的不同页面。后面会细讲
SSL证书验证——verify参数
requests 还提供了证书验证的功能。当发送HTTP 请求的时候,它会检查SSL 证书,我们可以使用verify 参数控制是否检查此证书。其实如果不加verify 参数的话,默认是True,会向动验证。
有些网站的证书没有被官方CA 机构信任,会出现证书验证错误的结果。如果用requests.get直接访问的话,就会提示一个错误SSLError ,表示证书验证错误。所以,如果请求一个HTTPS 站点,但是证书验证错误的页面时,就会报这样的错误。如果想避免的话只需把verify参数设为False即可。
import requests response = requests.get('https://www.12306.cn',verify=False) print(response.status_code)
结果:
结果中打印出了访问成功的状态吗:200。不过我们发现报了一个警告它建议我们给它指定证书。我们可以通过设置忽略警告的方式来屏蔽这个警告:
import requests from requests.packages import urllib3 urllib3.disable_warnings() response = requests.get('https://www.12306.cn',verify=False) print(response.status_code)
结果:200
代理设置——proxies参数
对于某些网站,在测试的时候请求几次,能正常获取内容。但是一旦开始大规模爬取,对于大规模且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面, 更甚者可能会直接封禁客户端的IP,导致一定时间段内无法访问。为了防止这种情况发生,我们需要设置代理来解决这个问题,这就需要用到proxies参数。
import requests proxies = { 'http':'http://10.10.1.10:3128', 'https':'http://10.10.1.10:1080' #该代理无效,请自行替换 } requests.get('http://www.taobao,com',proxies=proxies)
超时设置——timeout参数
在本机网络状况不好或者服务器网络响应太慢甚至无响应时,我们可能会等待特别久的时间才可能收到响应,甚至到最后收不到响应而报错。为了防止服务器不能及时响应,应该设置一个超时时间,即超过了这个时间还没有得到响应,那就报错。这需要用到timeout参数。这个时间的计算是发归请求到服务器返回响应的时间。
import requests r = requests.get('http://www.taobao.com',timeout=1) print(r.status_code)
通过这样的方式,我们将超时时间设置为1秒,如果1秒内没有响应,那就抛出异常。
身份验证——auth参数
有些网站在打开时就会弹出提示框,直接提示你输入用户名和密码,验证成功后才能查看页面(类似urllib的Handler),此时可以使用requests 自带的身份认证功能
import requests from requests.auth import HTTPBasicAuth r = requests.get('http://localhost:5000',auth=HTTPBasicAuth('username','password')) print(r.status.code)
认证成功返回200,认证失败返回401。
除此之外,requests还提供了更简单的写法,直接传给auth一个元祖,它会默认使用HTTPBasicAuth这个类来认证
import requests r = requests.get('http://localhost:5000',auth=('username','password')) print(r.status.code)
Prepared Request
urllib中,我们可以将请求表示为数据结构,其中各个参数都可以通过一个Request对象来表示。这在requests里同样可以做到,这个数据结构就叫Prepared Request 。
from requests import Request,Session url = 'http://httpbin.org/post' data = { 'name':'germey' } headers = {'Cookie': 'BAIDUID=D68A649DF89CEADA7862CA2EE54416AF:FG=1; BIDUPSID=D68A649DF89CEADA7862CA2EE54416AF; PSTM=1620095557; BD_UPN=13314752; __yjs_duid=1_d21d591988bfce506f5311b902e2b1751620097252706; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; H_PS_PSSID=33985_33820_31254_33848_33676_33607_22159; delPer=0; BD_CK_SAM=1; PSINO=5; BDRCVFR[Fc9oatPmwxn]=mk3SLVN4HKm; H_PS_645EC=3606G0yvkUwII1jinzk2qHzWVj6X71fg3uUuXoSCbESp0SiBJVaEN7Dgg8VtGdffC1%2Fa; BA_HECTOR=a18121252k8g2l2h8g1ga281s0rv'} s = Session() req = Request('POST',url,data=data,headers=headers) prepped = s.prepare_request(req) r = s.send(prepped) print(r.text)
这里我们引入了Request, 然后用 url 、 data 和 headers 参数构造了一个 Request 对象, 这时需要再调用 Session 的 prepare_request()方法将其转换为一个Prepared Request 对象, 然后凋用send()方法发送即可
有了Request这个对象, 就可以将请求当作独立的对象来看待, 这样在进行队列调度时会非常方便。