怎么根据业务节奏选对IP存活档?
配置代理IP降失败率的第一步不是写代码,是把业务节奏和IP存活档对齐。判断依据是目标站对单IP的请求间隔容忍度和业务的会话时长。
判断规则:
- 请求间隔容忍度短、3秒以内,会话短、单IP用完即弃,选存活1‑3分钟的短效档
- 请求间隔容忍度中、3‑10秒,会话中、单IP连续跑10‑30个请求,选存活5‑15分钟的短效档
- 请求间隔容忍度长、10秒以上,会话长、单IP连续跑数分钟到数小时,选存活0.5‑24小时的独享或长效档
- 请求间隔容忍度中长、7×24持续采集免维护,选隧道代理、每请求换IP
以舆情监测为例,采集节奏是关键词命中即抓、单次请求2‑3秒完成、每天2000万+请求。目标站对单IP的容忍度大约在5秒左右,典型配置是存活5‑10分钟的隧道代理,业务代码走固定隧道入口、每次请求换IP。
以招投标数据为例,采集节奏是每个招标页面需要连续拉取10‑20个附件、单次会话5‑15分钟。目标站对单IP的容忍度长,但对会话连贯性有要求,典型配置是存活30分钟‑2小时的独享代理,业务代码在会话开始时拉一个独享IP、会话结束后主动释放。
存活档选错,后面三步优化都是补丁式的救火。这一步是根节点。
分层重试机制怎么配才能吃掉70%的偶发失败?
不管IP策略多完美,请求失败率永远不可能是0。剩下的失败要靠重试机制吃掉。分层重试的核心是按失败类型分层处理,不同类型的失败对应不同的重试策略。
一个可复用的分层重试模板,伪代码:
def fetch_with_retry(url, max_retries=3):
for attempt in range(max_retries):
try:
response = request_with_proxy(url)
if response.status == 200:
return response
elif response.status in [403, 429]:
# IP被限制类,立即换IP,指数退避
sleep(2 ** attempt)
rotate_ip()
continue
elif response.status in [500, 502, 503, 504]:
# 目标站临时故障,短暂等待,不换IP
sleep(1 + attempt)
continue
elif response.status in [404, 410]:
# 资源不存在,不重试,直接标记失败
return None
except TimeoutError:
# 超时,换IP再试
rotate_ip()
continue
except ConnectionError:
# 连接错误,换IP,延迟
sleep(1)
rotate_ip()
continue
return None关键点有四个。
- 403、429这类IP被限制信号必须立即换IP,不能在原IP上重试,重试只会让当前IP进入更严格的风控。
- 5xx这类目标站故障不需要换IP,等一下重试即可,避免消耗IP。
- 4xx里的404、410是资源不存在,不重试直接标记失败。
- 超时和连接错误的处理,需要区分是代理侧问题还是目标站问题,一般换IP再试即可。
分层重试配置到位后,一个典型采集任务的偶发失败大约能被吃掉70%。剩下30%是策略层的问题,需要靠第三、第四步解决。
会话保持和IP切换怎么协同?
会话保持指的是同一批相关请求走同一个IP。这对招投标数据、法律大数据这类需要连续拉取多个附件的任务是必需的,中途换IP会导致会话token失效、鉴权重来。
会话保持和IP切换的协同,靠会话粒度的IP绑定实现。伪代码示意:
class Session:
def __init__(self):
self.ip = None
self.session_id = generate_session_id()
def start(self):
# 会话开始时拉一个IP,绑定到当前会话
self.ip = get_proxy_ip(sticky=True, ttl=1800)
def request(self, url):
# 会话内所有请求走同一IP
return request_with_ip(url, self.ip, session_id=self.session_id)
def end(self):
# 会话结束时主动释放IP
release_proxy_ip(self.ip)关键点有三个。 一是sticky=True标记这个IP是会话粘性的,代理层不主动切换。TTL设成预估最长会话时长+缓冲,比如1800秒即30分钟。 二是session_id需要贯穿整个会话,用于业务侧的日志追踪和异常定位。IP+session_id可以精准查到哪个IP在哪个会话中出了问题。 三是主动释放IP。会话结束后不主动释放,IP会在TTL到期前一直被绑定,造成资源浪费;且如果这个IP在会话过程中被目标站部分标记,主动释放能避免下一个会话继承污染。
会话保持和IP切换的协同做到位,能吃掉长会话任务10‑15%的失败率,这些失败在没有会话粘性的配置下都表现为中途鉴权失效。
异常IP剔除和池切换怎么做实时防护?
前三步做到位后,剩下的失败率主要来自个别IP在采集过程中被目标站临时标记这类偶发问题。第四步是实时监控当前使用的IP,出现异常信号时立即剔除并切换。
实时防护的四个信号:
- 连续N次403/429,这个IP已被目标站限制,剔除
- 响应时间连续升高,这个IP可能被限流,剔除
- 空响应或异常JSON结构,目标站可能返回了假数据,剔除
- 连接超时率高于阈值,这个IP的链路可能出问题,剔除
实时防护的核心配置,伪代码:
class IPHealthMonitor:
def __init__(self):
self.ip_metrics = {} # IP -> {failures, latencies, timestamps}
def record(self, ip, status, latency):
m = self.ip_metrics.setdefault(ip, {'failures': 0, 'latencies': []})
if status in [403, 429] or status is None:
m['failures'] += 1
m['latencies'].append(latency)
def should_rotate(self, ip):
m = self.ip_metrics.get(ip, {})
# 连续3次失败,剔除
if m.get('failures', 0) >= 3:
return True
# 最近5次响应时间平均超过阈值,剔除
recent = m.get('latencies', [])[-5:]
if len(recent) == 5 and sum(recent)/5 > 3.0:
return True
return False关键点有两个。 一是剔除要区分粒度。单IP连续失败,单IP剔除;同一子池多个IP连续失败,子池切换;同一供应商多个子池同时失败,供应商切换,如果有备用供应商。 二是剔除后不立即拉黑。异常IP先放入观察队列、休息5‑10分钟再放回可用池,避免因为业务瞬时波动误伤好IP。
四步都做到位后,一个典型采集任务的请求失败率通常能从20‑30%的初始状态降到3‑5%,剩下的失败是目标站主动策略调整或不可控异常导致的,属于工程可接受范围。
四步整合起来,一个采集任务的配置模板长什么样?
以网站采集器采集某公开数据类目为例,一个可复用的配置模板包括四个部分。
配置层:
- 存活档,短效5分钟,隧道代理接入
- 并发,50路
- 单IP QPS上限,3
- 请求超时,8秒
重试层:
- 分层重试,403/429立即换IP、5xx等待重试、4xx其他直接失败
- 最大重试次数,3
- 退避策略,指数退避,基数2秒
会话层:
- 采集类型,单请求独立采集、无会话
- 请求Cookie策略,每次请求清空
监控层:
- 单IP连续失败阈值,3
- 单IP最大延迟阈值,3秒
- IP观察队列休息时长,10分钟
- 失败率报警阈值,>10%告警
这套模板不是万能的,需要按具体业务节奏和目标站策略微调。但它给出了配置代理IP降低请求失败率这一工程问题的可执行框架,每一层都有具体的调节参数,每一层都能被测量和优化。
FAQ
Q:分层重试的退避策略用固定间隔和指数退避哪个好?
看失败类型。IP被限制类失败、403/429用指数退避,避免连续短时间重试对同一目标站施加压力。目标站临时故障类失败、5xx用固定间隔,等待目标站恢复。超时和连接错误用短固定间隔,因为这类失败往往是网络抖动,等太久没意义。
Q:会话粘性的TTL怎么设?
按预估最长会话时长+30%缓冲。招投标数据类会话时长通常在5‑15分钟,TTL设成20分钟即可;征信查询类会话时长通常在1‑3分钟,TTL设成5分钟。TTL设太长会造成IP资源浪费,太短会导致会话中途IP失效。
Q:并发数和单IP QPS上限怎么定?
并发数看整体采集吞吐目标,单IP QPS上限看目标站对单IP的请求间隔容忍度。一个常见的起点是并发50路、单IP QPS上限3,即每秒总吞吐150请求。跑起来后观察失败率和目标站响应模式,逐步调整。QPS调太高会触发目标站风控,调太低浪费带宽。
Q:异常IP剔除后要不要拉黑?
一般不建议永久拉黑。异常IP的异常可能是瞬时状态,目标站临时策略、网络抖动、缓存击穿。放入观察队列休息5‑10分钟再放回可用池是更稳妥的做法。永久拉黑会持续消耗IP池、抬升成本,且忽略了IP质量随时间恢复的特征。
Q:如果目标站升级了反爬策略,这四步配置还能用吗?
框架能用,参数需要调。目标站升级反爬策略后,通常表现为存活档需要缩短、单IP QPS上限需要下调、异常剔除的失败阈值需要更严格。四步的骨架不变,具体阈值按新的目标站响应模式重新校准即可。真正需要重写整套配置的情况很少。