在 Python 中使用 httpx 配置代理
httpx 与代理
httpx 是一个现代的 Python HTTP 库,同时支持同步和异步两种运行模式。它的一大优势是无需额外库即可内置支持 HTTP/2 和 SOCKS 代理。
安装
pip install httpx
# SOCKS 支持:
pip install httpx[socks]
# HTTP/2 支持:
pip install httpx[http2]
同步模式
HTTP 代理
import httpx
proxy = "http://user:pass@proxy_ip:port"
response = httpx.get("https://httpbin.org/ip", proxy=proxy)
print(response.json())
为 HTTP 和 HTTPS 设置不同代理
proxies = {
"http://": "http://proxy1:port",
"https://": "http://proxy2:port",
}
with httpx.Client(proxy=proxies) as client:
response = client.get("https://httpbin.org/ip")
print(response.json())
SOCKS5 代理
import httpx
proxy = "socks5://user:pass@proxy_ip:port"
with httpx.Client(proxy=proxy) as client:
response = client.get("https://httpbin.org/ip")
print(response.json())
异步模式
基础示例
import httpx
import asyncio
async def fetch():
proxy = "http://user:pass@proxy_ip:port"
async with httpx.AsyncClient(proxy=proxy) as client:
response = await client.get("https://httpbin.org/ip")
print(response.json())
asyncio.run(fetch())
并发请求
import httpx
import asyncio
async def fetch_url(client, url):
try:
response = await client.get(url, timeout=10)
return response.text
except Exception as e:
return None
async def main():
proxy = "http://user:pass@proxy_ip:port"
urls = [f"https://example.com/page/{i}" for i in range(50)]
async with httpx.AsyncClient(proxy=proxy) as client:
tasks = [fetch_url(client, url) for url in urls]
results = await asyncio.gather(*tasks)
success = sum(1 for r in results if r)
print(f"Success: {success}/{len(urls)}")
asyncio.run(main())
经代理的 HTTP/2
httpx 是少数支持 HTTP/2 的 Python 库之一:
import httpx
proxy = "http://user:pass@proxy_ip:port"
with httpx.Client(proxy=proxy, http2=True) as client:
response = client.get("https://httpbin.org/ip")
print(f"HTTP version: {response.http_version}")
print(response.json())
经代理的 HTTP/2 通过 CONNECT 方法实现——代理建立一条 TCP 隧道,再通过该隧道与服务器建立 HTTP/2 连接。
代理轮换
import httpx
import random
PROXIES = [
"http://user:pass@proxy1:port",
"http://user:pass@proxy2:port",
"http://user:pass@proxy3:port",
]
def get_random_proxy():
return random.choice(PROXIES)
# 同步轮换
for i in range(10):
proxy = get_random_proxy()
with httpx.Client(proxy=proxy) as client:
resp = client.get("https://httpbin.org/ip")
print(resp.json())
异步轮换
import httpx
import asyncio
import random
PROXIES = [
"http://user:pass@proxy1:port",
"http://user:pass@proxy2:port",
"http://user:pass@proxy3:port",
]
async def fetch_with_rotation(url):
proxy = random.choice(PROXIES)
async with httpx.AsyncClient(proxy=proxy) as client:
try:
resp = await client.get(url, timeout=10)
return resp.text
except Exception:
return None
async def main():
urls = ["https://example.com"] * 20
tasks = [fetch_with_rotation(url) for url in urls]
results = await asyncio.gather(*tasks)
print(f"Success: {sum(1 for r in results if r)}")
asyncio.run(main())
客户端配置
超时
timeout = httpx.Timeout(
connect=5.0, # 连接代理和服务器
read=10.0, # 读取响应
write=5.0, # 发送请求
pool=5.0 # 在连接池中等待
)
client = httpx.Client(proxy=proxy, timeout=timeout)
请求头与 Cookie
headers = {
"User-Agent": "Mozilla/5.0 ...",
"Accept-Language": "en-US,en;q=0.9",
}
client = httpx.Client(
proxy=proxy,
headers=headers,
follow_redirects=True,
max_redirects=10
)
连接池
limits = httpx.Limits(
max_connections=100, # 连接总数
max_keepalive_connections=20 # keep-alive 连接数
)
client = httpx.AsyncClient(proxy=proxy, limits=limits)
错误处理
import httpx
async def safe_fetch(client, url):
try:
response = await client.get(url)
response.raise_for_status()
return response.text
except httpx.ProxyError as e:
print(f"Proxy error: {e}")
except httpx.ConnectTimeout:
print("Connection timeout")
except httpx.ReadTimeout:
print("Read timeout")
except httpx.HTTPStatusError as e:
print(f"HTTP {e.response.status_code}")
except httpx.RequestError as e:
print(f"Request error: {e}")
return None
httpx、requests 与 aiohttp 对比
| 参数 | httpx | requests | aiohttp |
|---|---|---|---|
| 同步 | 支持 | 支持 | 不支持 |
| 异步 | 支持 | 不支持 | 支持 |
| HTTP/2 | 支持 | 不支持 | 不支持 |
| SOCKS | 支持(内置) | 通过 requests-socks | 通过 aiohttp-socks |
| URL 中指定代理 | 支持 | 支持 | 支持 |
| API | 兼容 requests | 标准 | 自定义 |
| 性能 | 高 | 中 | 高 |
从 requests 迁移
httpx 的设计目标是成为 requests 的直接替代品,迁移成本极低:
# requests
import requests
resp = requests.get(url, proxies={"https": proxy})
# httpx
import httpx
resp = httpx.get(url, proxy=proxy)
主要区别:httpx 使用 proxy 参数(单数形式)代替 proxies。
结论
对于需要代理功能的新 Python 项目,httpx 是最佳选择。它内置支持 HTTP/2、SOCKS5 以及同步和异步两种模式,是一款通用性很强的工具。兼容 requests 的 API 也让既有项目的迁移变得简单。
