抓取用轮换代理:配置与常见陷阱
轮换代理会改变你的请求所使用的出口 IP 地址,可以是每个请求换一个,也可以是每隔一段固定时间换一个。它是网页抓取中最常用的工具之一,也是最常被误用的工具之一。轮换得太少,单个地址会被限速;轮换得太频繁,流量又看起来完全不像访客。本指南解释两种轮换模型,给出一个带失效代理重试的可用 Python 方案,并说明代理字段如何配合验证码识别。
轮换与粘性会话
轮换代理服务分配地址的方式有两种:
- 按请求轮换。 每个请求都获得一个新的出口地址。这适用于大规模爬取许多互不相关的页面,其中没有任何页面需要依赖前一个页面。
- 粘性会话。 在一段设定的时间内,例如几分钟,或直到你主动释放之前,保持同一个地址。这适用于任何需要状态的场景:登录、购物车,或者 Cookie 很重要的分页列表。
真实访客在整个访问过程中使用同一个地址。粘性会话模拟的就是这种行为,因此当网站使用 Cookie 或会话时,它通常是更好的默认选择。无状态的爬取则适合按请求轮换。
用 Python 实现一个基础的轮换池
下面的示例维护一个代理 URL 池,依次轮换使用,并在某个代理失败时切换到下一个。凭据请保存在环境变量中,绝不要写进源代码。
import itertools
import os
import requests
# 代理 URL 从环境变量读取,例如:
# PROXY_POOL="http://user:pass@203.0.113.10:8080,http://user:pass@203.0.113.11:8080"
PROXIES = [p.strip() for p in os.environ.get("PROXY_POOL", "").split(",") if p.strip()]
rotation = itertools.cycle(PROXIES)
def fetch(url: str, max_tries: int = 3) -> requests.Response:
last_error = None
for _ in range(max_tries):
proxy = next(rotation)
try:
r = requests.get(
url,
proxies={"http": proxy, "https": proxy},
timeout=30,
)
if r.status_code == 407: # 代理认证失败
raise requests.RequestException("proxy auth rejected")
return r
except requests.RequestException as exc:
last_error = exc # 代理失效或过慢:换下一个
raise RuntimeError(f"all attempts failed for {url}: {last_error}")
这里有两个细节很关键。第一,失效的代理应当换一个不同的地址重试,而不是继续用同一个。第二,遇到认证错误的请求应当停止并上报,而不是把整个池子都耗尽。
追踪代理健康状况
简单的轮询会持续把流量发送给已经开始失败的代理。请为每个地址记录一个简单的分数:统计近期失败次数,一旦超过阈值,就把该地址从池中移出一段冷却期。之后再把它放回,并继续观察。这样,你的抓取器就会把请求花在池中健康的那部分上。
每个结果都要记录所用的代理。当网站开始返回封锁页面时,你会想知道是某一个地址、某一个地区,还是整个池子造成的。
控制池子的节奏
轮换会把负载分散到多个地址上,但每个地址仍然有自己的速率。请为每个地址设置延迟,并为整个池子设置每秒请求数的全局上限。轮换并不是发送更多流量的许可,它只是让每个地址的流量保持在合理范围内的一种方式。
常见错误
大多数轮换问题都源于少数几种习惯。在登录或结账流程中途更换地址,会打断会话,并让网站产生怀疑。429 响应表示的是网站对你的限速,而不是代理出了问题,因此立即换一个地址再重试,只会让问题扩散。在保留同一批 Cookie 的同时每次请求都更换地址,也同样不一致,因为这些 Cookie 是发给另一位访客的。最后,一个从不检查的池子会悄悄积累大量失效的地址,你的错误率会在没有明显原因的情况下上升。请定期检查池子,并移除失败的地址。
代理与验证码识别
有些验证码任务可以使用你的抓取器所用的代理。你可以通过可选的 proxy 字段传入它,格式为 http://user:pass@host:port,识别就会从你的页面请求所走的同一网络路径发出。无代理任务则完全跳过这个字段。选择哪一种,取决于网站是否把验证码绑定到网络地址,这种权衡在代理与无代理验证码识别中有详细说明。
两个实际要点:
- 当网站检查地址时,页面请求和验证码识别应使用同一个代理。混用地址可能导致 token 失效。
- Token 过期很快。请在提交表单之前才请求 token,而不要提前很久就请求。参见验证码 token 过期。
Scarnox 目前上线的验证码类型是 PopularCaptcha。PopularCaptcha Python 指南展示了请求的方式,以及如何提交返回的 token。
如何选择代理
你轮换的地址类型,与轮换机制本身同样重要。数据中心地址速度快、单次请求成本低,但往往得分较低。住宅地址得分较好,但速度较慢。住宅代理与数据中心代理对比一文对两者做了深入比较,其中的建议同样适用于你在这里构建的代理池。
负责任地抓取
- 阅读
robots.txt以及你所抓取网站的条款。 - 使用代理来分散合法的负载,而不是用来绕过网站所有者设置的限制。
- 只使用地址经过同意获取的代理服务。通过未获设备所有者同意的设备路由流量是不可接受的。
- 不要在代码和日志中保存凭据。
下一步
免费试用额度,无需信用卡:注册账户,并使用你自己的代理试用 PopularCaptcha 流程。当前费率请查看定价页面。