最贵的不一定最好——这句话我花了三个月、亏了2000多块钱才真正理解。去年我刚从免费代理转成付费代理时,以为交了钱就万事大吉,结果在学术论文采集项目里翻了三次车。第一次是半夜3点爬虫全挂,因为所有IP同一时段被封;第二次是花了高价买所谓“企业专线”,结果延迟比免费代理还高;第三次是因为地域不对,数据库直接返回403。
后来我逼着自己重新设计了一套城市代理IP调度架构,从顶层到底层全部重写。这套架构现在稳定跑了半年,单日采集量从2万次提升到20万次,封禁率从12%降到了0.3%。今天就拿这个学术爬虫例子,聊聊怎么从零设计一套靠谱的代理调度系统。
为什么学术数据库比电商网站更吃代理调度?
我采集的主要是 IEEE、Springer、CNKI 这几个库。它们的反爬逻辑很有意思:不只看请求频率,还看 IP 段的地域和 ASN。比如 CNKI 有一段时间对非中国大陆IP直接限流,而 IEEE 某些期刊只允许教育网IP访问。免费代理池里混着大量机房IP、被标记的IDC段,一上去就被封。
我最初用付费代理的“全国动态”模式,结果发现不同城市的表现天差地别。以 Springer 为例,我跑了3天做了张对比表:
| 城市 | 平均延迟(ms) | 可用率 | 24小时内封禁次数 |
|---|
| 北京 (电信) | 34 | 98.2% | 7 |
| 上海 (联通) | 41 | 97.5% | 12 |
| 广州 (移动) | 56 | 96.1% | 23 |
| 成都 (电信) | 29 | 99.1% | 2 |
数据很清晰:成都电信延迟最低、封禁最少。但我不能只用一个城市——数据库会记住IP段,连续用成都IP会被拉黑。所以我需要一套能同时管理多个城市代理、自动分配、故障自动转移的调度系统。
调度架构的核心:三层隔离 + 加权轮询
我的最终架构分为三层:
- 资源层:从代理服务商拿到的原始IP列表,按城市、运营商打标签。我用的是蚂蚁代理(mayihttp.com)的API提取,每次提取时指定城市和运营商,返回的IP自带延迟和上次使用时间。
- 调度层:基于加权轮询的负载均衡器,每个目标域名单独配置权重表。比如CNKI我配了北京电信30%、上海联通25%、成都电信45%,因为成都表现好。
- 执行层:每个爬虫worker从调度器拿IP,执行请求后上报结果(成功/失败、延迟、HTTP状态码)。调度器根据反馈动态调整权重。
调度器的核心算法比较简单,但有个关键点:故障转移不只是在失败时切换,还要考虑“准失败”。比如延迟超过5秒或返回403,即使没抛异常,也立即降权并触发切换。代码示意如下:
def select_ip(target_domain):
pool = get_ip_pool(target_domain) # 按域名获取城市IP列表
for ip_info in weighted_random(pool):
if ip_info['last_latency'] < 5000: # 延迟小于5秒
return ip_info['ip']
else:
# 记录准失败,权重减半
decr_weight(ip_info, 0.5)
continue
# 所有IP延迟高?触发熔断,降级到兜底城市
fallback_ip = get_fallback_ip('北京')
alert_team('延迟告警', target_domain)
return fallback_ip
这里有个坑:一开始我的 fallback 是固定写死“北京”,结果有一次北京电信故障,所有请求都转到北京,北京也被打爆。后来改成多级 fallback 链:先选延迟最低的非活跃城市,再不行就随机选一个,最后才告警。
监控告警:不是看失败率,而是看“沉默”
学术爬虫最怕的不是请求失败,而是请求成功但返回空数据。很多数据库的反爬策略是:给一个看起来正常的页面,但论文元数据全是 Null。这种“沉默封禁”普通监控抓不到。
我加了一层内容校验监控:每个请求后检查返回的 JSON 中是否包含预期字段(比如 'title' 是否非空)。如果连续3次返回空标题,自动将该城市IP全部拉入黑名单,并切到备用城市。
另一个关键是城市级的健康度评分。我写了个监控脚本,每5分钟计算每个城市的综合评分:
- 成功率:最近10分钟内200/403/429的比例
- 延迟P95:去掉极端值后的95分位延迟
- 数据完整率:返回有效字段的比例
评分低于阈值时自动触发流量迁移。有一次凌晨两点,CNKI 突然对上海联通段全面封禁(延迟全飙升到10秒+),监控在30秒内检测到,自动切到了成都电信,我第二天起才知道这事。
实测效果:200元 vs 2000元的开销
这套调度系统跑通后,我对比了两种方案:
| 方案 | 日均请求量 | 月费用(元) | 封禁率 | 有效数据占比 |
|---|
| 无调度,只用北京电信(蚂蚁代理动态IP) | 5万 | 150 | 8% | 72% |
| 有调度,多城市加权轮询(蚂蚁代理API提取) | 20万 | 280 | 0.4% | 98% |
多花130元,封禁率降了20倍,有效数据从72%提到98%。说实话我一开始没想到效果这么明显。唯一意外的是蚂蚁代理的HTTP隧道在某段时间不稳定,后来我改用API提取+白名单方式,先拉取一批IP缓存到本地,再通过调度器分发,稳定性提升了不少。
如果你也在做类似的城市代理IP调度,记住这三点:
- 不要迷信“全国动态”——真实的地域差异巨大,必须实测后建立权重表
- 故障转移一定要有“准失败”检测——延迟高、返回空数据比直接断开更隐蔽
- 监控要覆盖数据完整性——404好抓,空白数据才要命
蚂蚁代理(mayihttp.com)的API提取支持按城市、运营商过滤,配合3000万+IP池,足够支撑中小型爬虫。不过建议提取后自己缓存,别每次都实时请求API,否则提取接口本身会成为瓶颈。
这套架构我跑了半年,现在基本不用半夜起床看告警。如果哪天挂了,那肯定是电路问题了。😅