快速开始
发送请求
>>> 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'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
然而,通常情况下,应该使用类似这样的模式来保存正在流式传输的内容到文件中:
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\r\n# -*- coding:utf-8 -*-\r\n\r\n#!/usr/bin/env python\r\n# -*- coding:utf-8 -*-\r\n\r\nfrom multiprocessing import Pool\r\nfrom threading import Thread\r\nfrom 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\nanother,row,to,send\n')} >>> r = requests.post(url, files=files) >>> r.text { "args": {}, "data": "", "files": { "file": "some,data,to,send\nanother,row,to,send\n" }, "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)\python36\lib\site-packages\requests\models.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 '{\n "cookies": {\n "cookies_are": "working"\n }\n}\n'
Cookies are returned in a RequestsCookieJar
, which acts like a dict
but 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]>]