真正要做的,是让爬虫在检测到403、connectionreseterror或响应含“访问被拒绝”时自动换代理重试;需串联代理获取、验证、轮换与降级全链路,并预加载+后台刷新以避免api延迟拖慢吞吐。

手动换代理不是解决办法,是临时止痛;真正要做的,是让爬虫在检测到 403、ConnectionResetError 或响应内容含 “访问被拒绝” 时,自动触发新代理获取并重试——这需要把代理获取、验证、轮换、失败降级全链路串起来。
用 API 获取代理前先确认返回格式和鉴权方式
不同代理服务商(如快代理、芝麻代理、讯代理)的 API 返回结构差异很大,有的直接返回 ip:port 字符串,有的返回 JSON 包含 proxy、expire_time、speed 等字段。不提前解析清楚,后续根本没法用。
- 用
curl或requests.get()直接调一次 API,打印response.json()看原始结构 - 检查是否需带
Authorizationheader 或tokenquery 参数,漏掉就返回{"code":401,"msg":"invalid token"} - 注意频率限制:多数免费/低价套餐限每分钟 5–10 次请求,别在重试循环里无节制调用
代理必须验证可用性再加入池子,不能“拿过来就用”
API 返回的代理可能已失效、被目标站拉黑、或仅支持 HTTP 不支持 HTTPS——直接塞进 requests.Session().proxies 会导致后续所有请求卡死或报 ProxyError。
- 验证时用最轻量的请求:向
http://httpbin.org/ip发起 GET,超时设为3秒,stream=True避免下载响应体 - 只接受状态码
200且响应 JSON 中origin字段包含该代理 IP(证明流量真经代理发出) - 验证失败的代理立即丢弃,别缓存、别重试,否则会污染整个代理池
requests 重试逻辑里嵌入代理切换,而非全局替换
很多人写个全局 current_proxy 变量,出错就换一个——这会导致并发请求互相覆盖,线程不安全,且无法区分是网络抖动还是代理失效。
- 把代理作为请求级参数传入,例如
requests.get(url, proxies={"https": proxy_str}, timeout=10) - 封装一个
fetch_with_retry(url, max_retries=3)函数,在每次重试前从代理池取一个新代理(用queue.Queue或itertools.cycle+ 锁) - 捕获具体异常:
requests.exceptions.ProxyError、requests.exceptions.ConnectTimeout、requests.exceptions.ReadTimeout才触发换代理;HTTPError且 status=404 则不用换
代理池耗尽或全部失效时要有兜底策略
跑着跑着发现代理池空了,或者连续 5 个代理都验证失败——这时候硬等新 API 返回只会让任务卡死。
- 设置代理池最小保有量(如 3 个),低于阈值就异步调用 API 补充,但不阻塞当前请求
- 引入本地备用方案:比如用
rotating-user-agents+time.sleep(random.uniform(1,3))降低请求密度,撑到代理恢复 - 记录失效代理的 IP 和错误类型到日志文件,方便后续分析是服务商问题还是自己调用过频
最常被忽略的一点:代理 API 的响应延迟本身可能高达 800ms,如果每次请求前都同步调一次 API,吞吐量直接腰斩。真正的做法是预加载 + 后台刷新,让代理永远“比请求快半步”。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











