发起请求
首先,要加载rullib3模块:
>>> 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'})
响应内容
HTTPResponse
对象提供了 status、data、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'
注意:
对一个稍大的响应,有时将响应数据流式化(stream)更好。
请求数据
请求头(Headers)
可以在request() 方法的 headers
参数中使用一个字典指定请求头:
>>> r = http.request(
... 'GET',
... 'http://httpbin.org/headers',
... headers={
... 'X-Something': 'value'
... })
>>> json.loads(r.data.decode('utf-8'))['headers']
{'X-Something': 'value', ...}
查询参数
对于GET
、HEAD
和DELETE
请求,可以通过在fields
参数中使用一个字典来简单的传递参数:
>>> r = http.request(
... 'GET',
... 'http://httpbin.org/get',
... fields={'arg': 'value'})
>>> json.loads(r.data.decode('utf-8'))['args']
{'arg': 'value'}
对于POST
、PUT
请求,需要手动在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'}
表格数据
对于POST
、PUT
请求,urllib3将把在为request() 提供的fields
参数中的字典自动的表格化编码。
>>> r = http.request(
... 'POST',
... 'http://httpbin.org/post',
... fields={'field': 'value'})
>>> json.loads(r.data.decode('utf-8'))['form']
{'field': 'value'}
JSON
在调用request() 方法时,在指定编码后的数据作为body
参数,并设置Content-Type
请求头,可以发送一个JSON格式的请求。
>>> 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
编码上传文件,可以使用与表格数据相同的方法,使用一个(文件名, 文件数据)的元组来定义文件字段:
>>> 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请求。
为了能够验证需要设置根证书。最简单可靠的方法时使用certifi包,它提供Mozilla的根证书捆绑。
pip install certifi
也可以使用urllib3的secure扩展来安装certifi:
pip install urllib3[secure]
警告:
如果使用python2,将需要额外的包。之后会详述。
一旦有了证书之后,可以创建一个 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 ...
在python2中验证证书
老版本的Python2使用一个缺乏SNI support支持并且安全更新延迟落后的SSL构建的。因此它推荐使用pyOpenSSL。
如果使用urllib3的secure扩展来安装,所有在python2中验证证书需要的包都将被安装:
pip install urllib3[secure]
如果想要手动安装包,需要安装pyOpenSSL
, cryptography
, idna
, and certifi
.
一旦安装,就可以告诉urllib3使用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())
使用超时
超时允许你控制请求在被放弃之前允许运行多久。简单的说,你能对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))
在request() 指定timeout
将覆盖池级别的超时。
重试请求
urllib3 能自动重试幂等请求。同样的机制也处理重定向。能使用request() 方法中的retries
参数控制重试。默认的,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))
你还可以在request()
方法指定retries
覆盖池级别的重试策略。
错误和异常
urllib3 包装低级异常, 例如:
>>> try:
... http.request('GET', 'nx.example.com', retries=False)
>>> except urllib3.exceptions.NewConnectionError:
... print('Connection failed.')
参见 exceptions
查看全部异常的列表。
日志
如果你使用标准库 logging
模块,urllib3将会发出几个日志.在某些情况下,这是不可取的. 你可以使用标准的logger接口来更改urllib3日志记录器的日志级别:
>>> logging.getLogger("urllib3").setLevel(logging.WARNING)