一、Python网络请求的"过去式":requests的时代
在Python网络编程的发展历程中,requests库无疑是一座里程碑。自2011年发布以来,它凭借简洁优雅的API设计,彻底改变了Python开发者处理HTTP请求的方式。在此之前,开发者依赖于Python内置的urllib、urllib2库,这些库的接口繁琐,需要编写大量代码才能完成简单的请求操作。而requests库则将HTTP请求简化为几行代码,让网络请求变得像调用普通函数一样轻松。
requests库的核心优势在于其"人性化"的设计。它支持所有常见的HTTP方法,如GET、POST、PUT、DELETE等,并且提供了直观的参数传递方式。例如,发送一个GET请求只需一行代码:
import requests
response = requests.get('https://api.example.com/data')
同时,requests库还内置了许多实用功能,如自动处理Cookie、支持会话保持、提供多种认证方式(Basic、Digest、OAuth等)、自动解码响应内容等。这些功能使得requests库成为了Python开发者的首选,几乎成为了网络请求的代名词。
然而,随着Python生态的发展,requests库的局限性也逐渐显现出来。它基于同步阻塞I/O模型,在处理高并发请求时性能瓶颈明显。当需要同时发送大量请求时,每个请求都会阻塞当前线程,导致程序效率低下。此外,requests库不支持异步编程,无法与现代Python异步框架(如asyncio、FastAPI)无缝集成。这些局限性使得开发者开始寻找更适合现代应用场景的网络请求库。
二、新时代的选择:httpx的崛起
httpx库诞生于2019年,它的出现填补了requests库在异步编程和现代HTTP协议支持方面的空白。作为新一代Python网络请求库,httpx不仅继承了requests库的简洁API,还增加了对异步编程的支持,同时兼容HTTP/1.1和HTTP/2协议。
(一)httpx的核心特性
同步与异步双支持:httpx提供了同步和异步两种API,开发者可以根据需求灵活选择。同步API与requests库高度兼容,几乎可以无缝迁移;异步API则基于asyncio和Trio框架,支持高并发请求,能够显著提升程序性能。
HTTP/2协议支持:httpx原生支持HTTP/2协议,相比HTTP/1.1,HTTP/2具有多路复用、头部压缩、服务器推送等特性,能够大幅提高请求效率,减少网络延迟。
连接池优化:httpx内置了智能连接池,能够自动管理TCP连接的创建与复用,减少连接建立和关闭的开销。相比requests库的简单连接池实现,httpx的连接池更加灵活高效,能够根据实际需求调整并发连接数。
严格的超时控制:httpx默认设置了5秒的超时时间,避免了因网络问题导致请求无限期阻塞。开发者还可以根据需要自定义超时时间,提高程序的可靠性。
类型注解支持:httpx完全支持类型注解,能够在开发过程中提供更好的代码提示和类型检查,减少潜在的错误。
(二)从requests到httpx的平滑过渡
对于习惯了requests库的开发者来说,迁移到httpx库几乎没有学习成本。httpx的API设计与requests库高度兼容,大部分代码只需将requests替换为httpx即可正常运行。例如:
使用requests发送GET请求:
import requests
response = requests.get('https://api.example.com/data', params={'key': 'value'})
print(response.json())
使用httpx发送GET请求:
import httpx
response = httpx.get('https://api.example.com/data', params={'key': 'value'})
print(response.json())
除了同步API,httpx还提供了异步API,让开发者能够轻松实现高并发请求。例如:
import httpx
import asyncio
async def fetch_data():
async with httpx.AsyncClient() as client:
response = await client.get('https://api.example.com/data')
return response.json()
asyncio.run(fetch_data())
三、性能对比:requests与httpx的实战较量
为了更直观地展示requests和httpx的性能差异,我们可以通过一个简单的测试来对比两者在处理高并发请求时的表现。测试场景为发送100个HTTP请求,目标地址为httpbin.org的延迟接口(模拟真实网络延迟)。
(一)使用requests库的同步请求
import requests
import time
def fetch(url):
response = requests.get(url)
return response.status_code
start_time = time.time()
for _ in range(100):
fetch('https://httpbin.org/delay/1')
end_time = time.time()
print(f"requests同步请求耗时: {end_time - start_time:.2f}秒")
(二)使用httpx库的异步请求
import httpx
import asyncio
import time
async def fetch(client, url):
response = await client.get(url)
return response.status_code
async def main():
async with httpx.AsyncClient() as client:
tasks = [fetch(client, 'https://httpbin.org/delay/1') for _ in range(100)]
start_time = time.time()
await asyncio.gather(*tasks)
end_time = time.time()
print(f"httpx异步请求耗时: {end_time - start_time:.2f}秒")
asyncio.run(main())
测试结果显示,requests同步请求耗时约100秒,而httpx异步请求耗时仅约10秒,性能提升了近10倍。这充分体现了httpx在处理高并发请求时的优势,尤其适合爬虫、API测试、实时数据获取等场景。
四、httpx的高级功能
除了基本的请求功能,httpx还提供了许多高级功能,满足复杂场景的需求。
(一)命令行工具
httpx内置了命令行工具,开发者无需编写代码即可发送HTTP请求。安装httpx时只需添加cli扩展:
pip install httpx[cli]
使用命令行工具发送请求示例:
# 发送GET请求
httpx get https://api.example.com/data
# 发送POST请求
httpx post https://api.example.com/submit -d '{"key": "value"}'
# 启用HTTP/2协议
httpx --http2 get https://api.example.com/data
(二)自定义客户端配置
httpx允许开发者通过Client对象自定义请求行为,如设置超时时间、连接池大小、代理、认证信息等。例如:
import httpx
client = httpx.Client(
timeout=10.0,
limits=httpx.Limits(max_connections=100, max_keepalive_connections=20),
proxies={"http://": "http://proxy.example.com:8080", "https://": "http://proxy.example.com:8080"},
auth=("username", "password")
)
response = client.get('https://api.example.com/data')
(三)事件钩子
httpx支持事件钩子,开发者可以在请求发送前、响应接收后执行自定义逻辑。例如,记录请求日志:
import httpx
def log_request(request):
print(f"发送请求: {request.method} {request.url}")
def log_response(response):
print(f"接收响应: {response.status_code} {response.url}")
client = httpx.Client(event_hooks={'request': [log_request], 'response': [log_response]})
response = client.get('https://api.example.com/data')
五、总结
从requests到httpx,Python网络请求库经历了从同步到异步、从单一协议到多协议支持的演进。requests库以其简洁易用的API成为了Python网络编程的经典之作,但在现代高并发场景下逐渐力不从心。httpx库则在继承requests优点的基础上,增加了异步支持和HTTP/2协议支持,大幅提升了性能,同时提供了更丰富的高级功能。
对于开发者来说,选择requests还是httpx取决于具体的应用场景。如果是简单的同步请求场景,requests库仍然是一个不错的选择;如果需要处理高并发请求或与异步框架集成,httpx库则是更好的选择。无论选择哪个库,了解它们的特性和适用场景,都能帮助我们更高效地完成网络编程任务。