高级用法

自定义池行为

这个 PoolManager 类自动处理创建 ConnectionPool 根据需要为每个主机提供实例。默认情况下,最多保留10个 ConnectionPool 实例。如果您向许多不同的主机发出请求,则增加此数目可能会提高性能:

>>> import urllib3
>>> http = urllib3.PoolManager(num_pools=50)

但是,请记住,这确实会增加内存和套接字消耗。

同样, ConnectionPool 班级里有一大群人 HTTPConnection 实例。这些连接在单个请求期间使用,并在请求完成时返回池。默认情况下,将只保存一个连接以供重用。如果同时向同一主机发出多个请求,则增加此数目可能会提高性能:

>>> import urllib3
>>> http = urllib3.PoolManager(maxsize=10)
# Alternatively
>>> http = urllib3.HTTPConnectionPool('google.com', maxsize=10)

池的行为 ConnectionPool 不同于 PoolManager . 默认情况下,如果发出新请求,并且池中没有可用连接,则将创建新连接。但是,如果超过 maxsize 存在连接。这意味着 maxsize 不确定可以向特定主机打开的连接的最大数量,只是池中保持的最大连接数。但是,如果您指定 block=True 那么最多可以有 maxsize 打开到特定主机的连接:

>>> http = urllib3.PoolManager(maxsize=10, block=True)
# Alternatively
>>> http = urllib3.HTTPConnectionPool('google.com', maxsize=10, block=True)

任何新请求都将被阻止,直到池中有可用的连接。这是防止多线程应用程序中连接过多的主机泛滥的好方法。

流媒体和I/O

在处理大型响应时,通常最好流式处理响应内容:

>>> import urllib3
>>> http = urllib3.PoolManager()
>>> r = http.request(
...     'GET',
...     'http://httpbin.org/bytes/1024',
...     preload_content=False)
>>> for chunk in r.stream(32):
...     print(chunk)
b'...'
b'...'
...
>>> r.release_conn()

设置 preload_contentFalse 意味着urllib3将流式传输响应内容。 stream() 允许您在响应内容的块上迭代。

注解

使用时 preload_content=False ,你应该打电话 release_conn() 将HTTP连接释放回连接池,以便可以重新使用它。

但是,你也可以治疗 HTTPResponse 实例作为类文件对象。这允许您进行缓冲:

>>> r = http.request(
...     'GET',
...     'http://httpbin.org/bytes/1024',
...     preload_content=False)
>>> r.read(4)
b'\x88\x1f\x8b\xe5'

呼叫 read() 将阻塞,直到有更多响应数据可用。

>>> import io
>>> reader = io.BufferedReader(r, 8)
>>> reader.read(4)
>>> r.release_conn()

您可以使用像文件这样的对象做一些事情,比如使用内容解码内容。 codecs ::

>>> import codecs
>>> reader = codecs.getreader('utf-8')
>>> r = http.request(
...     'GET',
...     'http://httpbin.org/ip',
...     preload_content=False)
>>> json.load(reader(r))
{'origin': '127.0.0.1'}
>>> r.release_conn()

代理人

你可以使用 ProxyManager 要通过http代理来隧道请求,请执行以下操作:

>>> import urllib3
>>> proxy = urllib3.ProxyManager('http://localhost:3128/')
>>> proxy.request('GET', 'http://google.com/')

用法 ProxyManager 是一样的 PoolManager .

您可以使用HTTP、HTTPS或SOCKS连接到代理。urllib3的行为将根据您选择的代理类型和您正在联系的目标而有所不同。

当通过HTTP或HTTPS代理联系HTTP网站时,请求将与 absolute URI .

当通过HTTP代理与HTTPS网站联系时,将使用HTTP连接建立TCP隧道。之后,将与目的地建立TLS连接,并发送您的请求。

目前不支持通过HTTPS代理与网站联系。

对于袜子,你可以用 SOCKSProxyManager 连接到socks4或socks5代理。为了使用socks代理,您需要安装 PySocks 或者使用 socks 额外::

pip install urllib3[socks]

一旦安装了PySocks,您就可以使用 SOCKSProxyManager ::

>>> from urllib3.contrib.socks import SOCKSProxyManager
>>> proxy = SOCKSProxyManager('socks5://localhost:8889/')
>>> proxy.request('GET', 'http://google.com/')

自定义TLS证书

而不是使用 certifi 您可以提供自己的证书授权包。这对于生成自己的证书或使用私有证书颁发机构的情况非常有用。只需在创建 PoolManager ::

>>> import urllib3
>>> http = urllib3.PoolManager(
...     cert_reqs='CERT_REQUIRED',
...     ca_certs='/path/to/your/certificate_bundle')

当您指定自己的证书包时,只有用该包验证的请求才会成功。建议使用单独的 PoolManager 向不需要自定义证书的URL发出请求。

自定义SNI主机名

如果您想通过使用SNI的HTTPS创建到主机的连接,有两个位置需要主机名。它必须包含在发送的主机头中,以便服务器知道请求的主机是哪个。主机名还应与服务器提供的证书匹配,该证书由urllib3检查。

通常,当您通过名称连接到主机时,urllib3负责为您设置和检查这些值。但是,有时设置连接的预期主机头和证书主机名(subject)很有用,尤其是在未使用名称解析进行连接时。例如,您可以使用HTTPS通过IP连接到服务器,如下所示:

>>> import urllib3
>>> pool = urllib3.HTTPSConnectionPool(
...     "10.0.0.10",
...     assert_hostname="example.org",
...     server_hostname="example.org"
... )
>>> pool.urlopen(
...     "GET",
...     "/",
...     headers={"Host": "example.org"},
...     assert_same_host=False
... )

请注意,以这种方式使用连接时,必须指定 assert_same_host=False .

当的DNS解析 example.org 与您要使用的地址不匹配。IP可能用于专用接口,或者您可能希望在循环DNS下使用特定主机。

客户端证书

还可以指定客户端证书。当服务器和客户端都需要验证彼此的身份时,这非常有用。通常,这些证书是从同一个机构颁发的。要使用客户端证书,请在创建 PoolManager ::

>>> http = urllib3.PoolManager(
...     cert_file='/path/to/your/client_cert.pem',
...     cert_reqs='CERT_REQUIRED',
...     ca_certs='/path/to/your/certificate_bundle')

如果您有加密的客户端证书私钥,则可以使用 key_password 参数指定用于解密密钥的密码。::

>>> http = urllib3.PoolManager(
...     cert_file='/path/to/your/client_cert.pem',
...     cert_reqs='CERT_REQUIRED',
...     key_file='/path/to/your/client.key',
...     key_password='keyfile_password')

如果你的密钥没有加密 key_password 参数不是必需的。

证书验证和macOS

苹果提供的python和openssl库包含一个补丁,使它们能够自动检查系统密钥链的证书。如果指定自定义证书并看到请求意外成功,这可能会令人惊讶。例如,如果您指定自己的证书进行验证,而服务器提供的是不同的证书,则连接可能会失败。但是,如果该服务器提供系统密钥链中的证书,则连接将成功。

This article 有更深入的分析和解释。

TLS警告

urllib3将根据证书验证支持的级别发出几个不同的警告。这些警告指示特定的情况,并且可以以不同的方式解决。

  • InsecureRequestWarning

    当对未启用证书验证的https url发出请求时,会发生这种情况。跟随 certificate verification 解决此警告的指南。

  • InsecurePlatformWarning

    这发生在Python2平台上,该平台有一个过时的 ssl 模块。这些老年人 ssl 模块可能会导致一些不安全的请求成功,在它们应该失败的情况下,以及安全的请求失败时,他们应该成功。跟随 pyOpenSSL 解决此警告的指南。

  • SNIMissingWarning

    这发生在2.7.9之前的Python2版本上。这些旧版本缺少 SNI 支持。这可能导致服务器呈现客户端认为无效的证书。跟随 pyOpenSSL 解决此警告的指南。

发出未验证的https请求是 强烈地 然而,如果你理解这些风险并希望禁用这些警告,你可以使用。 disable_warnings()

>>> import urllib3
>>> urllib3.disable_warnings()

或者,您可以用标准捕获警告。 logging 模块:

>>> logging.captureWarnings(True)

最后,可以通过设置 PYTHONWARNINGS 环境变量或使用 -W flag .

谷歌应用引擎

urllib3支持 Google App Engine 还有一些警告。

如果你在使用 Flexible environment ,您不必进行任何配置-urllib3将只起作用。但是,如果您使用 Standard environment 那你要么用 urllib3.contrib.appengineAppEngineManager 或者使用 Sockets API

使用 AppEngineManager

>>> from urllib3.contrib.appengine import AppEngineManager
>>> http = AppEngineManager()
>>> http.request('GET', 'https://google.com/')

要使用Sockets API,请将以下内容添加到app.yaml并使用 PoolManager 像往常一样:

env_variables:
    GAE_USE_SOCKETS_HTTPLIB : 'true'

有关限制和问题的详细信息,请参阅 urllib3.contrib.appengine .

Brotli编码

brotli是由google创建的一种压缩算法,它比gzip和deflate具有更好的压缩性能,如果 brotlipy 已安装程序包。您也可以通过 urllib3[brotli] 额外费用:

$ python -m pip install urllib3[brotli]

下面是一个通过 Accept-Encoding 标题:

>>> from urllib3 import PoolManager
>>> http = PoolManager()
>>> http.request('GET', 'https://www.google.com/', headers={'Accept-Encoding': 'br'})

用Wireshark解密捕获的TLS会话

Python3.8及更高版本支持TLS预主密钥的日志记录。用这些秘密工具 Wireshark 可以解密捕获的网络流量。

要启用此功能,只需定义环境变量 SSLKEYLOGFILE

export SSLKEYLOGFILE=/path/to/keylogfile.txt

然后在中配置密钥日志文件 WiresharkWireshark TLS Decryption 以获取指示。