爬虫挂代理配置要点!请求头、超时时间与重试次数怎么设
问题往往不在代理本身,而在爬虫侧的配套……
很多做数据采集的朋友,代理IP买回来了,往配置文件里一填地址和端口,代码跑起来——结果三天不到,IP 封了大半,请求成功率掉到 60% 以下。
问题往往不在代理本身,而在爬虫侧的配套配置。请求头太”干净”、超时时间一卡就是两分钟、失败后立刻原样重发……这些细节不调整,再好的代理池也扛不住。
这篇文章把爬虫挂代理时最关键的三块配置——请求头、超时时间、重试次数——逐一拆开讲,最后附一段可以直接用的 Python 代码,照着改就能跑。
一、请求头:别让爬虫”裸奔”
目标站点的反爬系统第一眼看的就是 HTTP 请求头。如果你用 Python 的 requests 库直接发请求,默认带上的 User-Agent 是 python-requests/2.x,等于在对方面前举着牌子说”我是脚本”。
挂代理之后,IP 是干净的,但请求头暴露了真实意图,等于白搭。下面五个字段是每次请求必须处理的:
| 请求头字段 | 为什么重要 | 推荐做法 |
|---|---|---|
| User-Agent | 最基础的指纹,直接暴露客户端类型 | 维护 20-50 条主流浏览器 UA 池,每次请求随机取一条;避免所有请求用同一个 UA |
| Accept-Language | 语言设置和 IP 归属地矛盾会触发风控 | 代理 IP 在美国就配 en-US,en;q=0.9,在日本就配 ja-JP,保持 IP 与语言一致 |
| Referer | 模拟”从哪个页面点过来的” | 不要留空。填目标站的首页或上一级页面 URL,让请求链路看起来像正常浏览 |
| Accept-Encoding | 声明是否支持压缩 | 统一写 gzip, deflate, br,和真实浏览器行为对齐 |
| Connection | 控制连接是否复用 | 同域请求用 keep-alive 复用 TCP 连接,减少握手开销;跨域或切换代理时断开重建 |
还有一个容易忽略的点:请求头的顺序和格式。真实浏览器发出的请求头有固定的优先级排列,如果你用代码手动拼字符串,顺序乱七八糟,有经验的风控工程师一眼就能看出是脚本。用成熟库(如 requests、httpx)设置 header 字典,库会自动处理编码和排序,别自己手拼。
二、超时时间:别给慢请求”无限续命”
很多爬虫代码里写的是 requests.get(url, timeout=120),甚至干脆不写 timeout。后果是:某个代理节点卡住了,你的线程就干等两分钟,并发数被占满,整个采集任务像蜗牛一样爬。
正确的做法是把超时拆成两段:
- 连接超时(connect timeout):从发起 TCP 握手到连接建立的时间。一般设 5 秒。如果 5 秒还没连上,说明代理节点本身有问题(IP 被封、端口不通、节点宕机),继续等没有意义。
- 读取超时(read timeout):连接建立后,等待服务器返回第一个字节的时间。一般设 15~30 秒。目标站点正常响应通常在 3 秒内,超过 30 秒大概率是代理链路出了问题。
在 Python 里,timeout 参数可以传一个元组来分别指定:
# 连接超时 5 秒,读取超时 20 秒
response = session.get(
url,
timeout=(5, 20),
proxies={"http": proxy_url, "https": proxy_url},
headers=build_headers()
)
这里有一个和代理强相关的细节:每次切换代理 IP 时,必须新建连接。如果你用 requests.Session 做连接池复用,切换代理后旧的 TCP 连接还挂在之前的 IP 上,要么报错,要么请求实际走的还是老 IP。所以切换代理后,要么 session.close() 再重建,要么用 httpx.Client 的 mount 机制按代理地址分配独立的传输通道。
三、重试次数:指数退避 + 换 IP,别死磕
请求失败是常态,尤其是代理 IP 在高并发下被临时限流。但”失败了就立刻原样重发”是最差策略——你刚被限流,一秒后又用同一个 IP、同一个请求头打过去,等于告诉对方”我就是机器人”。
推荐的重试逻辑分三层:
- 指数退避等待:第 1 次失败等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒,第 4 次等 8 秒。加上一个随机抖动(±0.5 秒),避免多个爬虫实例同步重试形成”重试风暴”。
- 连续失败换代理:同一个代理 IP 连续失败 3 次(不管是 403、503 还是超时),就把这个 IP 标记为”冷却”,从池中取一个新 IP 继续。冷却时间建议 5~15 分钟,别刚被限流就立刻用回同一个 IP。
- 设置最大重试上限:单条 URL 最多重试 4~5 次。超过上限就记录到失败队列,等下一轮任务再处理,不要无限循环。
import random, time, requests
from requests.adapters import HTTPAdapter
MAX_RETRIES = 4
BACKOFF_BASE = 1 # 秒
def fetch_with_proxy(url, proxy_pool, session=None):
"""带代理的健壮请求函数"""
if session is None:
session = requests.Session()
adapter = HTTPAdapter(pool_connections=20, pool_maxsize=20)
session.mount("http://", adapter)
session.mount("https://", adapter)
for attempt in range(MAX_RETRIES):
proxy = proxy_pool.get_next() # 从池中取一个可用代理
proxy_url = f"http://{proxy['ip']}:{proxy['port']}"
try:
resp = session.get(
url,
timeout=(5, 20),
proxies={"http": proxy_url, "https": proxy_url},
headers=build_headers(region=proxy["region"]),
)
if resp.status_code == 200:
return resp
# 403 / 503 等风控响应
proxy_pool.mark_cooldown(proxy, cooldown=300)
except (requests.Timeout, requests.ConnectionError) as e:
proxy_pool.mark_cooldown(proxy, cooldown=300)
# 指数退避 + 随机抖动
wait = (BACKOFF_BASE ** attempt) + random.uniform(-0.5, 0.5)
time.sleep(max(wait, 0.5))
# 超过最大重试次数
print(f"[FAIL] {url} exceeded {MAX_RETRIES} retries")
return None
注意 mark_cooldown 这一步。代理池不是”用完了就没了”,而是需要一套健康度管理:每个 IP 记录最近的成功/失败次数,失败的 IP 进入冷却队列,冷却结束后重新参与轮询。这样你的代理利用率能提升 30% 以上,同时避免把流量集中砸在几个”快挂了”的 IP 上。
四、代理 IP 的选择:配置再好,底子不行也白搭
前面讲的请求头、超时、重试,都是”软件层”的优化。但爬虫能不能稳定跑,底层取决于代理 IP 本身的质量:
- IP 类型:住宅代理(Residential)的 IP 来自真实家庭宽带,被识别为”机器人”的概率远低于数据中心 IP。如果你的目标站点风控严格(电商、社交媒体、新闻聚合),优先选住宅代理。
- 匿名等级:高匿名代理不会在请求中暴露代理身份(
X-Forwarded-For、X-Real-IP等头部不泄露)。低匿名代理会带上这些头,等于告诉对方”我走了代理”。 - IP 池规模和轮换策略:池子越大,单 IP 被集中打击的概率越低。支持按地区、ISP 筛选的代理池,能帮你把 IP 和目标站点的风控规则对齐。
- 延迟和稳定性:代理多一跳,延迟自然增加。选择有海外节点覆盖、链路优化的服务商,能把额外延迟控制在 50ms 以内,不至于让你的超时设置被迫拉大到离谱的程度。
如果你正在搭建或优化爬虫的代理层,光络云值得纳入评估。光络云定位为全球网络基础设施及数据服务商,提供国内和海外双区域的代理 IP 服务,IP 池覆盖多个主流地区,支持高匿名、低延迟的代理通道。其住宅代理和数据中心代理可按需组合,配合前面讲的请求头轮换和指数退避策略,能显著降低 IP 封禁率。需要注意的是,光络云的代理 IP 需要客户端自身具备海外网络环境才能正常访问(TikTok 专线产品除外),部署前请确认你的网络条件。
五、几个容易踩的坑
坑 1:所有请求共用一个 Session 对象。
Session 内部维护连接池,如果代理 IP 频繁切换,旧连接会堆积。建议按代理 IP 分组管理 Session,或者每次切换代理后显式关闭旧 Session。
坑 2:超时设得太”宽容”。
timeout=120 看起来”保险”,实际上一个卡死的连接会占住线程池的 slot。10 个并发线程,3 个卡在超时里,你的有效并发就只剩 7 个。连接超时 5 秒、读取超时 20 秒,是绝大多数场景的合理区间。
坑 3:重试时不刷新请求头。
第一次请求用了 Chrome 的 UA,失败后重试还是同一个 UA、同一个 Referer。对方风控系统一看:同一个”浏览器”在一分钟内发了 4 次一模一样的请求,直接拉黑。每次重试应该从 UA 池里重新取一条。
坑 4:忽略 HTTP 状态码的语义。
403 是”你被拒了”,503 是”我暂时忙不过来”,429 是”你太频繁了”。这三种错误的处理策略完全不同:403 应该立刻换 IP,503 可以短退避后重试,429 需要拉长退避时间。别一律当成”网络错误”处理。
常见问题
Q: 代理 IP 和爬虫请求头,哪个对防封影响更大?
两者缺一不可,但侧重点不同。代理 IP 决定的是”你从哪里来”,请求头决定的是”你看起来像谁”。如果 IP 是数据中心段但请求头伪装成住宅浏览器,高级风控系统通过 IP 段查询就能识破。反过来,IP 是住宅段但请求头写着 python-requests,一样秒封。两者必须对齐。
Q: 超时时间设多少合适?有没有统一标准?
没有绝对标准,取决于你的目标站点响应速度和代理链路的延迟。但一个实用的起点是:连接超时 5 秒、读取超时 20 秒。如果你的代理节点在海外、目标站点也在海外,链路延迟会高一些,读取超时可以放宽到 30 秒。建议先用小批量请求跑 500 次,统计 P95 响应时间,再据此微调。
Q: 重试次数设 3 次还是 5 次?
建议设 4 次(含首次请求共 4 次尝试)。太少了,偶发的网络抖动会导致大量请求被误判为失败;太多了,一个持续被限流的 IP 会浪费大量时间。配合”连续 3 次失败换 IP”的策略,4 次重试基本能覆盖绝大多数临时性故障。
Q: 用光络云的代理 IP,我的服务器必须部署在海外吗?
是的,光络云的代理 IP 服务需要客户端自身具备海外网络环境才能正常建立连接(TikTok 专线产品除外)。如果你的服务器在国内,需要确保出口网络可以正常访问海外节点。部署前建议先做一轮连通性测试,确认代理端口在你的网络环境下可达。
Q: 代理池需要多大?100 个 IP 够不够?
取决于你的请求频率和目标站点的严格程度。如果每天请求量在 10 万次以内、目标站点风控中等,100 个住宅 IP 配合合理的轮换和冷却策略基本够用。如果日请求量到百万级、或者目标是高风控平台,建议 500 个以上 IP,并且按地区分散,避免单一地区 IP 被集中封禁。
