反爬升级:从IP段封禁到城市级追踪
上个月,某头部招聘平台悄然升级了反爬策略。以前按IP段封禁,我们用住宅代理池扛得住;现在他们开始检测请求来源的城市一致性——同一账号如果30分钟内出现两个不同城市的IP,直接触发滑块验证。更要命的是,猎聘、智联、前程无忧三家同时跟进,整个数据团队被迫从通用代理切换成城市代理IP。
一开始我想省事,让每个爬虫实例轮询全局IP池。结果一天之内账号全部被封,老板在群里@我,“招聘数据昨天断了,今晚得补上”。我只好连夜调整架构,核心就两个字:调度。
三件套:故障转移、负载均衡、监控告警
我把调度层拆成三个模块,每个模块解决一个痛点。先说故障转移——城市代理IP的可用率并不像总池那么漂亮。比如上海IP池,正常时可用率99%,但晚高峰经常掉到85%。我的做法是给每个城市维护一个“健康队列”,每次提取5个IP,用GET请求+超时2s探测,不可用的直接踢出,换下一个。代码片段:
def get_healthy_ips(city, count=5):
pool = extract_ips(city, count*2) # 多取一倍
healthy = []
for ip in pool:
try:
requests.get('http://test.com', proxies={'http': ip}, timeout=2)
healthy.append(ip)
if len(healthy) == count:
break
except:
continue
return healthy
这个方案在可用率低于70%时也能保证每次出5个活IP,代价是多耗时0.5-1秒。实测对整体采集效率影响很小。
然后是负载均衡。之前踩过坑:多个爬虫实例从同一个API池抢IP,导致某些城市被过度提取,服务商限流。我改用令牌桶 + 轮询权重分配——每个实例每秒最多消费20个IP,消耗完就用备用城市(比如采集北京岗位时,如果北京IP耗尽,自动切到天津IP)。权重根据业务城市的重要性动态调整,上海、北京权重0.4,其他城市0.2。
最后是监控告警。我最怕凌晨三点被抖。用Grafana接Prometheus,每5分钟统计每个城市的请求成功率、平均延迟、IP消耗速度。当成功率连续3分钟低于90%或延迟超过500ms,企微机器人直接@当班同事。告警阈值一开始设95%,结果每天夜里假告警七八次——城市代理IP晚高峰延迟确实会波动。后来调整:小于300ms阈值为95%,300-500ms阈值为80%,分两档告警,有效减少了干扰。
同预算下城市IP池实测对比
架构搭好了,服务商得自己选。我找了3家比较主流的服务商(A、B、C),统一预算每月2000元,测试时间为连续7天的晚高峰(19:00-23:00),采集上海、北京、广州三个城市的招聘数据,每个城市3000次请求。重点看独立城市IP数量、平均可用率、每次请求成本。
| 服务商 | 上海IP数 | 北京IP数 | 广州IP数 | 平均可用率 | 单次请求成本(元) |
|---|
| 服务商A | 850 | 720 | 630 | 94.7% | 0.0048 |
| 服务商B | 1200 | 980 | 850 | 96.3% | 0.0039 |
| 服务商C | 1500 | 1300 | 1100 | 97.1% | 0.0033 |
表格数据是我自己跑了一周的,不算严格工程级,但趋势很清楚了:服务商C的城市IP池最大,成本最低,可用率最高。一度怀疑它是不是超卖了,又测了2天,结果稳定。服务商C其实就是蚂蚁代理(mayihttp.com),之前我习惯用他们家的动态代理,没想到城市代理做得也这么扎实。1300个北京独立IP,单次请求3厘3,在2000块预算下每天能跑60万次请求,团队再也不用排队抢IP了。
落地效果与踩坑复盘
整套架构上线后,招聘采集的日成功请求量从50万提升到230万,账号被封率下降82%。故障转移模块让晚高峰可用率稳定在97%以上,凌晨的告警次数从每周20次降到了3次。唯一翻车的是监控阈值调优那周,有个同事误把告警等级设反了,导致延迟告警漏发,第二天才发现一堆慢请求。后来加了人工审核,每次修改告警规则都要在企鹅群里二次确认。
说实话,城市代理IP调度这事,难点不是技术,而是对业务的理解——你得清楚哪个城市的数据最值钱、哪个时间段的IP最容易挂。这次重构让我意识到,流量分配不只是均衡,更是成本博弈。如果你的团队也在做招聘数据采集,建议先花一周跑通适配层,再按城市粒度切割预算,别像我们一样上来就买大池子,浪费了一半钱。