前言
HTTPX 是新一代的 python 解析库,它是一个功能齐全的 HTTP 客户端,用于Python 3,较requests(只能发送同步请求)和 aiohttp(只能发送异步请求)不同的是,它同时提供同步和异步 API,有些网站强制使用 HTTP / 2.0 协议访问,urllib 和 requests 是无法爬取数据的,它们只支持 HTTP / 1.1,而 HTTPX 则全部支持。
例如 HTTPX 官网(F12 打开开发人员工具界面 → 选择网络【Network】 → 右键点击名称选中协议【Protocol】即可查看网站支持的协议类型,h2 即为 HTTP / 2.0 协议):
官方文档:https://www.python-httpx.org/
Github:https://github.com/encode/httpx/
HTTPX 的特点
- 广泛兼容请求的 API
- 标准同步接口,可提供异步支持
- HTTP/1.1 和 HTTP / 2.0 支持
- 能够直接向 WSGI 应用程序或 ASGI 应用程序发出请求。
- 无处不在的严格超时
- 完全键入批注
- 100% 测试覆盖率
- 国际域和网址
- Keep-Alive & Connection Pooling
- 具有 Cookie 持久性的会话
- 浏览器样式的 SSL 验证
- 基本/摘要式身份验证
- 优雅的键/值 Cookie
- 自动减压
- 自动内容解码
- 统一码响应正文
- 分段文件上传
- 代理支持
- 连接超时
- 流媒体下载
- .netrc 支持
- 分块请求
HTTPX 的安装
HTTPX 所需版本为 Python 3.6 及以上,可通过以下命令安装:
pip3 install httpx
但是如果想让 HTTPX 支持 HTTP / 2.0 的话,用如下命令安装:
pip3 install httpx[http2]
以下即为成功:
HTTPX 之 Client 对象
在了解 httpx 如何使用前,先了解一下 httpx 的 Client 对象,httpx.Client() 相当于 requests.Session 的替代,相较于 httpx 的其他 API 方法,Client 能更有效地利用网络资源,Client 使用 http 连接池,这意味着,当向同一主机发出多个请求时,将重用底层 TCP 连接,而不是为每个请求重新创建一个新的连接,能显著的改善性能:
- 减少了跨请求的延迟(无需握手)
- 减少 CPU 使用率和往返次数
- 减少网络拥塞
Client 的基本使用
方法一:作为上下文管理器,较推荐方式
import httpx
with httpx.Client() as client:
response = client.get('https://httpbin.org/get')
print(response)
# <Response [200 OK]>
方法二:显示关闭连接池
import httpx
client = httpx.Client()
try:
response = client.get('https://httpbin.org/get')
print(response)
finally:
client.close()
# <Response [200 OK]>
发送自定义请求头信息:
import httpx
with httpx.Client() as client:
headers = {'X-Custom': 'value'}
r = client.get('https://example.com', headers=headers)
print(r.request.headers['X-Custom'])
# value
Client 可以通过将参数传递给构造函数来将配置应用于所有传出请求 :
import httpx
url = 'http://httpbin.org/headers'
headers = {'user-agent': 'my-app/0.0.1'}
with httpx.Client(headers=headers) as client:
r = client.get(url)
print(r.json()['headers']['User-Agent'])
# my-app/0.0.1
更多详细用法可参考 Client 官方文档:https://www.python-httpx.org/advanced/
HTTPX 的使用
发送同步请求
httpx 和 requests 的基本使用有很多相似之处,例如进行 GET 请求:
import httpx
response = httpx.get('https://httpbin.org/get')
print(response.status_code)
print(response.headers)
print(response.text)
print(response.url)
print(response.cookies)
print(response.history)
- status_code:状态码
- headers:响应头
- text:响应体
- url:网页链接 URL
- cookies:获取 Cookie 信息
- history:请求历史
如图所示:"User-Agent": "python-httpx/0.22.0" ,即为使用 httpx 发送请求:
如下直接使用 httpx 访问 HTTP/2.0 的网站会出现报错:
import httpx
url = 'https://spa16.scrape.center/'
response = httpx.get(url)
print(response.text)
报错信息:httpcore.ReadError: [WinError 10054] 远程主机强迫关闭了一个现有的连接。
原因: httpx 默认不开启对 HTTP/2.0 的支持,默认使用的是 HTTP/1.0 需要手动声明一下才能使用 HTTP/2.0 ,这里就要使用到上述所讲的 httpx 的 Client 对象:
import httpx
# 显示将 http2 设置为 True,开启对 HTTP/2.0 的支持
client = httpx.Client(http2=True)
url = 'https://spa16.scrape.center/'
response = client.get(url)
print(response.text)
print(response.http_version)
# HTTP/2
# 代表使用了 HTTP/2.0 协议传输
注意:在客户端的 httpx 上启用对 HTTP/2.0 的支持并不意味着请求和响应都将通过 HTTP/2.0 传输,这得客户端和服务端都支持 HTTP/2.0 才行,如果客户端连接到仅支持 HTTP/1.0 的服务器,那么它也需要改用 HTTP/1.0 。
发送异步请求
httpx 支持异步客户端请求,支持 Pyhton 的 async 请求模式,异步是一种并发模型,比多线程高效得多,可以提供显著的性能优势,并允许使用长期网络连接,如果使用的是异步 Web 框架,则还需要使用异步客户端发送传出 HTTP 请求,若要发送异步请求,需要使用到 httpx.AsyncClient() 方法:
官方文档给出的方式是:
import httpx
async with httpx.AsyncClient() as client:
r = await client.get('https://www.example.com/')
print(r.code)
但需要注意的是 async with xxx as xxx 这个结构需要放在 async def xxx( ) 函数内:
不然会报错:SyntaxError: 'async with' outside async function,显示语法错误
import httpx
import asyncio
async def main():
async with httpx.AsyncClient() as client:
response = await client.get('https://www.example.com/')
print(response.http_version)
# HTTP/1.1
asyncio.run(main())
使用 HTTP/2.0 即更改为 httpx.AsyncClient(http2=True)
更多详细用法可参考 Client 官方文档:异步支持 - HTTPX (python-httpx.org)
异步
为了完成某个任务,有时不同程序单元之间无需通信协调也能完成任务,此时不相关的程序单元之间可以是异步的,如爬取网页,调度程序调用下载程序后,即可调度其他任务,无需与该下载任务保持通信以协调行为,不同网页的下载、保存等操作都是无关的,也无须相互通知协调,这些异步操作完成的时刻不确定,所以异步也意味着无序执行。
总结
以上为对新一代功能强大的解析库 HTTPX 的相关知识的基本归纳总结,同时引出了相关的异步概念,后续会对异步爬虫进行具体项目分析,有任何建议欢迎评论区指正交流~