跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

Python中如何实现异步的爬虫代理切换_在aiohttp中动态更新Proxy参数

aiohttp中不能在ClientSession初始化时设proxy,因会话级代理固定不可变;必须在每个session.get()等请求方法中单独传proxy参数,且需确保格式完整、避免传None,并配合force_close=True防止连接复用混乱。 为什么直接在
aiohttp.ClientSession
初始化时传
proxy
参数行不通 因为
aiohttp.ClientSession
proxy
参数是会话级的,一旦创建就固定绑定到某个代理地址,后续所有请求都复用它。你没法在单个 session 里“中途换代理”。强行改
session._default_proxy
属于黑盒操作,不稳定且在新版本中可能失效。 常见错误现象:
AttributeError: can't set attribute
或请求仍走旧代理,甚至引发连接复用混乱。 真正可行的方式是:每个请求单独指定
proxy
参数 必须确保每次调用
session.get()
/
post()
等方法时,显式传入当前要使用的代理 URL 注意代理 URL 格式必须完整,例如
http://user:pass@host:port
http://host:port
;不支持只传 host:port 如何在并发请求中为每个任务分配不同代理 核心思路是把代理列表和待抓取 URL 列表 zip 起来,或用
asyncio.Queue
统一调度。避免多个协程争抢同一个代理导致限速/封禁。 实操建议: 立即学习 “ Python免费学习笔记(深入) ”; Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载 用
itertools.cycle()
轮询代理(适合简单轮换,但无法感知代理失效) 更稳妥的做法是维护一个可异步获取代理的函数,比如
async def get_valid_proxy()
,内部做健康检查(如先发 HEAD 请求验证连通性) 不要在
ClientSession
外层做代理选择逻辑,而应在每个
session.request()
调用前确定代理值 示例片段:
async with session.get(url, proxy=proxy_url) as resp:
——
proxy_url
必须是字符串,不能是
None
;若某次不想用代理,就别传
proxy
参数,而非传
None
遇到
aiohttp.client_exceptions.ClientConnectorError
怎么关联到代理问题 这个错误本身不指明是代理挂了还是目标站挂了。需要结合
exception.__cause__
或日志上下文判断。 容易踩的坑: 代理认证失败时,aiohttp 默认抛
ClientResponseError
(状态码 407),但有时会被底层 SSL 或连接层吞掉,最终表现为
ClientConnectorError
代理超时或无响应,会触发
asyncio.TimeoutError
,但常被包裹进
ClientConnectorError
中 建议在捕获异常后加一句:
if "proxy" in str(exc).lower(): ...
做粗略过滤(虽然不严谨,但比完全盲猜强) 调试阶段可在请求前打印
proxy_url
,并用
curl -x
手动验证该代理是否可用 代理切换频率太高会不会被 aiohttp 自动复用连接池搞乱 会。aiohttp 默认启用连接池(
TCPConnector
),而连接池是按 host + port + proxy 组合索引的。如果频繁切换代理,会导致大量空闲连接堆积,内存缓慢上涨,甚至触发
Too many open files
。 解决方案很直接: 初始化
ClientSession
时传
connector=aiohttp.TCPConnector(limit_per_host=10, force_close=True)
——
force_close=True
关键,它让每次请求后主动关闭 TCP 连接,避免复用到不同代理 或者更精细地控制:为每个代理单独建一个短生命周期的
ClientSession
(不推荐,开销大),不如统一用
force_close=True
+ 合理的
limit_per_host
注意:设了
force_close=True
后,HTTP/1.1 的 keep-alive 会失效,但对代理场景影响不大——反正你本来就不想复用连接 代理池的实效性永远比切换逻辑更重要。再漂亮的异步调度,也救不了已经失效的代理列表。上线前务必加一层实时探测,别只靠“上次能用”来假设。

相关文章