请求库2 - requests

urllib是基本库,功能实现尚且比较复杂。requests库更加友好、高效。

requests能更加简单的实现Cookies、登录验证和代理设置等额外操作。

基本用法

基本的GET请求

实例1:抓取知乎专题的标题

文本内容通过response.text属性查询。

URL参数

如果get访问的服务器需要参数需要在URL中加入参数,常见的方式有两种:

  1. 直接构建带参数的URL字符串,通过问号分隔,例如 http://xxx.com/?key=value
  2. 通过param参数传递URL参数,该参数接受一个字典,如 response = requests.get(..., param = {'k': 'v'})
    1. 可以是简单的字典,如 {"key1": "value1", "key2": "value2"}构造出的参数字符串为 ?key1=value1&key2=value2
    2. 可以有多个值,如 {"key1": "value1", "key2": ["key21", "key22"]}构造出的参数字符串为?key1=value1&key2=value21&key2=value22
    3. 可以是空值,此时会忽略这个参数,如 {"key1": "value1", "key2": None}构造出的参数字符串为 ?key1=value1

实例2:抓取json数据

json数据本质上还是文本数据,我们抓取后需要转化为字典/json格式,为避免这一转化步骤,可直接通过response.json()方法获取json字典

实例3:抓取GitHub站点图标

二进制内容通过response.content获取,直接打印bytes类型的字符串是没有视觉意义的,因此需要保存到本地。注意文件打开格式为wb

图片、视频、音频等二进制多媒体文件都用这种方式获取。

基本的POST请求

POST请求需要提交表单(form),表单数据在python中以字典表示,通过requests.post()函数的data参数传入。

响应结果中我们可以看到请求的数据存储在form字段中。

响应(response)

我们通过requests.get()或者requests.post()向服务器发送一个请求(request),服务器给我们一个返回结果称之为响应(response)。

响应结果中包含了许多的信息,主要如下:

  • text:str类型的请求内容
  • json() :如果返回内容本质上是json数据,直接调用这个
  • content:bytes类型的请求内容
  • cookies:类型为requests.cookies.RequestsCookieJar
  • headers:字典,requests.structures.CaseInsensitiveDict类型
  • ok:bool类型,请求是否正常返回结果
  • status_code:int类型,状态码,正常为200
  • encoding:编码方式,常见的如utf-8, gbk
  • url:请求的url

状态码

requests内置了一个状态码查询对象requests.codes

例如正常返回200对应的状态码对象为requests.codes.ok

下面是常见的状态码和对应的状态码对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# 信息性状态码
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',),

# 重定向状态码
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

# 客户端错误状态码
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',),

# 服务端错误状态码
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')

高级用法

会话维持

这里涉及到一个 Session 的概念。不管是调用get还是调用post或者其它请求方法,requests都会默认给我们建立一个Session,当请求完成自动·关闭Session。一个Session就相当于打开了一个浏览器,我们打开浏览器,点击某个页面,看到了信息,然后关闭浏览器。

如果我们连续两次发出请求,其实是相当于打开了两个浏览器窗口。两个窗口之间的信息是不互通的,例如我在一个浏览器中登录了,想在第二个浏览器中获取登陆后的个人信息是做不到的,除非我们手动在第二个浏览器的请求中添加第一次登录的Cookie信息。

如果我们是在同一个浏览器中打开了两个标签页,情况就不一样了。第一个标签页中登录,第二个标签页也处于登录状态。

Session方式通过requests.Session()初始化,返回一个requests.session.Session对象。

Session通常用来打开同一个站点的不同页面。

POST上传文件

requests6

requests.post()的参数files接受一个字典类型的数据,字典每个元素标识了相应的文件

注意传入的字典包含的是 文件对象,而不是文件名字符串。

Cookies获取

Cookies信息存储在response.cookies中,数据类型为 requests.cookies.RequestsCookieJar

response.cookies.items()返回一个 元组列表

Cookies可以用来维持 登录状态:

1
2
3
4
5
6
headers = {
'Cookie': '...',
'User-Agent': 'Chrome/53.0.2785.116'
}
url = 'https://www.zhihu.com'
response = requests.get(url, headers=headers)

SSL证书验证

原文所举的12306的例子好像已经被修复了

1
2
response = requests.get('https://www.12306.cn', verify=True)
response.status_code # 200

如果设置varify = True(默认值),当我们请求一个HTTPS的站点需要验证SSL证书,如果证书无效(不存在或者不合法),程序抛出requests.exceptions.SSLError

不验证SSL证书需要手动设置varify = False,可能会抛出 警告:建议设置证书。

忽略警告可以使用:

  • requests.packages.urllib3.disable_warnings()
  • import logging; logging.captureWarnings(True)

设置代理

对于某些网站,在测试的时候请求几次,能正常获取内容。但是一旦开始大规模爬取,对于大规模且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面,更甚者可能会直接封禁客户端的IP,导致一定时间段内无法访问。

通过设置 代理 可以解决上述问题,设置代理通过参数proxies实现。

HTTP代理

简单的参数用于指定HTTP/HTTPS代理,例如

1
2
proxies = {"proxy_name": "http://host:port"} # 模板地址
response = requests.get(url, proxies = proxies)

HTTP代理需要身份验证时

1
proxies = {"proxy_name": "http://user:passwd@host:port"}

SOCKS代理

安装socks库:pip install requests[socks]

设置代理:proxies = {'http': 'socks5://user:passwd@host:port'}

超时

在本机网络状况不好或者服务器网络响应太慢甚至无响应时,我们可能会等待特别久的时间才可能收到响应,甚至到最后收不到响应而报错。为了防止服务器不能及时响应,应该设置一个超时时间,即超过了这个时间还没有得到响应,那就报错。这需要用到timeout参数。

这个时间的计算是发出请求到服务器返回响应的时间。

请求时间分为两部分:连接(connect)和读取(read)。因此timeout参数的值可以是标量,也可以是元组。

身份认证

在访问网站时我们可能需要提供用户名和密码才能继续访问。

HTTP认证

requests自带身份认证模块requests.auth.HHTPBasicAuth

带身份认证的请求通过参数auth实现。

1
2
3
4
5
from requests.auth import HTTPBasicAuth
##1.完整形式
response = requests.get(url, auth=HTTPBasicAuth('user', 'passwd'))
##2.简写形式
response = requests.get(url, auth=('user', 'passwd'))

OAuth认证

安装第三方包:pip install requests_oauthlib

1
2
3
from requests_oauthlib import OAuth1
auth = OAuth1('app_key', 'app_secret', 'user_oauth_token', 'user_oauth_token_secret')
response = requests.get(url, auth = auth)

对请求进行抽象

请求 抽象为 Requests类

1
from requests import Request, Session

初始化Request

1
2
3
4
url = '...'
data = '{...}'
headers = '{...}'
request = Request('POST', url, data = data, headers = headers)

转换request对象

1
2
3
session = Session()
prepared_request = session.prepare_request(request)
response = session.send(prepared_request) # not post or get

请求 独立成本地的对象,需要的时候才在 会话 中获取结果。

这在队列调度中十分有效。


  1. 使用chrome可以通过访问 chrome://version 查询到用户代理信息。
  2. 本文参考:https://cuiqingcai.com/5514.html
>>>>>>>>>>>>> 转载请注明出处 <<<<<<<<<<<<<
0%