上个月做竞品内容选题,照例去几个学术库拉论文的引用量和关键词分布。跑了两周,原来那套"换个IP接着跑"的路子突然不灵了——请求头、UA、TLS指纹全对得上,IP也是全新的,照样在第7到9次请求时被丢一个403,而且这个403跟着账号走,换IP也不解除。
跟几个做采集的朋友对了一下,不是我的问题。几家学术数据库在今年陆续把风控从"单IP频次计数"改成了"会话一致性 + 行为指纹"。IP只是其中一个字段了,这才是这次采集翻车的根因。
判断依据变了,IP池大小不再是第一变量
以前的风控逻辑很朴素:一个IP一分钟超过多少次请求就拉黑,换掉就行。现在不一样,一次访问会被拆成十几个信号——TLS握手特征、请求间隔的方差、页面停留时长、翻页路径是否线性。系统算的是一个"像不像人"的概率分。
这意味着什么?你换得越勤,间隔方差越大,反而越像机器。我一开始笃定池子越大越好,把日用量从2万IP加到7万IP,跑了三天,封禁率一点没降,白烧了三天钱。后来改成按会话粘性走,同样的池子,效果立刻不一样。
同一批短效动态IP,只改轮换粒度做的对照:
| 数据库 | 风控类型 | 请求级轮换 | 5分钟粘性 | 30分钟长效 |
|---|
| A 库 | 单IP 60次/分钟 | 1.2% | 1.8% | 2.1% |
| B 库 | 会话一致性校验 | 27.4% | 6.3% | 4.8% |
| C 库 | 账号-IP-设备三元组 | 61.5% | 43.2% | 12.7% |
数字很清楚:频控型的库,短效池随便轮;指纹型的,粘性比数量重要十倍;绑定型的,光换IP没用,得配长效出口加账号策略。
学术库采集场景:我的分层方案和参数
我的实际负载是日更约8万条论文元数据(标题、引用数、作者机构),分布在上述三个库。整套方案按风控类型分了三档,不是一套池子打天下:
- 频控型(A库):短效动态IP,请求级轮换,并发控制在单IP 20次/分钟以内,留三倍余量。0.0022元/IP起的短效池在这个场景最划算。
- 指纹型(B库):隧道代理,会话粘性5分钟,同一隧道内保持UA、Cookie、翻页节奏一致。这里有个坑——粘性隧道必须在5分钟内跑完整条翻页链路,否则会话中途断掉,前面攒的"信任分"全清零,我为此重排过一次任务切分粒度。
- 绑定型(C库):长效出口 + 固定账号,一台机器一个出口,不做轮换,只做限速。
重试逻辑别硬刚,被403后立刻重试是最蠢的做法,等于自己举手。下面这段是我现在跑的版本:
import requests, time, random
TUNNEL = "http://user:pass@tunnel-host:8080" # 5分钟粘性隧道
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."
def fetch(url, retry=3):
for i in range(retry):
try:
r = requests.get(url, proxies={"http": TUNNEL, "https": TUNNEL},
headers={"User-Agent": UA}, timeout=8)
if r.status_code == 200:
time.sleep(random.uniform(1.2, 3.5)) # 压间隔方差
return r.text
if r.status_code in (403, 429):
time.sleep(2 ** i * 10) # 指数退避
except requests.RequestException:
time.sleep(3)
return None
两个细节:间隔随机化的下限不能低于1.2秒,再快B库必触发;退避基数取10秒而不是1秒,因为指纹型风控对"连续被拒后立刻再来"特别敏感。
成本账:分层后单条数据成本砍了一半
老板一度觉得隧道贵,先上了两周纯短效池,结果B库那条线成功率卡在60%上下,业务方天天问选题数据为什么缺一半。后来按上面分层重排,账是这样的:
| 档位 | 单价 | 日用量 | 日成本 |
|---|
| 短效动态(A库) | 0.0022元/IP | 4.2万 IP | 92 元 |
| 粘性隧道(B库) | 16元/天/通道 | 3 通道 | 48 元 |
| 长效独享(C库) | 按天计 | 2 出口 | 36 元 |
合计日成本约176元,日成功条数从3.1万涨到7.6万,单条有效数据成本从0.0041元降到0.0023元,降了约44%。贵的那档反而更便宜,这是我最没想到的一点。
说句实话,这个方案在我们8万条/日的量级够用,如果你要跑千万级,任务切分和出口池的调度得重做,粘性会话的复用率会成为瓶颈。另外隧道这块我用的是蚂蚁代理的粘性通道,16元/天起,实测延迟在10ms上下,三个通道撑B库的翻页链路没出过断流;短效池走API提取,接进现有调度器只改了两行配置。
给同行的判断:先去摸清目标站的风控属于哪一型,再决定池子和轮换粒度。先堆量再调策略,是本末倒置的烧钱方式。具体的接入文档在 mayihttp.com 上,我就不展开念参数了。