当前位置: 首页 > 工具软件 > urllib3 > 使用案例 >

Python爬虫--urllib3

黄彬
2023-12-01

首先,导入urllib3模块:

>>> import urllib3

您需要一个PoolManager实例来发出请求。此对象处理连接池和线程安全的所有详细信息,因此您不必:

>>> http = urllib3.PoolManager()

要发出请求,请使用request()

>>> r = http.request('GET', 'http://httpbin.org/robots.txt')
>>> r.data
b'User-agent: *\nDisallow: /deny\n'

request()返回一个HTTPResponse对象, 响应内容部分解释了如何处理各种响应。

您可以使用request()任何HTTP动词来发出请求:

>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={'hello': 'world'})

请求数据部分涵盖发送其他类型的请求的数据,包括JSON,文件和二进制数据。

响应内容

HTTPResponse对象提供 statusdata和 header属性:

>>> r = http.request('GET', 'http://httpbin.org/ip')
>>> r.status
200
>>> r.data
b'{\n  "origin": "104.232.115.37"\n}\n'
>>> r.headers
HTTPHeaderDict({'Content-Length': '33', ...})

JSON内容

可以通过解码和反序列data化请求的属性来加载JSON内容 :

>>> import json
>>> r = http.request('GET', 'http://httpbin.org/ip')
>>> json.loads(r.data.decode('utf-8'))
{'origin': '127.0.0.1'}

二进制内容

data响应的属性始终设置为表示响应内容的字节字符串:

>>> r = http.request('GET', 'http://httpbin.org/bytes/8')
>>> r.data
b'\xaa\xa5H?\x95\xe9\x9b\x11'

注意

对于更大的响应,有时更好地传输 响应。

请求数据

标题

您可以在headers参数中将标题指定为字典request()

>>> r = http.request(
...     'GET',
...     'http://httpbin.org/headers',
...     headers={
...         'X-Something': 'value'
...     })
>>> json.loads(r.data.decode('utf-8'))['headers']
{'X-Something': 'value', ...}

查询参数

对于GETHEADDELETE请求,您只需将参数作为参数中的字典传递fieldsrequest()

>>> r = http.request(
...     'GET',
...     'http://httpbin.org/get',
...     fields={'arg': 'value'})
>>> json.loads(r.data.decode('utf-8'))['args']
{'arg': 'value'}

对于POSTPUT请求,您需要在URL中手动编码查询参数:

>>> from urllib.parse import urlencode
>>> encoded_args = urlencode({'arg': 'value'})
>>> url = 'http://httpbin.org/post?' + encoded_args
>>> r = http.request('POST', url)
>>> json.loads(r.data.decode('utf-8'))['args']
{'arg': 'value'}

表格数据

对于PUTPOST请求,urllib3将自动对fields提供的参数中 的字典进行格式编码request()

>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={'field': 'value'})
>>> json.loads(r.data.decode('utf-8'))['form']
{'field': 'value'}

JSON 

您可以通过将编码数据指定为body 参数并Content-Type在调用时设置标头来 向JSON发送请求request()

>>> import json
>>> data = {'attribute': 'value'}
>>> encoded_data = json.dumps(data).encode('utf-8')
>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     body=encoded_data,
...     headers={'Content-Type': 'application/json'})
>>> json.loads(r.data.decode('utf-8'))['json']
{'attribute': 'value'}

文件和二进制数据

要使用multipart/form-data编码上载文件,您可以使用与表单数据相同的方法,并将文件字段指定为以下元组 :(file_name, file_data)

>>> with open('example.txt') as fp:
...     file_data = fp.read()
>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={
...         'filefield': ('example.txt', file_data),
...     })
>>> json.loads(r.data.decode('utf-8'))['files']
{'filefield': '...'}

虽然不严格要求指定文件名,但建议使用它来匹配浏览器行为。您还可以传递元组中的第三个项目以明确指定文件的MIME类型:

>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     fields={
...         'filefield': ('example.txt', file_data, 'text/plain'),
...     })

要发送原始二进制数据,只需指定body参数即可。还建议设置Content-Type标题:

>>> with open('example.jpg', 'rb') as fp:
...     binary_data = fp.read()
>>> r = http.request(
...     'POST',
...     'http://httpbin.org/post',
...     body=binary_data,
...     headers={'Content-Type': 'image/jpeg'})
>>> json.loads(r.data.decode('utf-8'))['data']
b'...'

证书验证

强烈建议始终使用SSL证书验证。 默认情况下,urllib3不验证HTTPS请求

为了启用验证,您需要一组根证书。最简单,最可靠的方法是使用提供Mozilla根证书包的certifi包:

pip install certifi

您还可以使用secure 额外的安装与urllib3一起安装certifi :

pip install urllib3[secure]

警告

如果您使用的是Python 2,则可能需要其他软件包。有关详细信息,请参阅以下部分

获得证书后,您可以创建PoolManager 在发出请求时验证证书的证书:

>>> import certifi
>>> import urllib3
>>> http = urllib3.PoolManager(
...     cert_reqs='CERT_REQUIRED',
...     ca_certs=certifi.where())

PoolManager会自动处理证书验证,并会提高SSLError,如果验证失败:

>>> http.request('GET', 'https://google.com')
(No exception)
>>> http.request('GET', 'https://expired.badssl.com')
urllib3.exceptions.SSLError ...

注意

如果需要,您可以使用OS提供的证书。只需指定证书包的完整路径作为ca_certs参数而不是 certifi.where()。例如,大多数Linux系统都存储证书/etc/ssl/certs/ca-certificates.crt。其他操作系统可能很难

Python 2中的证书验证

较旧版本的Python 2使用ssl缺少SNI支持的模块 构建,并且可能落后于安全更新。由于这些原因,建议使用 pyOpenSSL

如果你使用secure额外的安装urllib3,将安装Python 2上所有必需的证书验证包:

pip install urllib3[secure]

如果您想要手动安装的软件包,您需要pyOpenSSL, cryptographyidna,和certifi

注意

如果您不使用macOS或Windows,请注意加密需要额外的系统包进行编译。有关 所需软件包的列表,请参阅在Linux上构建加密

安装完成后,您可以通过以下方式告诉urllib3使用pyOpenSSL urllib3.contrib.pyopenssl

>>> import urllib3.contrib.pyopenssl
>>> urllib3.contrib.pyopenssl.inject_into_urllib3()

最后,您可以创建一个PoolManager在执行请求时验证证书:

>>> import certifi
>>> import urllib3
>>> http = urllib3.PoolManager(
...     cert_reqs='CERT_REQUIRED',
...     ca_certs=certifi.where())

如果你不想使用pyOpenSSL,你可以简单地省略对它的调用urllib3.contrib.pyopenssl.inject_into_urllib3()。urllib3将回退到标准库ssl模块。执行此操作时,您可能会遇到 几个警告

警告

如果您不使用pyOpenSSL,则必须使用ssl支持编译Python以使证书验证起作用。这种情况并不常见,但可以在没有SSL支持的情况下编译Python。有关 更多详细信息,请参阅此 Stackoverflow线程

如果您使用的是Google App Engine,则必须在以下位置明确启用SSL支持app.yaml

libraries:
- name: ssl
  version: latest

使用超时

超时允许您控制在中止之前允许运行的请求的时间。在简单的情况下,您可以将超时指定float 为request()

>>> http.request(
...     'GET', 'http://httpbin.org/delay/3', timeout=4.0)
<urllib3.response.HTTPResponse>
>>> http.request(
...     'GET', 'http://httpbin.org/delay/3', timeout=2.5)
MaxRetryError caused by ReadTimeoutError

要进行更精细的控制,您可以使用一个Timeout 实例,它允许您指定单独的连接和读取超时:

>>> http.request(
...     'GET',
...     'http://httpbin.org/delay/3',
...     timeout=urllib3.Timeout(connect=1.0))
<urllib3.response.HTTPResponse>
>>> http.request(
...     'GET',
...     'http://httpbin.org/delay/3',
...     timeout=urllib3.Timeout(connect=1.0, read=2.0))
MaxRetryError caused by ReadTimeoutError

如果您希望所有请求都受到相同的超时,您可以在PoolManager级别指定超时:

>>> http = urllib3.PoolManager(timeout=3.0)
>>> http = urllib3.PoolManager(
...     timeout=urllib3.Timeout(connect=1.0, read=2.0))

您仍然通过指定timeoutto来 覆盖此池级超时request()

重试请求

urllib3可以自动重试幂等请求。同样的机制也处理重定向。您可以使用retries参数to 控制重试次数request()。默认情况下,urllib3将重试请求3次,并最多跟进3次重定向。

要更改重试次数,只需指定一个整数:

>>> http.requests('GET', 'http://httpbin.org/ip', retries=10)

要禁用所有重试和重定向逻辑,请指定retries=False

>>> http.request(
...     'GET', 'http://nxdomain.example.com', retries=False)
NewConnectionError
>>> r = http.request(
...     'GET', 'http://httpbin.org/redirect/1', retries=False)
>>> r.status
302

要禁用重定向但保留重试逻辑,请指定redirect=False

>>> r = http.request(
...     'GET', 'http://httpbin.org/redirect/1', redirect=False)
>>> r.status
302

要获得更精细的控制,您可以使用Retry实例。此类允许您更好地控制请求的重试方式。

例如,要总共执行3次重试,但仅限于2次重定向:

>>> http.request(
...     'GET',
...     'http://httpbin.org/redirect/3',
...     retries=urllib3.Retry(3, redirect=2))
MaxRetryError

您还可以禁用太多重定向的异常,只返回 302响应:

>>> r = http.request(
...     'GET',
...     'http://httpbin.org/redirect/3',
...     retries=urllib3.Retry(
...         redirect=2, raise_on_redirect=False))
>>> r.status
302

如果您希望所有请求都遵循相同的重试策略,则可以在PoolManager级别指定重试:

>>> http = urllib3.PoolManager(retries=False)
>>> http = urllib3.PoolManager(
...     retries=urllib3.Retry(5, redirect=2))

您仍然通过指定retriesto来 覆盖此池级重试策略request()

错误和异常

urllib3包含较低级别的异常,例如:

>>> try:
...     http.request('GET', 'nx.example.com', retries=False)
>>> except urllib3.exceptions.NewConnectionError:
...     print('Connection failed.')

有关exceptions所有例外的完整列表,请参阅。

记录

如果您使用的是标准库logging模块,则urllib3会发出几个日志。在某些情况下,这可能是不可取的。您可以使用标准记录器界面更改urllib3记录器的日志级别:

>>> logging.getLogger("urllib3").setLevel(logging.WARNING)
 类似资料: