最佳 Python HTTP 客户端用于网络抓取:实用比较
Senior Web Scraping Engineer
TL;DR:
- Requests 适合直接的同步作业。 当工作流程需要持久的配置和连接重用时,请使用会话。
- HTTPX 支持同步和异步应用程序。 其配对的客户端接口可以减少两种风格之间的概念差距。
- aiohttp 适合已经围绕 asyncio 构建的应用程序。 有意地重用客户端会话并绑定并发工作。
- urllib3 暴露了更底层的传输控制。 当池行为是应用程序设计的一部分时,它非常有用。
- HTTP 客户端不会执行页面 JavaScript。 当响应中缺少所需内容时,请使用渲染或管理访问服务。
介绍:将客户端匹配到应用程序
Python HTTP 客户端发送请求并暴露响应。应用程序决定要获取什么、返回的内容是否有用,以及如何将其转换为记录。
这种划分解释了为什么用异步库替换同步库并不会自动修复抓取工作。该工作可能在等待目标、解析大型文档或接收需要 JavaScript 的页面。每个问题都需要不同的干预措施。
本比较涵盖 Requests、HTTPX、aiohttp 和 urllib3 作为客户端库。Scrapeless Web Unlocker 稍后将作为这些库可以调用的服务出现。它不是一个 Python HTTP 库。对于需要浏览器交互和文件处理的相关工作流程,下载文件工作流 展示了不同的执行层。
Python HTTP 客户端概览
选择与其周围代码的执行模型匹配的客户端。该表比较的是接口,而不是基准结果。
| 客户端 | 主要应用风格 | 可重用对象 | 良好的起点 |
|---|---|---|---|
| Requests | 同步 | Session |
小脚本和已建立的同步服务 |
| HTTPX | 同步或异步 | Client / AsyncClient |
需要两种风格的应用程序 |
| aiohttp | 异步 | ClientSession |
现有的 asyncio 工作流程 |
| urllib3 | 更底层的同步传输 | PoolManager |
显式的连接池集成 |
这些库都不会将响应主体变成渲染的浏览器页面。它们可以检索 HTML、JSON 和其他表示;一个解析器或浏览器执行下一个阶段。
连接池实际改变了什么
连接池允许兼容的请求重用现有连接,而不是从头建立每个连接。重用可以减少设置工作,但其好处取决于目标、请求模式和服务器行为。
长期存在的客户端对象还为应用程序提供了一个共享设置和 Cookie 的地方。将该对象的作用域限制在预期的工作或服务生命周期。为每个 URL 创建一个新客户端会丢弃使用池的大部分理由。
HTTP 状态和内容验证仍然是分开的。HTTP 表示模型 描述了响应所表示的内容;抓取器仍然必须检查表示是否包含所需的数据。
Requests:从可读的同步代码开始
当顺序代码适合工作负载并且团队重视熟悉的请求-响应流程时,Requests 是一个实用的选择。它的会话接口使连接重用和持久设置可以访问,而无需引入事件循环。
超时是必不可少的。如果没有明确的界限,暂停的操作可能会占用工作者比工作期望的时间更长。成功的状态检查应随后验证响应内容,而不是立即假设提取成功。
同步执行并非天生不适合生产。一个小的批准集工作可能比作为并发系统操作顺序请求更容易。在更改应用程序模型之前,测量实际瓶颈。
HTTPX:保持同步和异步接口相关
HTTPX 提供同步和异步客户端,这在代码库具有不同执行环境时非常有用。请求选项和响应检查等共享概念使迁移变得更容易,尽管异步调用站点仍需要对客户端生命周期进行仔细管理。
HTTPX 还提供可选的 HTTP/2 支持。HTTPX HTTP/2 配置 需要明确的设置;仅选择该库并不意味着每个连接都协商该协议。
不要假设每个设置在库之间具有相同的含义。在替换现有客户端之前,比较重定向行为、超时阶段、代理配置和异常类型。
aiohttp:使用共享的异步会话
Aiohttp 提供了一个围绕 asyncio 构建的异步客户端。它适合已经调度其他异步 I/O 的服务,并且需要 HTTP 请求参与该模型。
重用 ClientSession 并设置预期操作的总超时。在应用程序级别绑定工作,以便程序不会创建无限制的任务集。较大的任务队列并不意味着可以从目标中收集更多权限。
异步执行在应用程序等待 I/O 时改善了调度机会。它并不能使 HTML 解析变得免费,去除服务器限制,或保证较低的端到端延迟。在评估客户端时,保持这些声明分开。
urllib3: 慎重选择直接池控件
Urllib3 在较低层级公开了连接池和传输配置。当应用程序或库需要直接管理这些细节而不是通过更高层的便利接口时,它非常有用。
额外的控制带来了对响应处理的更多责任。决定字节如何变成文本,何时消耗内容,以及如何释放池资源。应为具体需求选择较低层的 API,而不是因为假设较少的抽象会更快。
用 Scrapeless 开始抓取
使用 Scrapeless 强化您的网页抓取和自动化工作流程!
今天注册并获得 $5 的免费信用 — 无需信用卡。立即在 Scrapeless Dashboard 领取您的免费信用。
用每个客户端运行相同的内容检查
公平的功能比较检索相同的源并检查相同的内容标记。下面的脚本对每个客户端请求一次公共协议文档,然后报告预期主题是否存在。这是一个功能检查,而不是速度排名。
先决条件和安装
使用支持的 Python 环境并安装以下版本。该示例需要出站的 HTTPS 访问,但不需要 Scrapeless 凭据。后续的 Web Unlocker 请求单独需要一个有效的 Scrapeless API 密钥,并且在没有密钥的情况下仍处于待审核状态。
将软件包安装到虚拟环境中:
bash
python3 -m pip install requests==2.32.5 httpx==0.28.1 aiohttp==3.13.5 urllib3==2.6.3
将其保存为 compare_clients.py,然后用 Python 运行。请求是故意按顺序进行的,包括异步客户端示例,因此脚本并不表示并发基准。
python
import asyncio
import json
import ssl
import certifi
import requests
import httpx
import aiohttp
import urllib3
URL = 'https://www.rfc-editor.org/rfc/rfc9114.html'
MARKER = 'HTTP/3'
HEADERS = {'User-Agent': 'ContentComparison/1.0'}
def report(name, status, body):
text = body.decode('utf-8')
if status != 200 or MARKER not in text:
raise ValueError(f'{name}: expected document missing')
print(json.dumps({'client': name, 'status': status,
'bytes': len(body), 'topic_present': True}))
with requests.Session() as client:
response = client.get(URL, headers=HEADERS, timeout=30)
response.raise_for_status()
report('requests', response.status_code, response.content)
with httpx.Client(timeout=30, follow_redirects=True) as client:
response = client.get(URL, headers=HEADERS)
response.raise_for_status()
report('httpx', response.status_code, response.content)
pool = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',
ca_certs=certifi.where())
try:
response = pool.request('GET', URL, headers=HEADERS,
timeout=urllib3.Timeout(total=30))
report('urllib3', response.status, response.data)
finally:
pool.clear()
async def run_async():
context = ssl.create_default_context(cafile=certifi.where())
connector = aiohttp.TCPConnector(ssl=context)
async with aiohttp.ClientSession(
connector=connector, timeout=aiohttp.ClientTimeout(total=30)
) as client:
async with client.get(URL, headers=HEADERS) as response:
response.raise_for_status()
report('aiohttp', response.status, await response.read())
asyncio.run(run_async())
该脚本检查实际的响应主体并保持 TLS 证书验证。字节计数可能会在上游文档更改时变化。成功的标记检查确认了这个有限的检索任务;它并不建立其他网站的提取质量。
在比较速度之前比较工作负载
有用的性能实验保持目标集、并发限制、超时策略和接受检查不变。报告完成的有用记录、经过的时间和资源使用。包括失败,而不是从样本中删除它们。
从小的允许工作负载开始。在引入有限并行性之前,测量顺序执行。对于异步应用程序,还要检查解析和存储上花费的时间;事件循环中的阻塞 CPU 工作可能会掩盖异步网络的好处。
读取结构化响应时保持类型。当处理 JSON 值类型 时,区分字符串、数字和空值。将缺失的价格转换为零会改变记录的含义,无论是哪个客户端获取的。
HTTP 客户端的终止:托管页面访问
HTTP 客户端在响应表示处停止;它不执行页面的脚本,也不自动将挑战转化为预期内容。首先检查返回的 HTML 中是否存在目标数据。HTML 解析算法 从标记构建文档树,这与将页面作为浏览器运行是不同的。
Scrapeless Web Unlocker 提供了一个托管访问端点,Python 客户端可以调用。在该边界保持相同的响应验证规则。当前的 Web Unlocker 请求配置 记录了端点和输入合同;在需要时,渲染选项应从他们当前的文档中选择。
注意:以下服务请求需要
SCRAPELESS_API_KEY。经过身份验证的检索正在等待无该凭证的实时验证;这里没有返回的 HTML 或完成结果是虚构的。
python
import os
import requests
response = requests.post(
'https://api.scrapeless.com/api/v2/unlocker/request',
headers={'x-api-token': os.environ['SCRAPELESS_API_KEY']},
json={
'actor': 'unlocker.webunlocker',
'input': {'url': 'https://httpbin.io/get',
'method': 'GET', 'redirect': False},
'proxy': {'country': 'ANY'}
},
timeout=60
)
response.raise_for_status()
print(response.text)
此调用演示了文档化的服务边界,而不是 Python 客户端替代品或 JavaScript 渲染演示。在解析之前检查实际响应和应用程序状态。请单独查看 Scrapeless 定价 与客户端库:库安装和托管服务调用具有不同的成本模型。
结论:选择最简单的适合运行时的客户端
对于同步工作流程,请使用 Requests,当相关的同步和异步接口有帮助时使用 HTTPX,对于以 asyncio 为中心的应用程序使用 aiohttp,当需要直接池控制时使用 urllib3。在比较中保持内容检查稳定。只有当返回的表示无法满足任务时,才添加渲染或托管访问层。
准备构建您的网络数据工作流程吗?
加入开发人员讨论实际收集工作流程的讨论: Discord · Telegram。
在 app.scrapeless.com 创建一个帐户,并开始使用您可以验证输出的授权任务。
常见问题
问:初学者应该选择哪个 Python HTTP 客户端?
Requests 是一个简单的起点,适用于小型同步任务。设置超时,检查状态,并在添加更多基础设施之前验证主体。
问:HTTPX 是否总是比 Requests 更快?
没有普遍的速度排序来自于库的名称。连接重用、并发、目标行为和解析工作决定了观察到的结果。
问:aiohttp 能够渲染 JavaScript 吗?
Aiohttp 检索 HTTP 响应,而不运行浏览器渲染引擎。当所需数据由页面脚本生成时,请使用浏览器或适当的托管渲染服务。
问:更换客户端能解决访问被拒绝的页面吗?
更换客户端并不建立授权或保证访问。检查响应,确认允许的工作流程,并选择适当的访问路径,而不将挑战页面视为数据。
问:Scrapeless Web Unlocker 是一个 Python 库吗?
Web Unlocker 是一个托管服务,Python HTTP 客户端可以调用。客户端处理本地请求,而服务处理其文档化的远程访问工作。
在Scrapeless,我们仅访问公开可用的数据,并严格遵循适用的法律、法规和网站隐私政策。本博客中的内容仅供演示之用,不涉及任何非法或侵权活动。我们对使用本博客或第三方链接中的信息不做任何保证,并免除所有责任。在进行任何抓取活动之前,请咨询您的法律顾问,并审查目标网站的服务条款或获取必要的许可。



