Session 对象允许您在 请求。它还会在从 会话实例,并将使用的连接池。所以如果您正在向同一主机(底层 TCP)发出多个请求连接将被重用,这可以带来显著的性能增加。urllib3Session 对象具有主 Requests API 的所有方法。让我们在请求之间保留一些 cookie:
s = requests.Session()
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get('https://httpbin.org/cookies')
print(r.text)
'{"cookies": {"sessioncookie": "123456789"}}'
会话还可用于向请求方法提供默认数据。这是通过向 Session 对象上的属性提供数据来完成的:
s = requests.Session()
s.auth = ('user', 'pass')
s.headers.update({'x-test': 'true'})
#both 'x-test' and 'x-test2' are sent
s.get('https://httpbin.org/headers', headers={'x-test2': 'true'})
传递给请求方法的任何字典都将与 设置的会话级别值。方法级参数覆盖会话参数。
但请注意,方法级参数不会在请求,即使使用会话。此示例将仅发送 Cookie 使用第一个请求,但不使用第二个请求:
s = requests.Session()
r = s.get('https://httpbin.org/cookies', cookies={'from-my': 'browser'})
print(r.text)
# '{"cookies": {"from-my": "browser"}}'
r = s.get('https://httpbin.org/cookies')
print(r.text)
# '{"cookies": {}}'
如果要手动将 Cookie 添加到会话中,请使用 Cookie 实用程序函数来操作 。
会话也可以用作上下文管理器:
with requests.Session() as s:
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
这将确保会话在块一关闭就关闭已退出,即使发生了未处理的异常。with
从 dict 参数中删除值
有时,我们会希望从 dict 参数中省略会话级键。自 执行此操作时,只需在方法级别中将该键的值设置为参数。它将被自动省略。None
每当给朋友打电话时,我们都在做两个重大事项。首先,你正在构造一个对象,这个对象将是发送到服务器以请求或查询某些资源。其次,一旦 Requests 从服务器获得响应,就会生成一个对象。 该对象包含服务器返回的所有信息,以及还包含最初创建的对象。这是一个简单的请求从维基百科的服务器获取一些非常重要的信息:requests.get() Request Response Response Request
r = requests.get('https://en.wikipedia.org/wiki/Monty_Python')
如果我们想访问服务器发回给我们的标头,我们这样做:
r.headers
{'content-length': '56170', 'x-content-type-options': 'nosniff', 'x-cache':
'HIT from cp1006.eqiad.wmnet, MISS from cp1010.eqiad.wmnet', 'content-encoding':
'gzip', 'age': '3080', 'content-language': 'en', 'vary': 'Accept-Encoding,Cookie',
'server': 'Apache', 'last-modified': 'Wed, 13 Jun 2012 01:33:50 GMT',
'connection': 'close', 'cache-control': 'private, s-maxage=0, max-age=0,
must-revalidate', 'date': 'Thu, 14 Jun 2012 12:59:39 GMT', 'content-type':
'text/html; charset=UTF-8', 'x-cache-lookup': 'HIT from cp1006.eqiad.wmnet:3128,
MISS from cp1010.eqiad.wmnet:80'}
但是,如果我们想获取我们发送给服务器的标头,我们只需访问 request,然后是请求的标头:
r.request.headers
{'Accept-Encoding': 'identity, deflate, compress, gzip',
'Accept': '*/*', 'User-Agent': 'python-requests/1.2.0'}
每当我们收到一个对象时 从 API 调用或 Session 调用中,该属性实际上是所使用的属性。在某些情况下,可能希望做一些额外的事情在发送请求。简单的方法如下:request Prepared Request
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)
由于没有对对象执行任何特殊操作,因此立即准备并修改对象。然后将和其他参数一起发送。RequestPreparedRequestrequests.Session.
但是,上述代码将失去具有Requests 对象的一些优点。具体而言,-level 状态(如 cookie)将 不会应用于的请求。要获得该状态应用时,将 to 的调用替换为 的调用,如下所示:
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)
当使用准备好的请求流时,请记住,它不会考虑环境。 如果使用环境变量来更改请求的行为,这可能会导致问题。 例如:中指定的自签名SSL证书将不予考虑。 结果被抛出。 可以通过将环境设置显式合并到会话中来绕过此行为:REQUESTS_CA_BUNDLESSL: CERTIFICATE_VERIFY_FAILED
from requests import Request, Session
s = Session()
req = Request('GET', url)
prepped = s.prepare_request(req)
# Merge environment settings into session
settings = s.merge_environment_settings(prepped.url, {}, None, None, None)
resp = s.send(prepped, **settings)
print(resp.status_code)
Requests 验证 HTTPS 请求的 SSL 证书,就像 Web 浏览器一样。 默认情况下,SSL 验证处于启用状态,如果出现以下情况,Requests 将抛出 SSLError 无法验证证书:
requests.get('https://requestb.in')
requests.exceptions.SSLError: hostname 'requestb.in' doesn't match either of '*.herokuapp.com', 'herokuapp.com'
我没有在此域上设置SSL,因此会引发异常。非常好。不过,GitHub 会这样做:
requests.get('https://github.com')
<Response [200]>
可以将路径传递到具有受信任 CA 证书的 CA_BUNDLE 文件或目录:verify
requests.get('https://github.com', verify='/path/to/certfile')
或持久性:
s = requests.Session()
s.verify = '/path/to/certfile'
注意
如果设置为目录的路径,则必须已使用以下方法处理该目录 随 OpenSSL 提供的实用程序。verifyc_rehash
也可以通过环境变量指定此受信任 CA 列表。 如果未设置,将用作回退。REQUESTS_CA_BUNDLEREQUESTS_CA_BUNDLECURL_CA_BUNDLE
如果设置为 False,则请求也可以忽略验证 SSL 证书:verify
requests.get('https://kennethreitz.org', verify=False)
<Response [200]>
请注意,当设置为 时,请求将接受任何 TLS 服务器提供的证书,并将忽略主机名不匹配 和/或过期的证书,这将导致应用程序容易受到攻击 中间人 (MitM) 攻击。将 verify 设置为可能有用在本地开发或测试期间。verifyFalseFalse
默认情况下,设置为 True。该选项仅适用于主机证书。verifyverify
可以指定一个本地证书作为单个证书用作客户端证书文件(包含私钥和证书)或两者的元组文件的路径:
requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key'))
<Response [200]>
或持久性:
s = requests.Session()
s.cert = '/path/client.cert'
如果指定了错误的路径或无效的证书,则会收到 SSLError:
requests.get('https://kennethreitz.org', cert='/wrong_path/client.pem')
SSLError: [Errno 336265225] _ssl.c:347: error:140B0009:SSL routines:SSL_CTX_use_PrivateKey_file:PEM lib
警告
本地证书的私钥必须是未加密的。 目前,Requests 不支持使用加密密钥。
Requests 使用包 certifi 中的证书。这允许用户在不更改请求版本的情况下更新其受信任的证书。
在版本 2.16 之前,Requests 捆绑了一组它信任的根 CA, 来源于Mozilla信托商店。证书仅更新了每个请求版本一次。当未安装时,这导致了使用明显较旧的证书捆绑包时,证书捆绑包非常过时请求的版本。certifi
为了安全起见,我们建议经常升级 certifi!
默认情况下,当发出请求时,将下载响应的正文马上。可以覆盖此行为并延迟下载响应 body,直到使用参数访问该属性:stream
tarball_url = 'https://github.com/psf/requests/tarball/main'
r = requests.get(tarball_url, stream=True)
此时,仅下载了响应标头和连接保持打开状态,因此允许我们将内容检索设置为有条件的:
if int(r.headers['content-length']) < TOO_LONG:
content = r.content
可以使用和方法进一步控制工作流。 或者,可以从底层读取未解码的正文 urllib3 。
如果在发出请求时设置为,则“请求”不能 将连接释放回池,除非消耗了所有数据或调用 。这可能导致连接效率低下。如果发现自己部分阅读请求 使用时正文(或根本不阅读它们),应该在语句中发出请求,以确保它始终处于关闭状态:streamTruestream=Truewith
with requests.get('https://httpbin.org/get', stream=True) as r:
# Do things with the response here.
好消息 — 多亏了 urllib3,在一个会话中 keep-alive 是 100% 自动的! 在会话中提出的任何请求都将自动重用适当的 连接!
请注意,只有在所有正文全部发生时,连接才会释放回池以供重复使用数据已被读取;请确保设置或读取对象的属性。streamFalsecontentResponse
Requests 支持流式上传,允许发送大型流或文件,而不将它们读入内存。要流式传输和上传,只需提供一个 你身体的类似文件的物体:
with open('massive-body', 'rb') as f:
requests.post('http://some.url/streamed', data=f)
警告
强烈建议以二进制文件打开文件模式。这是因为请求可能会尝试提供的标头,以及它是否执行此值 将设置为文件中的字节数。可能会出现错误如果以文本模式打开文件。Content-Length
Requests 还支持对传出和传入请求进行分块传输编码。要发送块编码的请求,只需提供一个生成器(或任何没有的迭代器一个长度)对于你的身体:
def gen():
yield 'hi'
yield 'there'
requests.post('http://some.url/chunked', data=gen())
对于分块编码响应,最好使用 循环访问数据。在将在请求中设置的理想情况,其中在这种情况下,您可以通过使用参数进行调用来逐块迭代。如果要设置块的最大大小, 可以将参数设置为任何整数。stream=Trueiter_contentchunk_sizeNonechunk_size
可以在一个请求中发送多个文件。例如,假设想要将图像文件上传到具有多个文件字段“images”的 HTML 表单:
<input type="file" name="images" multiple="true" required="true"/>
为此,只需将文件设置为以下元组的列表:(form_field_name, file_info)
url = 'https://httpbin.org/post'
multiple_files = [
('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
r = requests.post(url, files=multiple_files)
r.text
{
...
'files': {'images': 'data:image/png;base64,iVBORw ....'}
'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a',
...
}
警告
强烈建议以二进制文件打开文件 模式。这是因为请求可能会尝试提供的标头,以及它是否执行此值将设置为文件中的字节数。可能会出现错误 如果以文本模式打开文件。Content-Length