requests库详解

  上次讲的urllib库在操作cookie和代理之类的时候比较麻烦,然而我们学习python是为了简化操作,python就是讲究一个简洁,两三行代码实现很多功能,requests库是用python语言编写的,基于urllib3写成的,采用了Apache2 licensed开源协议的HTTP库,比urllib更方便,说白了requests库就是python实现简单易用的一个HTTP库
安装方法

  直接使用pip安装

pip install requests

  怎么证明你的requests是安装好的呢,执行下面的代码,如果没有报错即可。

import requests

用法详解

  • 实例引入
      我们先看下面的代码,感受一下requests库的方便之处:
# coding = 'utf-8'
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)

  上面的代码就是get到了百度首页,然后打印出了首页的response类型,和状态码,还有text看到它的类型是str,就不需要decode转码了。cookie等信息:
状态码200

请求

  • 基本get请求
      基本写法

  我们现在看一下基本的get请求方法怎么写的:

import requests

response = requests.get('http://httpbin.org/get')
print(response.text)

  上面打印的就是我们get请求到的内容,和我们直接访问httpbin.org/get里面的内容一致,这样还是比较简单的,我们再看看怎么加一个带参数的get请求:

import requests

response = requests.get('http://httpbin.org/get?name=peng&age=21')
print(response.text)

  上面这个就是把我们要get时的附加参数都带到了链接里面,然后打印出来的内容里面都有我们带的name和age,但是这样链接整太长不太好,可以将我们要附带的内容写在字典里面,然后在请求时使用params带上也行,方法如下:

import requests

data = {
    'name': 'peng',
    'age': '21'
}
response = requests.get('http://httpbin.org/get', params=data)
print(response.text)

  两种的执行结果都如下图所示:
带参数的get

  • 解析json
      httpbin.org/get其实返回的就是一些json字符串。我们可以直接调用response.json这个方法,如果返回的结果是一个json字符串,那么它就会把返回的结果编码成一个json对象,我们可以先看看用response.json的方法
import requests

response = requests.get('http://httpbin.org/get')
print(response.json())

  我们再看看用json,json.loads的方法来读取我们返回的结果:

import requests
import json

print(json.loads(response.text))

  其实这两个返回的结果都是一样的,都会给我们返回编码好的json对象:
两种写法同种答案

  • 获取二进制数据
      二进制数据就是我们的视频图片歌曲这样的文件。我们现在来演示一下怎么下载一张图片
import requests

response = requests.get('https://github.com/favicon.ico')
print(type(response.text), type(response.content))
print(response.text)
print(response.content)

  我们获取的是github的图标,我们直接用我们的刚才的方法,传入github的图标地址,然后打印出text类型和content的类型,得到分别为<class 'str'> <class 'bytes'>这样两种类型,然后打印出图片的内容:
图片内容如图
  可以看到上图都是二进制的编码,我们需要将其保存出来

import requests

response = requests.get('https://www.github.com/favicon.ico')
with open('favicon.ico','wb') as f:
    f.write(response.content)
    f.close()

  上面这段代码就将其保存了下来,用了with open方法,写入了response和content。可以去本地的文件夹查看。视频图片音乐都可以这样去保存,但是需要注意的是你要用直链

  • 添加headers
      headers是很重要的,在我们爬取一些网站时如果不加headers就会报错,如知乎,下面这段代码是不加headers的运行结果:
import requests

response = requests.get('https://www.zhihu.com')
print(response.text)

  上面这段代码执行出来就是下图所示的样子:
没有headers
  在headers里面有很多内容,如user-agent等这些信息没有的话,服务器就会认为我们是爬虫,就不理会我们,现在我们就把user-agent当成一个字典,然后用headers参数传到get里面就可以了:

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'
}
response = requests.get('https://www.zhihu.com/explore', headers=headers)
print(response.text)

  上面这个代码运行出来就会是知乎的explore页面源码,这样就正常了,这样就实现了浏览器的伪装。
正常伪装

  • 基本POST请求
      POST请求就是要带一个from data,我们可以用data参数把要带的信息写在字典里,然后去传:
import requests

data = {
    'name': 'peng',
    'age': '20'
}
response = requests.post('http://www.httpbin.org/post', data=data)
print(response.text)

  我们可以看看这个post请求带了data的效果:
携带data信息
  现在我们再看看如果post请求既带了data还携带了headers该怎么写呢:

import requests

data = {
    'name': 'peng',
    'age': '21'
}
headers = {
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36'
}
response = requests.post('http://www.httpbin.org/post', data=data, headers=headers)
print(response.text)

  可以看到上面的写法就是把data和headers分成两个字典来写,post都会带上这两个参数:
post
  可以看到requests比urllib简单的多

响应

  • reponse属性
      我们现在先把reponse都打印出来看看:
import requests

response = requests.get('http://www.yuanpeng666.top')
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)

  上面列举的都是response的常用属性,可以看到状态码,头信息、headers、cookies、url等等

  • 状态码判断
      response附带一个内置的状态码查询,比如下面这段成功代码:
import requests

response = requests.get('http://www.yuanpeng666.top')
if response.status_code == requests.codes.ok:
    print('yes')
if response.status_code == 200:
    print('ok')

  访问我们的博客,明显OK。如果我们的状态码是200,就OK,在response里面,就像是有一张表一样,各个状态码都对应,如刚才的200.就是ok,我们打印出来的结果都是yes和ok:
code=200
  各个状态码都有对应的查询代码:

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.0

Client 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'),

  举一反三,我们试试404的这个查询码:

import requests

response = requests.get('https://www.yuanpeng666.top/ww.html')
if response.status_code == requests.codes.not_found:
    print('code 404')
if response.status_code == 404:
    print('code 404')

  看上面这个,我们的网站里是没有ww.html这个文件的,所以必然会请求不到,我们无论是使用404。还是用not_found都会给我们正常的打印出来:
404
  这两种方法看个人习惯,上面那个表在官方文档中也可以查询到。

高级操作

  • 文件上传
      我们用fileopne这个方法去上传文件,post里面有个参数是files,我们可以用这个参数去传:
import requests

files = {
    'file': open('1.png', 'rb')
}
response = requests.post('http://httpbin.org/post', files=files)
print(response.text)

  上面就是文件上传的方法,可以看到下图运行结果就会打印出图片的二进制值:
文件上传
  可以看到输出结果有字节流,我们把文件的名称指定成了file,当然你也可以指定其他名称。

  • 获取cookie
import requests

response = requests.get('https://www.baidu.com')
print(response.cookies)
for key, value in response.cookies.items():
    print(key + '=' + value)

  cookies是一个列表的形式,这里就用for循环把cookie一个个打印出来。我们都知道cookies是做会话维持的,如果你的爬虫没有cookies信息,可能过一段时间就会掉。

  • 会话维持
      一起看看会话维持这里怎么写吧,我们模拟登陆一下
import requests

requests.get('http://httpbin.org/cookies/set/number/666')
response = requests.get('http://httpbin.org/cookies')
print(response.text)

  但是我们看到输出结果如下图:
cookies空
  上面的代码运行出来没有cookies是正常的,因为我们没有那样写相当于做了两次get请求,但是是在两个浏览器里面,第一次是正常的,请求到了cookies,但是第二次的时候我们是直接get的,肯定是没有内容的。so我们应该写成下面的样子:

import requests

s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/666')
response = s.get('http://httpbin.org/cookies')
print(response.text)

  上面的写法才是正确的,我们用了Session这个对象声明一下,然后用Session发起两次请求。而这一次是在一个浏览器里面了,这个方法也是非常常用的,我们可以看看运行结果:
cookies

  • 证书验证
      现在再来说一下证书验证的问题,证书就是ssl证书,有的网站没有用ssl或者它的ssl不是官方的,浏览器认为它的ssl是错误的,我们就会抛出报错信息:
import requests

response = requests.get('https://abc.yuanpeng666.top')
print(response.status_code)

  上面访问了一个没有ssl的网站,但是我还加了https,就会报错:
no  ssl
  我们解决这个错误的方法就是在get里面多一个<font color="green">verify</font>的参数,然后将其设置为“<font color="red">False</font>”

import requests

response = requests.get('https://nuanqin.top',verify=False)
print(response.status_code)

  注意啦,这里的地址换成小胡的blog地址了,他是http的,我们改成这样就可以正常访问,并返回一个200的状态码了:
200
  但是我们也看到了有一行的警告信息,强迫证的你只需要调用urllib3的原生包,就可以解决:

import requests
from requests.packages import urllib3

urllib3.disable_warnings()
response = requests.get('https://nuanqin.top', verify=False)
print(response.status_code)

  urllib3里面有一个<font color="red">disable_warnings()</font>我们调用一下就OK了
没有waring
  还有一种方法就是我们自己传一个证书然后让服务器去验证:

import requests

response = requests.get('https://www.yuanpeng666.top', cert=('/ssl/ssl.key', '/ssl/key'))
print(response.status_code)

  当然这个证书是你本地的,可用的才行,我这里没有就不做演示了, 但是我们做是完全可以的。

  • 代理设置
      这个跟上一节的urllib是一样的,也可以设置一个代理:
import requests

proxies = {
    "http": "http://127.0.0.1:1086",
    "https": "https://127.0.0.1:1086",
}
response = requests.get("http://httpbin.org/get",proxies=proxies)
print(response.status_code)

  然后也是可以看到状态码是200的成功样子,这个注意你的本地代理端口写正确就行了,基本跟urllib是一样的操作。如果你的操作不成功,先别着急,请往后看
  先说假如你的代理需要用户名或者密码,我们也是可以传进去的:

import requests

proxies = {
    "http": "http://user:password@127.0.0.1:1086",
    "https": "https://user:password@127.0.0.1:1086",
}
response = requests.get("http://httpbin.org/get", proxies=proxies)
print(response.status_code)

  上面的操作就是带了用户名和密码的,意思就是说你本地的代理需要用户名和密码,那你就加上,先写用户名,再写密码。这样也是OK的
  OK。如果上面两种操作方法都不可以的话,那么大部分人都用的是socks这种代理方法,我们需要先用pip安装一个requests[socks]的包:

pip install requests[socks]

  安装好之后如图所示:
socks
  现在在我们的代码里面就应该写成下面的样子:

import requests

proxies = {
    'http': 'socks5://127.0.0.1:1086',
    'https': 'socks5://127.0.0.1:1086'
}
response = requests.get('http://httpbin.org/get', proxies=proxies)
print(response.status_code)

  大部分人用ssr的都可以这样写,如图所示我这样就成功了:
proxies

  • 超时设置
      我们再来看一下超时设置。比如我们要在多少秒之内访问一个网站,如若不然就报错,免得浪费我们服务器的资源,这个在urllib那一节也说过:
import requests

response = requests.get("https://www.baidu.com", timeout=2)
print(response.status_code)

  上述代码的意思就是在2秒之内请求到百度的信息,那结果必然是OK的,所以就会返回一个200的状态码,但是我们现在换一个国外的网站来试试,肯定不会在0.5秒打开一个国外的网站。

import requests

response = requests.get("https://httpbin.org/get", timeout=0.5)
print(response.status_code)

  上述代码就是在0.5秒里打开我们的测试网站,那么结果必然报错:
报错
  这样的报错会使程序终止,我们可以写成下面的样子,让他改变一下:

import requests
from requests.exceptions import ReadTimeout

try:
    response = requests.get("http://python.org", timeout=0.5)
    print(response.status_code)
except ReadTimeout:
    print('Time out')

  我们这里把刚才的网站换成了python的官网,原因是刚才那个测试网站我们加载过一次的了,这样就稳稳的报错了:
time out

  • 认证设置
      认证设置是指有些网站需要用户名和密码才可以进去,这时候我们可以把用户名和密码带上:
import requests
from requests.auth import HTTPBasicAuth

r = requests.get('http://abc.yuanpeng666.top', auth=HTTPBasicAuth('156', '110'))
print(r.status_code)

  只要你的用户名和密码输入正确就OK了,但是如果我们把用户名或者密码输错了,或者删掉后面的加密选项,就会报401的错误。也就是请求被禁止,如果你觉得这样的写法比较麻烦,也可以用下面的方式,直接传一个字典进去:

import requests

r = requests.get('http://abc.yuanpeng666.top', auth=('user', 'password'))
print(r.status_code)

  这样也是可以的。

  • 异常处理
      最后看看我们的异常处理问题,刚才说的超时会有一个异常捕获这里就不演示超时的问题了,现在看看网络问题的异常捕获:
import requests
from requests.exceptions import ConnectionError

try:
    r = requests.get("http://httpbin.org/get")
    print(r.status_code)
except ConnectionError:
    print("wifi")

  我把网线拔了,没有网络,就会说是网络问题,就会打印wifi出来:
网络错误

结语

  到此我们的requests就完了,基本和高级用法都说了,这段时间自己很忙,所以帖子也出得比较慢。

最后修改:2020 年 04 月 23 日 09 : 43 PM
请俺喝杯咖啡呗