07Requests库的基本使用

学习爬虫,最基础的便是模拟浏览器向服务器发出请求

python强大之处就是提供了功能齐全的类库来帮助我们完成这些请求

requests库,我们只需要关心请求的链接是什么,需要传的参数是什么,以及如何设置可选的参数就好了


基本用法

简单实例

用python写爬虫的第一步就是模拟发起一个请求,把网页的源代码获取下来

当我们在浏览器中输入一个URL并回车,实际上就是让浏览器帮我们发起一个GET类型的HTTP请求,浏览器得到源代码后,把它渲染出来就可以看到网页内容了

如果我们想用requests来获取源代码,requests库提供了了一个get方法,我们调用这个方法,并传入对应的URL就能得到网页的源代码

import requests

r = requests.get("https://static1.scrape.cuiqingcai.com",verify=False)

print(r.text)

VESA格式与JEIDA格式标准_http

我们已经成功获取网页的HTML源代码,里面包含了电影的标题、类型、上映时间…

把网页源代码获取下来之后,下一步我们把想要的数据提取出来,数据的爬取就完成了

请求

HTTP中最常见的请求之一就是GET请求

GET请求

URLhttp://httpbin.org/get

如果客户端发起的是GET请求的话,该网站会判断并返回相应的请求信息,包括Headers、IP等

import requests

r = requests.get("http://httpbin.org/get")

print(r.text)

VESA格式与JEIDA格式标准_VESA格式与JEIDA格式标准_02

我们成功发起了GET请求,也通过这个网站的返回结果得到了请求所携带的信息,包括Headers、URL、IP

对于GET请求,URL后面可以跟上一些参数,我们添加两个参数,name是germey,age25,URL就可以写成

http://httpbin.org/get?name=germey&age=25

要构造这个请求链接,是不是要直接写成这样?

r = requests.get('http://httpbin.org/get?name=germey&age=25')

可以,但如果这些参数还需要我们手动拼接,未免有些不人性化

一般情况下,我们利用params参数就可以直接传递了

import requests

data = {
    'name':'germey',
    'age':25
}

r = requests.get('http://httpbin.org/get',params=data)
print(r.text)

VESA格式与JEIDA格式标准_request_03

我们把URL参数通过字典的形式传给get方法的params参数,通过返回信息我们可以判断,请求的链接自动被构造成了:http://httpbin.org/get?name=germey&age=25 这样我们就不用再自己去构造URL

网页的返回类型实际上是str类型,但是它很特殊,是JSON格式的,如果想直接解析返回结果,得到一个JSON格式的数据的话,可以直接调用JSON方法

import requests

r = requests.get('http://httpbin.org/get')
print(type(r.text))
print(r.json())
print(type(r.json()))

VESA格式与JEIDA格式标准_request_04

调用json方法,就可以将返回结果是JSON格式的字符串转化成字典

如果返回结果不是JSON格式,便会出现解析错误,抛出json.decoder.JSONDecodeError异常

抓取网页

上面的请求链接返回的是JSON形式的字符串,那么如果请求普通的网页,则肯定能获得相应的内容,再加上一点提取信息的逻辑

import requests
import re

r = requests.get('https://static1.scrape.cuiqingcai.com/', verify=False)
pattern = re.compile('<h2.*?>(.*?)</h2>',re.S)
titles = re.findall(pattern,r.text)
print(titles)

VESA格式与JEIDA格式标准_python_05

用最基础的正则表达式来匹配出所有的标题

成功提取出了所有的电影标题,一个基本的抓取和提取流程就完成了

抓取二进制数据

上面的例子中,我们抓取的是网站的一个页面,实际上它返回的是一个HTML文档。

图片、音频、视频这些文件本质上都是由二进制码组成的,由于有特定的保存格式和对应的解析方式,我们才可以看到这些形形色色的多媒体

要抓取它们,就要拿到它们的二进制数据

GitHub的站点图标

import requests

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

VESA格式与JEIDA格式标准_python_06

VESA格式与JEIDA格式标准_http_07

上面 r.text的结果,下面是r.content的结果

前者出现了乱码,后者结果前面带有一个b,这代表是bytes类型的数据

由于图片是二进制数据,所以前者在打印时转换成str类型,也就是图片直接转换为字符串,当然会出现乱码

我们将提取到的信息保存下来

import requests

r = requests.get('http://github.com/favicon.ico')
with open('favicon.ico','wb') as f:
    f.write(r.content)

使用open方法,它的第一个参数是文件名称,第二个参数代表以二进制的形式打开,可以向文件里写入二进制数据

音频和视频文件也可以用这种方法获取

添加headers

在发起一个HTTP请求的时候,会有一个请求头Request Headers

我们使用headers参数就可以完成了

刚才的实例中,我们没有设置Request Headers信息,如果不设置,某些网站就会发现这不是一个正常的浏览器发起的请求,网站可能会返回异常的结果,导致网页抓取失败

添加Headers信息,添加一个User-Agent字段

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'
}
r = requests.get('https://static1.scrape.cuiqingcai.com/',headers=headers)
print(r.text)

当然,我们可以在headers参数中任意添加其他的字段信息

POST请求

import requests

data = {'name':'germy','age':'25'}
r = requests.post("http://httpbin.org/post",data=data)
print(r.text)

VESA格式与JEIDA格式标准_状态码_08

form部分就是提交的数据,这就证明POST请求成功发送了

响应

发送请求后,得到的自然就是响应,即Response

上面的实例中,我们使用text和content获取了响应的内容

还有很多属性和方法可以用来获取其他信息,比如状态码、响应头、Cookies等

import requests

r=requests.get('https://static1.scrape.cuiqingcai.com/',verify=Flase)
print(type(r.status_code),r.status_code)
print(type(r.headers),r.headers)
print(type(r.cookies),r.cookies)
print(type(r.url),r.url)
print(type(r.history),r.history)

VESA格式与JEIDA格式标准_状态码_09

分别打印输出status_code属性得到状态码,输出headers属性得到响应头,输出Cookies属性得到Cookies,输出url属性得到URL,输出history属性得到请求历史

headers和cookies这两个属性得到的结果分别是CaseInsensitiveDict和RequestsCookieJar类型

状态码是用来表示响应状态的,返回200代表我们得到的响应是没问题的,我们可以通过判断Response的状态码来确认是否爬取成功

requests还提供了一个内置的状态码查询对象 requests.codes

import requests

r = requests.get('https://static1.scrape.cuiqingcai.com/',verify=False)
exit() if not r.status_code == requests.codes.ok else print('Request Successfully')

这里通过比较返回码和内置的成功的返回码,来保证请求得到了正常响应,输出成功请求的消息,否则程序终止,requests.codes.ok得到的是成功的状态码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',),  



# 重定向状态码  

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

高级用法

文件上传

requests可以模拟提交一些数据

假如有的网站需要上传文件

import requests

files = {'file':open('favicon.ico','rb')}
r = requests.post('http://httpbin.org/post',files=files)
print(r.text)

favicon.ico需要和当前脚本在同一目录下

VESA格式与JEIDA格式标准_python_10

VESA格式与JEIDA格式标准_python_11

网站会返回响应,里面包含files这个字段,而form字段是空的,这证明文件上传部分会单独有一个files字段来标识

Cookies

一个获取Cookies的过程

import requests

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

VESA格式与JEIDA格式标准_http_12

首先调用cookies属性即可成功得到Cookies

可以发现它是RequestsCookieJar类型

然后用items方法将其转化为元组组成的列表,遍历输出每一个Cookies的名称和值,实现Cookie的遍历解析

我们也可以直接用Cookie来维持登录状态,以GitHub为例,登录GitHub,然后将Headers中的Cookie内容复制下来

import requests

headers = {
    'Cookie':'_octo=GH1.1.105174646.1611285614; tz=Asia%2FShanghai; _device_id=e3e5be50c68232ae282cb57a6f4d1bae; has_recent_activity=1; user_session=vxqtENlWRws-DvURQJtiwO8M1SR_Cg2ugsoY5MSYeKh-OGe5; __Host-user_session_same_site=vxqtENlWRws-DvURQJtiwO8M1SR_Cg2ugsoY5MSYeKh-OGe5; tz=Asia%2FShanghai; logged_in=yes; dotcom_user=Leon-1999; _gh_sess=UjrkQOlAjWV2GfUy6KtU%2FvFCs1J%2Bt%2BfLdiFWJ6CRW6hgjMYNB35RwJdoMzW9o22Eig3zTkeCW6bAq%2F22FQik0OrtzvJSX9dzIpdi0yyAzw7qvRMbEEnPI4j3AzDUHo4A3QuyDENOTzSNW6QjKuEJDGV1HnGNN2e4F%2FOvVL%2FGnzwzkuJqSfB%2BxlZ0MSVuO3ci%2FxJa%2BP86W%2FZiAr%2FjIzrwYkr3SfRC5%2BmnuwyPBqFpQPi8qhnu8ZLxjmKZaddrY1cHrtZNMHzTzIW%2F63MgEcDrvItgbgVEICFohlmrqV7218hPVKhMwAF87FWivuUXk%2FOPerqQlaPIeu8IEjTwgnrFGbc2Gi6vYUHdHtkkxR2XRK84UR3jkubHlrK1Pl1XJY4oMyegS4Zl%2BN4ZzX06SImZlEkWnT6zGU4JEcXMzqHF7ISie5osts5SI%2FkVufDPOheWYnl02ftP2T26edSMbwLxPCb0aYhVm0ueBZ2ppzfCNIwOyHsVCgCIkKA0R%2BX7ofkWdS76RInzSlrYgpI2ntwiky9Zx0iilPh7lGbU97ltcFYRLk8evQ3y26xSIw56DUjaYdsxSJ%2FQdZ3n8OBLZfaCqnko%2BBz2gk2y%2Fb1jW9l1aF5ZMtg9%2FWlxd%2FqJvrE0KU65Xv8snz45JNxpLJNcDkBkc71WYLTQ3yo%2FrR7ssrVsuk%2Fh3BXadxrr1kd8%2FRwrMEqLICNQM4H8uA2zVOcMUwvIIo6F5Nsk5lNI1PcYS3bt%2BV26Z07p6AKnrN30p05NLWKvU0mIbA9Q7h7UWEXie1HeoA5HaNWFQdk6D4%2BHojFU%2BOnPMgtwdohvrGDzPI0mXsnuELv%2FlLdkdUWhwfr0Kt%2BIHwf1uDiPu0efxM%2BaoxBoVdKSrAzgOjb%2BuOrdGMkMQfExNx3gniHjVnw2Y%2BBJNidFFCWuKQJvEGZN0du8KA19jg4%3D--LJvR5S2QWc6Q%2BqSr--SXNUblMcMmvDNKsNgu4rNg%3D%3D'
    'User-Agent':"Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36"
}

r = requests.get('https://github.com/',headers=headers)
print(r.text)

发现结果中包含了登录后才能显示的结果

VESA格式与JEIDA格式标准_python_13

用Cookies成功模拟了登录状态,这样我们就能爬取登录之后才能看到的页面了


也可以通过cookies参数来设置Cookies的信息,我们可以构造一个RequestsCookieJar对象,然后把刚才的cookie处理并赋值

import requests

cookies='_octo=GH1.1.105174646.1611285614; tz=Asia%2FShanghai; _device_id=e3e5be50c68232ae282cb57a6f4d1bae; has_recent_activity=1; user_session=vxqtENlWRws-DvURQJtiwO8M1SR_Cg2ugsoY5MSYeKh-OGe5; __Host-user_session_same_site=vxqtENlWRws-DvURQJtiwO8M1SR_Cg2ugsoY5MSYeKh-OGe5; tz=Asia%2FShanghai; logged_in=yes; dotcom_user=Leon-1999; _gh_sess=UjrkQOlAjWV2GfUy6KtU%2FvFCs1J%2Bt%2BfLdiFWJ6CRW6hgjMYNB35RwJdoMzW9o22Eig3zTkeCW6bAq%2F22FQik0OrtzvJSX9dzIpdi0yyAzw7qvRMbEEnPI4j3AzDUHo4A3QuyDENOTzSNW6QjKuEJDGV1HnGNN2e4F%2FOvVL%2FGnzwzkuJqSfB%2BxlZ0MSVuO3ci%2FxJa%2BP86W%2FZiAr%2FjIzrwYkr3SfRC5%2BmnuwyPBqFpQPi8qhnu8ZLxjmKZaddrY1cHrtZNMHzTzIW%2F63MgEcDrvItgbgVEICFohlmrqV7218hPVKhMwAF87FWivuUXk%2FOPerqQlaPIeu8IEjTwgnrFGbc2Gi6vYUHdHtkkxR2XRK84UR3jkubHlrK1Pl1XJY4oMyegS4Zl%2BN4ZzX06SImZlEkWnT6zGU4JEcXMzqHF7ISie5osts5SI%2FkVufDPOheWYnl02ftP2T26edSMbwLxPCb0aYhVm0ueBZ2ppzfCNIwOyHsVCgCIkKA0R%2BX7ofkWdS76RInzSlrYgpI2ntwiky9Zx0iilPh7lGbU97ltcFYRLk8evQ3y26xSIw56DUjaYdsxSJ%2FQdZ3n8OBLZfaCqnko%2BBz2gk2y%2Fb1jW9l1aF5ZMtg9%2FWlxd%2FqJvrE0KU65Xv8snz45JNxpLJNcDkBkc71WYLTQ3yo%2FrR7ssrVsuk%2Fh3BXadxrr1kd8%2FRwrMEqLICNQM4H8uA2zVOcMUwvIIo6F5Nsk5lNI1PcYS3bt%2BV26Z07p6AKnrN30p05NLWKvU0mIbA9Q7h7UWEXie1HeoA5HaNWFQdk6D4%2BHojFU%2BOnPMgtwdohvrGDzPI0mXsnuELv%2FlLdkdUWhwfr0Kt%2BIHwf1uDiPu0efxM%2BaoxBoVdKSrAzgOjb%2BuOrdGMkMQfExNx3gniHjVnw2Y%2BBJNidFFCWuKQJvEGZN0du8KA19jg4%3D--LJvR5S2QWc6Q%2BqSr--SXNUblMcMmvDNKsNgu4rNg%3D%3D'

jar = requests.cookies.RequestsCookieJar()
headers = {
    'User-Agent':'Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
}
for cookie in cookies.split(';'):
    key,value = cookie.split('=',1)
    jar.set(key,value)
r = requests.get('https://github.com/',cookies=jar,headers=headers)
print(r.text)

首先新建一个RequestsCookieJar对象,然后将cookies利用split方法分割,接着利用set方法设置好每个Cookie的key和value,最后通过调用requests的get方法并传递给cookies参数即可,同样可以正常登录

Session维持

在requests中,如果直接利用get或post等方法的确可以做到模拟网页的请求,但这实际上是相当于不同的Session,相当于你用两个浏览器打开了不同的页面

设想这样一个场景,第一个请求利用post方法登录了某个网站,第二次想获取成功登录后的自己的个人信息,又用了一次get方法去请求个人信息页面。

实际上,这相当于打开了两个浏览器,是两个完全不相关的Session,能成功获取个人信息吗?当然不能

有人会问,那我在两次请求时设置一样的Cookies不就行了?可以,但这样做很烦琐,有更简单的解决方法

解决这个问题的主要方法是维持同一个Session,相当于打开一个新的浏览器选项卡而不是新开一个浏览器。

我们又不想每次设置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)

这里我们请求了一个测试网址,请求这个网址时,可以设置一个cookie,名称叫做number,内容是123456789,随后又请求一次,此网址可以获取当前的Cookies

这样能成功获取到设置的Cookies吗?

VESA格式与JEIDA格式标准_request_14

并不行,我们用Session试试看

import requests
s = requests.Session()
s.get('http://httpbin.org/cookies/set/number/123456789')
r = s.get('http://httpbin.org/cookies')
print(r.text)

VESA格式与JEIDA格式标准_http_15

成功获取!这就是同一个Session和不同Session的区别

利用Session,可以做到模拟同一个Session而不用担心Cookies的问题了,它通常用于模拟登录成功之后再进行下一步的操作

SSL证书验证

现在很多网站都要求使用HTTPS协议,但是有些网站可能并没有设置好HTTPS证书,或者网站的HTTPS证书不被CA机构认可,这些网站就可能出现SSL证书错误的提示


VESA格式与JEIDA格式标准_状态码_16

我们可以在浏览器中通过一些设置来忽略证书的验证

我们用requests来请求这类网站

import requests

response = requests.get('https://static2.scrape.cuiqingcai.com/')
print(response.status_code)

VESA格式与JEIDA格式标准_python_17

这里直接抛出了SSLError错误,原因就是因为我们请求的URL的证书是无效的

如果我们一定要爬取这个网址,可以使用verify参数控制是否验证证书,如果将其设置为False,在请求时就不会再验证证书是否有效。如果不加verify参数的话,默认值是True,会自动验证

import requests
response = requests.get('https://static1.scrape.cuiqingcai.com/',verify=False)

print(response.status_code)

VESA格式与JEIDA格式标准_http_18

这样就打印出请求成功的状态码,不过我们发现了一个警告,它建议我们给它制定证书。我们可以通过设置忽略警告的方法来屏蔽这个警告

import requests
from requests.packages import urllib3

urllib3.disable_warnings()
response = requests.get('https://static1.scrape.cuiqingcai.com/',verify=False)
print(response.status_code)

VESA格式与JEIDA格式标准_python_19

或者通过捕获警告到日志的方式忽略警告:

import logging
import requests
logging.captureWarnings(True)
response = requests.get('https://static1.scrape.cuiqingcai.com/',verify=False)
print(response.status_code)

VESA格式与JEIDA格式标准_状态码_20

我们也可以制定一个本地证书用作客户端证书,这可以是单个文件(包含密钥和证书)或一个包含两个文件路径的元组

import requests

response = requests.get('https://static1.scrape.cuiqingcai.com/',cert=('/path/server.crt','/path/server.key'))
print(response.status_code)

我们需要有crt和key文件,并且制定它们的路径

本地私有证书的key必须是解密状态,加密状态的key是不支持的

身份认证

在访问某些设置了身份认证的网站时,我们可能会遇到认证窗口


VESA格式与JEIDA格式标准_python_21

这种情况下,这个网站启用了基本身份认证,HTTP Basic Access Authentication,它是一种允许网页浏览器或者其他客户端程序在请求时提供用户名和口令形式的身份凭证的一种登录验证方式

我们可以使用requests自带的身份认证功能,通过auth参数即可设置

import requests
from requests.auth import HTTPBasicAuth

r = requests.get('https://static3.scrape.cuiqingcai.com/',auth=HTTPBasicAuth('admin','admin'))
print(t.status_code)

如果用户名和密码正确的话,请求时会自动认证成功,返回200状态码;如果认证失败,则返回401状态码

如果参数都传一个HTTPBasicAuth类,就显得有些烦琐

所以requests提供了一个更简单的写法,可以直接传一个元组,它默认使用HTTPBasicAuth类来认证

import requests
r = requests.get('https://static3.scrape.cuiqingcai.com/',auth=('admin','admin'))

此外,requests还提供了其他认证方式,OAuth认证

pip3 install requests_oauthlib

使用OAuth1认证的方法如下:

import requests
from requests_oauthlib import OAuth1
url = 'https://api.twitter.com/1.1/account/verify_credentials.json'
auth = OAuth1('YOUR_APP_KEY', 'YOUR_APP_SECRET',
              'USER_OAUTH_TOKEN', 'USER_OAUTH_TOKEN_SECRET')
requests.get(url, auth=auth)

超时设置

在本机网络状况不好或者服务器网络响应延迟甚至无响应时,我们可能会等待很久才能收到响应,甚至最后收不到响应而报错。

为了防止服务器不能及时响应,应该设置一个超时时间,即超过了这个时间还没有得到响应,那就报错

这需要用到timeout参数,这个时间的计算是发出请求到服务器返回响应的时间

import requests

r = requests.get('http://httpbin.org/get',timeout=1)
print(r.status_code)

我们将超时时间设置为1秒,如果1秒内没有响应,那就抛出异常

请求分为两个阶段,即连接(connect)和读取(read)

timeout将作用连接和读者这二者的timeout总和

如果要分别指定,就可以传入一个元组:

r = requests.get('https://httpbin.org/get',timeout=(5,30))

如果想永久等待,可以直接将timeout设置为None,或者不设置直接留空,因为默认是None

这样的话,如果服务器还在运行,但是响应特别慢,那就慢慢等吧,它永远不会返回超时错误的

r = requests.get('https://httpbin.org/get',timeout=None)

或直接不加参数

r = requests.get('https://httpbin.org/get')

代理设置

某些网站在测试的时候请求几次,能正常获取内容

但是对于大规模且频繁的请求,网站可能会弹出验证码,或者跳转到登录认证页面,更甚者可能会直接封禁客户端的IP,导致一定时间内无法访问

为了防止这种情况发生,我们需要设置代理来解决这个问题,需要用到proxies参数

import requests

proxies ={
  'http': 'http://10.10.10.10:1080',
  'https': 'http://10.10.10.10:1080',
}
requests.get('https://httpbin.org/get',proxies=proxies)

这个代理可能是无效的,可以直接搜索寻找有效的代理并替换试验一下

若代理需要使用上文所述的身份认证,可以使用类似http://user:password@host:port

import requests
proxies = {'https':'http://user:password@10.10.10.10:1080/'}
requests.get('https://httpbin.org/get',proxies=proxies)

除了基本的HTTP代理外,requests还支持SOCKS协议的代理

pip3 install “requests[socks]”

import requests
proxies = {
    'http':'sock5://user:password@host:port',
    'https':'sock5://user:password@host:port'
}
requests.get('https://httpbin.org/get',proxies=proxies)

Prepared Request

我们使用requests库的get和post方法可以直接发送请求,但有没有想过,这个请求在requests内部是怎么实现的?

实际上,requests在发送请求的时候在内部构造了一个Request对象,并给这个对象赋予了各种参数,包括url、headers、data…

然后直接把这个Request对象发送出去,请求成功后会再得到一个Response对象,再解析即可

这个Request是什么类型呢?实际上它就是Prepared Request

深入一下,不用get方法,直接构造一个Prepared Request对象

from requests import Request,Session
url = 'http://httpbin.org/post'
data = {'name':'germey'}
headers = {'User-Agent':'Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'}
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方法将其转换为一个Prepare Request对象,然后调用send方法发送

VESA格式与JEIDA格式标准_状态码_22

同样达到了POST请求效果

予了各种参数,包括url、headers、data…

然后直接把这个Request对象发送出去,请求成功后会再得到一个Response对象,再解析即可

这个Request是什么类型呢?实际上它就是Prepared Request

深入一下,不用get方法,直接构造一个Prepared Request对象

from requests import Request,Session
url = 'http://httpbin.org/post'
data = {'name':'germey'}
headers = {'User-Agent':'Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'}
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方法将其转换为一个Prepare Request对象,然后调用send方法发送


VESA格式与JEIDA格式标准_request_23

同样达到了POST请求效果

有了Request对象,就可以将请求当做独立的对象来看待,这样一些场景中我们可以直接操作Request对象,更灵活地实现请求的调度和各种操作