怎么使用Python的Requests库

寻技术 Python编程 2023年08月06日 73

本文小编为大家详细介绍“怎么使用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
不支持此功能,但有一个单独的包支持此功能&mdash;&mdash;
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
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]>]

请求超时

可以使用

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
n
object. In particular,
Sessio
n
-level state such as cookies will not get applied to your request. To get a
PreparedRequest
with 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_BUNDLE
will not be taken into account. As a result an
SSL: CERTIFICATE_VERIFY_FAILED
is thrown. You can get around this behaviour by explicitly merging the environment settings into your session:

当你使用prepared request请求时,请记住它没有考虑环境。如果你正使用环境变量来更改请求的行为,这可能会导致问题。例如:在

REQUESTS_CA_BUNDLE
中指定的自签名SSL证书将不起作用,结果引发了
SSL:CERT						
						
						
						
						
						
						
					
关闭

用微信“扫一扫”