本文小编为大家详细介绍“怎么使用Python的Requests库”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用Python的Requests库”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
快速开始
发送请求
>>> import requests >>> r = requests.get('https://api.github.com/events') # GET >>> r = requests.post('https://httpbin.org/post', data={'key': 'value'}) # POST >>> r = requests.put('https://httpbin.org/put', data={'key': 'value'}) # PUT >>> r = requests.delete('https://httpbin.org/delete') # DELETE >>> r = requests.head('https://httpbin.org/get') # HEAD >>> r = requests.options('https://httpbin.org/get') # OPTIONS
URL传参
可以使用
params字典参数为URL提供查询字符串参数,例如,访问
https://httpbin.org/get?key1=value1&key2=value2,可使用以下代码:
>>> import requests >>> payload = {'key1': 'value1', 'key2': 'value2', 'key3':'', 'key4':None} >>> r = requests.get('https://httpbin.org/get', params=payload) >>> r.url https://httpbin.org/get?key2=value2&key1=value1&key3=
需要注意的是,如果字典参数中key值(即URL参数的值为
None),则该参数不会添加到URL的查询字符串中。
如果URL查询字符串中,存在重复参数(参数名称相同,参数值不同),则需要将key值设置为由参数值组成的列表,如下:
>>> import requests >>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']} >>> r = requests.get('https://httpbin.org/get', params=payload) >>> r.url https://httpbin.org/get?key1=value1&key2=value2&key2=value3
响应内容
读取服务器响应内容
>>> import requests >>> r = requests.get('https://api.github.com/events') >>> r.text <class 'str'> [{"id":"27579847062","type":"PushEvent","actor":{"...
requests 将自动解码来自服务器的内容。大多数unicode字符集都是无缝解码的。
当你发出请求时,requests会根据HTTP头对响应的编码进行有依据的猜测。当你访问
r.text时,将使用requests猜测的文本编码。可以使用
r.encoding属性查找请求使用的编码,并对其进行更改:
>>> r.encoding # 输出:utf-8 r.encoding = 'ISO-8859-1'
如果更改编码,则每当调用
r.text时,requests都将使用新的
r.encoding的值。在任何情况下,你都可以应用特殊逻辑来确定内容的编码。例如,HTML和XML可以在其正文中指定其编码。在这种情况下,你应该使用
r.content查找编码,然后设置
r.encoding。这将允许你使用具有正确编码的
r.text。
requests还将在需要时使用自定义编码。如果你已经创建了自己的编码并将其注册到
codecs模块,则可以简单地使用codec名称作为
r.encoding的值,而requests将为你处理解码。
二进制响应内容
对于非文本请求,还可以以字节的形式访问响应体(当然,文本请求也可以):
>>> r.content b'[{"id":"27581220674","type":"IssueCommentEvent","actor":{"id":327807...
requests会自动解码
gzip和
deflate传输编码。
如果安装了类似 brotli 或 brotlicffi的Brotil类库,Requets也会自动界面
br传输编码
如果Brotli库(如[Brotli])为您自动解码
br传输编码(https://pypi.org/project/brotli)或brotliffi已安装。
例如,可以使用以下代码,从请求返回的二进制数据创建图像:
from PIL import Image from io import BytesIO img = Image.open(BytesIO(r.content))
JSON响应内容
可使用内置的JSON解码器,处理JSON数据:
>>> import requests >>> r = requests.get('https://api.github.com/events') >>> r.json() # JSON [{'id': '27609416600', 'type': 'PushEvent', ...
如果JSON解码失败,
r.json()将抛出异常。例如,如果响应得到一个204(无内容),或者如果响应包含无效的JSON,则
r.json()会抛出
requests.exceptions.JSONDecodeError。此封装的异常可能会因为不同python版本和JSON序列化库可能引发的多个异常提供互操作性。
需要注意的是,调用
r.json()的成功调用并不表示响应的成功。一些服务器可能会在失败的响应中返回JSON对象(例如,HTTP 500的错误详细信息)。这样的JSON将被解码并返回。要检查请求是否成功,请使用
r.raise_for_status()或检查
r.status_code
原始响应内容
可以通过访问
r.raw访问服务器返回的原始socket响应。如果希望这样做,确保在初始请求中设置
stream=True:
>>> import requests >>> r = requests.get('https://api.github.com/events', stream=True) >>> r.raw <urllib3.response.HTTPResponse object at 0x0000018DB1704D30> >>> r.raw.read(10) b'x1fx8bx08x00x00x00x00x00x00x03'
然而,通常情况下,应该使用类似这样的模式来保存正在流式传输的内容到文件中:
with open(filename, 'wb') as fd: for chunk in r.iter_content(chunk_size=128): fd.write(chunk)
使用
Response.iter_content将处理很多你在直接使用
Resort.raw时需要处理的事情。当流式传输下载时,以上是检索内容的首选和推荐方法。请注意,
chunk_size可以自由调整为更适合你使用场景的数字。
注意
关于使用
Response.iter_content与
Response.raw的重要注意事项。
Response.iter_content将自动解码
gzip和
deflate传输编码。
Response.raw是一个原始字节流--它不会转换响应内容。如果确实需要访问返回的字节,请使用
Response.raw。
自定义请求头
如果您想向请求中添加HTTP头,只需向
headers参数传递一个
dict即可,例如:
>>> url = 'https://api.github.com/some/endpoint' >>> headers = {'user-agent': 'my-app/0.0.1'} >>> r = requests.get(url, headers=headers)
注意:自定义请求头的优先级低于更具体的信息源。例如:
如果在
.netrc
中指定了凭据,则使用headers=
设置的Authorization
请求头将被覆盖,而凭据又将被auth=
参数覆盖。请求将在~/.netrc
、~/_netrc
或NETRC
环境变量指定的路径处中搜索netrc文件。如果从主机重定向,将删除
Authorization
请求头。Proxy-Authorization
请求头将被URL中提供的代理凭据覆盖。当我们可以确定内容的长度时,将覆盖
Content-Length
请求头。
此外,请求根本不会根据指定的自定义请求头更改其行为。请求头仅是简单的传递到最终请求中。
注意:所有请求头值必须是字符串、字节字符串或unicode。虽然允许,但建议避免传递unicode请求头值。
更复杂的POST请求More complicated POST requests
通常,如果发送一些表单编码(form-encoded)的数据--就像一个HTML表单。为此,只需将字典传递给
data参数即可。发送请求时,将自动对字典数据进行表单编码:
>>> import requests >>> payload = {'key1': 'value1', 'key2': 'value2'} >>> r = requests.post("https://httpbin.org/post", data=payload) >>> r.text { "args": {}, "data": "", "files": {}, "form": { "key1": "value1", "key2": "value2" }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "23", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "python-requests/2.27.1", "X-Amzn-Trace-Id": "Root=1-6409fe3b-0cb4118319f09ab3187402bc" }, "json": null, "origin": "183.62.127.25", "url": "https://httpbin.org/post" }
data参数中,为每个键可以具有多个值。这可以通过将
data设置为元组列表或以列表为值的字典来实现。当表单中有多个元素使用相同的键时,这特别有用:
>>> import requests >>> payload_tuples = [('key1', 'value1'), ('key1', 'value2')] >>> r1 = requests.post('https://httpbin.org/post', data=payload_tuples) >>> payload_dict = {'key1': ['value1', 'value2']} >>> r2 = requests.post('https://httpbin.org/post', data=payload_dict) >>> r1.text { "args": {}, "data": "", "files": {}, "form": { "key1": [ "value1", "value2" ] }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "23", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "python-requests/2.27.1", "X-Amzn-Trace-Id": "Root=1-6409ff49-11b8232a7cc81fc0290ec4c4" }, "json": null, "origin": "183.62.127.25", "url": "https://httpbin.org/post" } >>> re.text == r2.text True
有时,你可能想发送未经表单编码的数据,则需要传入
string类型的数据,而不是
dict,
string数据将被直接提交。
例如,GitHub API v3接受JSON编码的POST/PATCH数据:
>>> import requests >>> import json >>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, data=json.dumps(payload))
请注意,上述代码不会添加
Content-Type请求头(特别是不会将其设置为
application/json)。如果需要设置那个请求头(
'Content-Type': 'application/json,发送json请求体),并且不想自己对
dict进行编码,你也可以直接使用
json参数传递它,它将自动被编码:
>>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> r = requests.post(url, json=payload)
注意,如果提供了
data,或者
file参数,
json参数将被自动忽略。
提交Multipart-Encoded文件
Request让上传Multipart编码文件变得简单:
>>> import requests >>> url = 'https://httpbin.org/post' >>> files = {'file': open('report.xls', 'rb')} >>> r = requests.post(url, files=files) >>> r.text { "args": {}, "data": "", "files": { "file": "#!/usr/bin/env python # -*- coding:utf-8 -*- #!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Pool from threading import Thread from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor..." }, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "3035", "Content-Type": "multipart/form-data; boundary=9ef4437cb1e14427fcba1c42943509cb", "Host": "httpbin.org", "User-Agent": "python-requests/2.27.1", "X-Amzn-Trace-Id": "Root=1-640a03df-1a0a5ce972ce410378cda7a2" }, "json": null, "origin": "183.62.127.25", "url": "https://httpbin.org/post" }
可以显示的设置文件名称,内容类型,请求头:
>>> url = 'https://httpbin.org/post' files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})} >>> r = requests.post(url, files=files) >>> r.text { "args": {}, "data": "", "files": { "file": "data:application/vnd.ms-excel;base64,UEsDBBQAAAAAAHy8iFMAAAAAAA...==" }, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "9667", "Content-Type": "multipart/form-data; boundary=ff85e1018eb5232f7dcab2b2bc5ffa50", "Host": "httpbin.org", "User-Agent": "python-requests/2.27.1", "X-Amzn-Trace-Id": "Root=1-640def51-43cc213e33437a0e60255add" }, "json": null, "origin": "183.62.127.25", "url": "https://httpbin.org/post" }
如果想发送一些字符串,以文件的方式被接收:
>>> url = 'https://httpbin.org/post' >>> files = {'file': ('report.csv', 'some,data,to,send another,row,to,send ')} >>> r = requests.post(url, files=files) >>> r.text { "args": {}, "data": "", "files": { "file": "some,data,to,send another,row,to,send " }, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "184", "Content-Type": "multipart/form-data; boundary=2bfe430e025860528e29c893a09f1198", "Host": "httpbin.org", "User-Agent": "python-requests/2.27.1", "X-Amzn-Trace-Id": "Root=1-640df132-247947ca699e9da35c588f2d" }, "json": null, "origin": "183.62.127.25", "url": "https://httpbin.org/post" }
如果你将一个非常大的文件作为
multipart/form-data请求提交,你可能需要流式传输该请求。默认情况下,
requests不支持此功能,但有一个单独的包支持此功能——
requests toolbelt。阅读toolbelt文档获取有关如何使用它的详细信息。
要在一个请求中发送多个文件,请参阅高级章节。
警告
强烈建议以二进制模式打开文件。这是因为requests可能会尝试为你提供
Content-Length请求头,如果这样做,该请求头值将被设置为文件中的字节数。如果以文本模式打开文件,可能会发生错误。
响应状态码
>>> import requests >>> r = requests.get('https://httpbin.org/get') >>> r.status_code 200
以便于参考,
requests还附带一个内置的状态代码查找对象:
>>> r = requests.get('https://httpbin.org/get') >>> r.status_code == requests.codes.ok True
如果请求出错4XX客户端错误或5XX服务器错误响应),我们可以使用
response.raise_for_status()抛出错误:
>>> import requests >>> bad_r = requests.get('https://httpbin.org/status/404') >>> bad_r.status_code 404 >>> bad_r.raise_for_status() Traceback (most recent call last): File "D:/codePojects/test.py", line 12, in <module> bad_r.raise_for_status() File "D:Program Files (x86)python36libsite-packages equestsmodels.py", line 960, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 404 Client Error: NOT FOUND for url: https://httpbin.org/status/404
但是,如果
r.status_code为
200,
raise_for_status()将返回
None
>>> r.raise_for_status() None
响应头
>>> r.headers { 'content-encoding': 'gzip', 'transfer-encoding': 'chunked', 'connection': 'close', 'server': 'nginx/1.0.4', 'x-runtime': '148ms', 'etag': '"e1ca502697e5c9317743dc078f67693f"', 'content-type': 'application/json' }
根据RFC 7230, HTTP请求头大小写不敏感,所以,我们可以使用任何大写。因此,我们可以使用任意大小写来访问请求头:
>>> r.headers['Content-Type'] 'application/json' >>> r.headers.get('content-type') 'application/json'
Cookies
如果响应包含Cookie,可以快速访问它们:
>>> url = 'http://example.com/some/cookie/setting/url' >>> r = requests.get(url) >>> r.cookies['example_cookie_name'] # 如果存在名为 example_cookie_name的cookie的话 'example_cookie_value'
可以使用
cookies参数将cookie发送给服务器:
>>> url = 'https://httpbin.org/cookies' >>> cookies = dict(cookies_are='working') >>> r = requests.get(url, cookies=cookies) >>> r.text '{ "cookies": { "cookies_are": "working" } } '
Cookies are returned in a
RequestsCookieJar, which acts like a
dictbut also offers a more complete interface, suitable for use over multiple domains or paths. Cookie jars can also be passed in to requests:
返回的Cookie存储在
RequestsCookieJar中,其作用类似于
dict,同时提供了一个更完整的接口,适合在多个域或路径上使用。Cookie jar也可以传递给请求:
>>> jar = requests.cookies.RequestsCookieJar() >>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies') Cookie(version=0, name='tasty_cookie', value='yum', port=None, port_specified=False, domain='httpbin.org', domain_specified=True, domain_initial_dot=False, path='/cookies', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False) >>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere') Cookie(version=0, name='gross_cookie', value='blech', port=None, port_specified=False, domain='httpbin.org', domain_specified=True, domain_initial_dot=False, path='/elsewhere', path_specified=True, secure=False, expires=None, discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False) >>> url = 'https://httpbin.org/cookies' >>> r = requests.get(url, cookies=jar) >>> r.text '{"cookies": {"tasty_cookie": "yum"}}'
重定向与history
默认情况下,
requests将对除
HEAD之外的所有请求执行位置重定向(如果需要重定向的话)。
我们可以使用Response对象的
history属性来跟踪重定向。
Response.history列表包含为完成请求而创建的
Response对象。列表按响应的先后顺序排序。
例如,Gitee将所有HTTP请求重定向到HTTPS:
>>> r = requests.get('http://gitee.com/') >>> r.url 'https://gitee.com/' >>> r.status_code 200 >>> r.history [<Response [302]>]
如果使用HEAD,GET,
OPTIONS,
POST,
PUT,
PATCH或者
DELETE,可以使用
allow_redirects参数禁止重定向:
>>> r = requests.get('http://gitee.com/', allow_redirects=False) >>> r.status_code 302 >>> r.history [] >>> r = requests.head('http://gitee.com/', allow_redirects=False) >>> r.url 'http://gitee.com/' >>> r.status_code 302 >>> r.history [] >>> r = requests.head('http://gitee.com/', allow_redirects=True) >>> r.status_code 200 >>> r.url 'https://gitee.com/' >>> r.history [<Response [302]>]
请求超时
可以使用
timeout参数告诉requests在给定的秒数后停止等待响应。几乎所有的生产代码都应该在几乎所有的请求中使用此参数。否则会导致程序无限期挂起:
>>> requests.get('https://gitee.com/', timeout=0.1) Traceback (most recent call last): File "<stdin>", line 1, in <module> ... urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='gitee.com', port=443): Read timed out. (read timeout=0.1)
注意:
timeout不是整个响应的下载时间限制;相反,如果服务器在
timeout秒内没有发出响应(更准确地说,如果在
timeout秒内底层socket没有接收到任何字节数据),则会引发异常。如果未明确指定
timeout,则请求不会超时。
错误和异常
如果出现网络问题(例如DNS故障、拒绝连接等),requests将抛出
ConnectionError异常。
如果HTTP请求返回了失败的状态代码,
Response.raise_for_statu()将抛出
HTTPError
如果请求超时,则会抛出
Timeout异常。
如果请求超过了配置的最大重定向次数,则会抛出
TooManyRedirects异常。
requests显式抛出的所有异常都继承自
requests.exceptions.RequestException。
高级用法
Session对象
Session对象允许你跨请求保持某些参数,以及Session实例发出的所有请求的cookie,并将使用
urllib3的[连接池](https://urllib3.readthedocs.io/en/latest/reference/index.html#module-urllib3.connectionpool)。因此,如果你向同一主机发出多个请求,将复用底层TCP连接,这可能会显著提高性能(请参见HTTP持久连接)。
Session对象具有主要 requests API的所有方法。
让我们在请求之间保持一些cookie:
>>> s = requests.Session() >>> s.get('https://httpbin.org/cookies/set/sessioncookie/123456789') <Response [200]> >>> r = s.get('https://httpbin.org/cookies') >>> r.text '{ "cookies": { "sessioncookie": "123456789" } } ' >>>
Seesion对象还可以用于向请求方法提供默认数据。这是通过向Session对象属性提供数据来实现的:
>>> s = requests.Session() >>> s.auth = ('user', 'pass') >>> s.headers.update({'x-test': 'true'}) # 'x-test'和'x-test2'请求头随请求发送了 >>> s.headers.update({'x-test': 'true'}) >>> s.get('https://httpbin.org/headers', headers={'x-test2': 'true'}) <Response [200]>
传递给请求方法的任何字典都将与会话级别设置的值合并。方法级别的参数会覆盖会话级别的参数。
然而,请注意,即使使用会话,方法级参数也不能跨请求保持。本示例将只在发送第一个请求发送cookie,而不发送第二个请求
>>> s = requests.Session() >>> r = s.get('https://httpbin.org/cookies', cookies={'from-my': 'browser'}) >>> r.text '{ "cookies": { "from-my": "browser" } } ' >>> r = s.get('https://httpbin.org/cookies') >>> r.text '{ "cookies": {} } '
Cookie utility functions to manipulate
Session.cookies
如果想手动向Session添加Cookie,那么使用 Cookie utility functions来操作
Session.cookies。
Session对象也可以用作上下文管理器
>>> with requests.Session() as s: ... s.get('https://httpbin.org/cookies/set/sessioncookie/123456789') ... <Response [200]> >>>
这将确保在退出
with块后立即关闭会话,即使发生未处理的异常。
Remove a Value From a Dict Parameter Sometimes you'll want to omit session-level keys from a dict parameter. To do this, you simply set that key's value to `None` in the method-level parameter. It will automatically be omitted. 从字典参数中删除值 有时,你需要从dict参数中忽略会话级别的键。为此,只需在方法级参数中将该键的值设置为“None”即可。它将被自动忽略。
Session中包含的所有值都可以直接使用。参见Session API Docs了解更多信息。
请求和响应对象
示例:获取响应头和请求头
>>> r = s.get('https://httpbin.org') >>> r.headers # 获取响应头 {'Date': 'Mon, 13 Mar 2023 15:43:41 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': '9593', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true'} >>> r.request.headers {'User-Agent': 'python-requests/2.27.1', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'sessioncookie=123456789'} >>>
Prepared requests
每当收到来自某个API调用或者Session调用的
Response对象,
request属性实际上是所使用的
PreparedRequest。在某些情况下,你可能希望在发送请求之前对请求体或请求头(或其他任何内容)做一些额外的工作。简单的做法如下:
from requests import Request, Session s = Session() req = Request('POST', url, data=data, headers=headers) prepped = req.prepare() # do something with prepped.body prepped.body = 'No, I want exactly this as the body.' # do something with prepped.headers del prepped.headers['Content-Type'] resp = s.send(prepped, stream=stream, verify=verify, proxies=proxies, cert=cert, timeout=timeout ) print(resp.status_code)
However, the above code will lose some of the advantages of having a requests
S
essio
nobject. In particular,
Sessio
n-level state such as cookies will not get applied to your request. To get a
PreparedRequestwith that state applied, replace the call to
Request.prepare()with a call to
Session.prepare_request(), like this:
由于你没有对
Request对象执行任何特殊操作,因此您可以立即prepare它并修改
PreparedRequest对象。然后将其与发送给
requests.*或
Session.*的其它参数一起发送。
然而,上述代码将失去使用requests
Session对象的一些优点。特别是
Session级别的状态,比如cookie将不会应用于你的请求。如果需要获取应用了那些状态的
Prep
aredRequ
est,替换
Request.prepare()调用为
Session.prepare_request(),像这样:
from requests import Request, Session s = Session() req = Request('GET', url, data=data, headers=headers) prepped = s.prepare_request(req) # do something with prepped.body prepped.body = 'Seriously, send exactly these bytes.' # do something with prepped.headers prepped.headers['Keep-Dead'] = 'parrot' resp = s.send(prepped, stream=stream, verify=verify, proxies=proxies, cert=cert, timeout=timeout ) print(resp.status_code)
When you are using the prepared request flow, keep in mind that it does not take into account the environment. This can cause problems if you are using environment variables to change the behaviour of requests. For example: Self-signed SSL certificates specified in
REQUESTS_CA_BUNDLEwill not be taken into account. As a result an
SSL: CERTIFICATE_VERIFY_FAILEDis thrown. You can get around this behaviour by explicitly merging the environment settings into your session:
当你使用prepared request请求时,请记住它没有考虑环境。如果你正使用环境变量来更改请求的行为,这可能会导致问题。例如:在
REQUESTS_CA_BUNDLE中指定的自签名SSL证书将不起作用,结果引发了
SSL:CERT