做数据采集的人大概都遇到过这种局面:脚本跑了半小时,进度条卡在 12%,日志里全是超时和 403,翻回去一看,代理池里能用的一只手数得过来。这时候大多数人第一反应是"IP 不够用",于是把轮换频率调到每请求一次就换——结果报错更多了。
这篇就把两件容易互相打架的事说清楚:多久换一次 IP,以及换的过程中连接怎么不断。看完你至少能判断出,自己的任务到底该配几分钟一换,还是该让一个 IP 撑完一整段。
先别急着调频率,摸清你手上这三个数
轮换频率不是拍脑袋定的,它由三个实实在在的数字倒推出来。
第一个是单次请求的完整耗时。注意是完整耗时,不是服务器响应时间。从建立连接、发请求、等返回、读完 body 到关闭,这一整套算下来,一个普通商品详情页在国内不同地区可能要 300ms 到 1.5 秒不等。如果你要抓的页面本身还带几张图、几个异步接口,两秒以上很常见。
第二个是目标站点的容忍阈值。同一个 IP 在十分钟里访问 30 次,有的站毫无反应,有的站第六次就给你弹验证。这个没法靠猜,只能试:拿三五个 IP,分别按每分钟 5 次、10 次、20 次的节奏打,看哪一档开始出现异常返回。这个测试花二十分钟,能省掉后面两天瞎调参。
第三个是你的任务总量。要采 5000 个页面和要采 50 万个页面,策略完全是两回事。前者一个稳妥的低频任务两小时能跑完,后者就必须考虑单位时间的吞吐。
| 任务类型 | 建议轮换节奏 | 单 IP 承受请求数 | 要盯的指标 |
|---|---|---|---|
| 商品详情/文章页,几千条量级 | 每 10-20 次请求换一次 | 15 次左右 | 成功率是否稳定在 95% 以上 |
| 搜索结果页,需要多地区数据 | 按地区批量切换 | 同地区连续 5-8 次 | 返回内容地区是否对得上 |
| 需要登录态的数据 | 整段会话固定一个 IP | 不主动换 | 会话是否被踢下线 |
| 接口类数据,量大且轻 | 每 30-60 次换一次 | 50 次左右 | QPS 是否被限 |
还有个容易被忽略的细节:换 IP 的动作本身要花时间。如果每到一次上限就同步去拉一个新 IP,等待时间会直接吃掉吞吐。稳妥的做法是后台线程提前备好一批待用 IP,主流程只从队列里取,取不到才阻塞。
换得像"换个人在操作",而不是"换了个马甲"
有些朋友发现,明明每十次就换一次 IP,还是被拦。问题往往不在频率,而在换得不像真人。
想象一个真实用户在用你的目标站点:他从打开首页开始,浏览列表,点进详情,翻到第二页,偶尔停留久一点。全程同一个出口 IP,浏览器指纹不变,请求头一致。而你的脚本是:IP 换了,User-Agent 也跟着换;IP 换了,请求顺序还是严格按 ID 递增;IP 换了,每次间隔精确到毫秒级的 0.500 秒——这种规律性比不换 IP 更扎眼。
所以轮换要做的是"整体节奏的自然化":
一是让间隔有抖动。基础间隔 0.8 秒,实际执行时随机浮动 ±40%,也就是 0.48 到 1.12 秒之间。这个改动一行代码的事,效果比换十次 IP 都明显。
二是让 IP 和地区绑定。如果这轮抓的是华东某几个城市的门店信息,那这段任务里所有请求都该来自那个地区,而不是随机乱跳。神龙IP支持 200+ 城市的精准定位,做区域价格对比、本地搜索结果核对这类任务时,就能按城市分组跑,一组跑完再切下一组,逻辑很干净。
三是别让一个 IP 承担不相关的任务。同一个 IP 上一秒在抓北京餐饮数据,下一秒去抓广州汽车配件,行为画像会显得很怪。按任务切池子,比按时间切池子更安全。
稳定性八成输在连接管理,不是 IP 质量
报错多的时候,先分清是哪一类。如果是 403、429、返回验证页,那是被识别了,属于 IP 策略问题;如果是 timeout、connection reset、读了半截断开,那多半是连接管理没做好。这两种问题的解法完全不同,混在一起调只会越调越乱。
连接这一侧,最常见的三个坑:
不设超时。很多示例代码里 requests.get 不写 timeout,默认就是一直等。遇上代理链路抖一下,整个线程就挂在那里,几十个线程很快被占满,整个任务假死。读超时和连接超时都要设,而且数值别设太紧,网络波动下 10 秒是个比较稳的起点。
并发开太满。100 个线程同时打,本地看着很猛,实际上连接队列里全是排队和超时。多数场景下 20-40 个并发足够跑出好成绩,稳定性和速度反而都更好。带宽也是同理,动态高级套餐峰值 6Mbps、动态独享峰值 10Mbps,带宽 6-15M 可按需定制,并发数要和带宽匹配,不是越大越好。
失败后立刻重试。请求挂了马上用同一个 IP 再打一次,大概率还是挂,还额外加了两次失败记录。正确做法是退避:等 1 秒、3 秒、再不行就换 IP,重试三次仍失败就标记这条任务待补采。
import random
import time
import requests
from requests.adapters import HTTPAdapter
session = requests.Session()
# 连接池大小要和并发数匹配,小了会频繁建连
adapter = HTTPAdapter(pool_connections=40, pool_maxsize=40, max_retries=0)
session.mount("http://", adapter)
session.mount("https://", adapter)
def fetch(url, proxy, retry=3):
"""单次抓取,带超时与退避重试"""
for i in range(retry):
try:
resp = session.get(
url,
proxies={"http": proxy, "https": proxy},
timeout=(5, 10), # 连接5秒,读取10秒
headers={"User-Agent": UA_POOL[i % len(UA_POOL)]}
)
if resp.status_code == 200:
return resp.text
# 429/403 说明被识别,换IP比原地重试更有用
if resp.status_code in (403, 429):
break
except requests.RequestException:
pass
time.sleep((2 ** i) + random.uniform(0, 0.8)) # 退避+抖动
return None
def polite_sleep(base=0.8):
time.sleep(base * random.uniform(0.6, 1.4))
这段代码里没有花哨的东西,但超时、连接池、退避、抖动四样都在。实际跑起来,比"多买点 IP"更能提升成功率。
池子本身的时效,决定了你要不要频繁调参
前面讲的是策略层。但如果你手里的 IP 池本身质量不稳——大量重复、失效快、来源杂——那再怎么调参数也只是在填坑。
判断一个池子够不够用,看三个维度:可用的新鲜 IP 有多少、切换要多久、单 IP 能撑多久。神龙IP是自营机房资源,1000 万+ 纯净 IP 池、200+ 城市精准定位,响应能到 30ms 这个量级——这个数字的意义在于,你换 IP 带来的额外延迟几乎可以忽略,轮换频率就可以放心调高,不用心疼损耗。支持 IKEv2、PPTP、L2TP、SSTP、SOCKS5 几种协议,数据全程加密传输,在需要长期挂着跑的采集任务上不用担心链路的稳定性。
套餐选哪个,看你的任务形态:
如果是大范围的列表页、搜索结果、价格监控这类需要不断换 IP 的场景,动态高级更合适——日更 200 万+ IP,2 到 360 小时的时效可以按任务长度选,6Mbps 峰值带宽应付常规并发没问题。
如果是需要相对稳定出口的重活,比如要维持一段时间的会话、或者把采集和压力测试混在一起跑,动态独享更省心——IP 不与他人共享,10Mbps 峰值,同样支持 2 到 360 小时时效,被"邻居"拖累的概率低很多。
另外提醒一句,做服务器性能压测、多账号内容的 IP 独立管理时,思路和纯采集又不一样:前者看重的是稳定的并发承载,后者看重的是一个账号长期绑定一个出口。别拿一套参数套所有场景。
常见问题
Q:轮换频率调到每次请求都换,为什么成功率反而下降了?
因为每次换 IP 都要重新建连、走一遍认证,链路还没热起来请求就发出去了,握手失败和超时的比例自然升高。同时高频切换会让出口 IP 的行为看起来极度异常,容易被风控标记。建议从每 10-20 次请求换一次开始试,用成功率曲线找到拐点,而不是一上来就拉满。
Q:采集过程中大量 timeout,是代理 IP 不行吗?
先别下结论。把超时时间、并发数、连接池大小三个参数检查一遍,八成能解决。如果参数都合理还是频繁超时,那再看是不是某个地区的节点质量有问题——按地区统计失败率,通常能发现集中在少数几个出口。把失败率高的先剔除,比整体换池子更高效。
Q:需要登录才能看的数据,怎么处理 IP 轮换?
这类任务不要中途换 IP。登录态和出口 IP 是绑定的,换 IP 很可能直接触发重新验证。做法是整段会话固定一个 IP,跑完再释放。如果任务量很大,就按账号维度分片,一个 IP 对应一个账号,批次之间再轮换,这样既保住了会话,也不会让单个 IP 累计请求过多。
Q:动态 IP 的时效选 2 小时还是 360 小时,有讲究吗?
看你一段任务能跑多久。短任务选短时效,IP 换得勤、池子新鲜度高;长任务选长时效,减少中途失效导致的断点。实操上建议略微超过预估任务时长,比如任务大概跑 3 小时,就选 6 小时档,留出重跑和补采的余量,避免跑到一半集体过期。





