很多站长在日志里按官方 IP 段放行「蜘蛛」,结果发现带宽和 CPU 照样被拉满。本文用 9 个问答讲清 蜘蛛IP段被租用与代理滥用的真实原因、假蜘蛛的三步验证法、Nginx 只限可疑爬虫的配置写法、行为层识别指标,以及误伤真蜘蛛时怎么分级放行。
Q:我按官方蜘蛛 IP 段放行了,为什么还是有假蜘蛛进来?
因为 IP 段只能证明「这台机器归属哪个机房」,不能证明「这个请求来自搜索引擎的抓取队列」。三个常见原因:
- 反向解析被冒用:PTR 记录由 IP 持有者自行配置,任何人都能把自己的 IP 反解写成看起来像官方的域名。只查 PTR 不做正查回验,等于没有验证。
- 同 ASN 相邻段被租用:爬虫代理服务商大量租用云厂商与 IDC 的机器,这些机器与搜索引擎抓取出口处在同一个大 ASN 下。用「放行整个 ASN」的策略,等于把这一整片都放进来。
- 云段承载抓取:部分搜索引擎已公开说明其抓取会使用云服务段。于是「云厂商段」既可能是真蜘蛛,也可能只是花钱租来的爬虫,这类来源无法靠 IP 单独定性。
结论很明确:IP 段放行只能作为第一层筛选,不能作为唯一判据。真正的判据要落在「谁来访问」加「怎么访问」两条线上。
Q:验证假蜘蛛的正确顺序是什么?
三步,顺序不能颠倒,因为成本从低到高:
- 第一步 UA 粗筛:UA 里声明是蜘蛛的先挑出来。这一步最便宜,但 UA 可随意伪造,只能用来分组。
- 第二步 rDNS 正查回验:先反查 IP 拿 PTR 域名,再把域名正查解析,看是否指回同一个 IP。
- 第三步 IP 段与 ASN 比对:把 IP 与官方公开段、已知云段做比对,划分「真蜘蛛、疑似代理、纯爬虫」三类归属。
IP=203.0.113.10
# 1) 反查得到 PTR 域名
PTR=$(dig +short -x $IP | sed 's/\.$//')
echo "PTR=$PTR"
# 2) 正查回验:解析必须指回同一个 IP,否则 PTR 是伪造的
dig +short $PTR | grep -qx "$IP" && echo "rDNS OK" || echo "rDNS 伪造或缺失"
# 3) 取 ASN 与归属
whois -h whois.cymru.com " -v $IP" | tail -1
一个容易被忽略的细节:正查回验必须匹配到同一个 IP。很多站长只执行第一步拿到 PTR 就认定「是官方蜘蛛」,这正是被绕过的地方。
Q:官方蜘蛛 IP 段列表怎么维护和自动更新?
不要手工抄。Google 与 Bing 都提供机器可读的段列表,写成定时任务每日更新,再生成 Nginx 与 ipset 两套数据:
# 每日更新:Googlebot 官方段(JSON 格式)
curl -s https://developers.google.com/static/search/apis/ipranges/googlebot.json \
> /tmp/g.json
# 校验内容非空再替换,避免拉取失败清空白名单
test -s /tmp/g.json && cp /tmp/g.json /etc/engine/googlebot.json
# 生成 ipset 网段集合
ipset create engine_v4 hash:net -exist
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]+' /etc/engine/googlebot.json \
| while read cidr; do ipset add engine_v4 $cidr -exist; done
# 生成 Nginx geo 段
{ echo "geo \$is_engine_ip {"; echo " default 0;";
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]+' /etc/engine/googlebot.json \
| while read cidr; do echo " $cidr 1;"; done; echo "}"; } > /etc/nginx/conf.d/engine_ip.conf
nginx -t && nginx -s reload
注意两点:百度官方没有提供机器可读的段文件,只能按其公开说明页人工维护并定期复核;更新时先校验再覆盖,否则某次拉取失败会把白名单清空,真蜘蛛立刻被限速。
Q:Nginx 里怎么做到只限可疑爬虫、放行真蜘蛛?
核心技巧是让白名单拿到空 key。Nginx 对空 key 的请求不计入 limit_req 统计,于是可以用同一个限速 zone 实现「只限爬虫、不限用户」:
# http 段
map $http_user_agent $limit_key {
default $binary_remote_addr;
"~*(Baiduspider|bingbot|Googlebot)" ""; # 空 key = 不计入限速
}
map $http_user_agent $loggable {
default 0;
"~*(python-requests|scrapy|Go-http-client|curl)" 1;
}
limit_req_zone $limit_key zone=crawler:20m rate=3r/s;
server {
limit_req zone=crawler burst=20 nodelay;
limit_req_status 429;
# 可疑 UA 单独落盘观察,不阻断
access_log /var/log/nginx/crawler.log combined if=$loggable;
}
三个要点:白名单只免拦截不免限速,否则被滥用的蜘蛛段会直接打穿源站;先给足 burst 再逐步收紧,避免真蜘蛛因瞬时并发被 429;UA 白名单不能写太宽,只匹配官方蜘蛛标识,不要写 ~*bot 这种一网打尽的规则。
Q:IP 段和 UA 都能伪造,还有什么更硬的判据?
行为层。这一层最难伪造,因为要伪装就得真的按真人方式访问,成本立刻上升。四个高区分度特征:
- 只拉动态接口、不拉静态资源:正常访客必然请求 CSS、JS、图片;纯采集脚本往往只请求 HTML 或接口。
- 不读 robots.txt、不留 Cookie:真蜘蛛会读 robots 并遵守抓取间隔,很多采集器直接跳过。
- 单 IP 匀速高并发:真人访问有停顿、有跳转,脚本请求间隔几乎恒定。
- 请求顺序与站内链接结构无关:采集器按 ID 顺序遍历,不按页面上的链接走。
# 集合差法:只拉静态资源、从不访问首页的 IP
awk '{print $1, $7}' access.log | grep -E '\.(css|js|jpg|png|webp)$' \
| awk '{print $1}' | sort -u > static_only.txt
awk '{print $1, $7}' access.log | grep -E '^[^ ]+ /$' \
| awk '{print $1}' | sort -u > visited_home.txt
comm -23 static_only.txt visited_home.txt | head -20
# 反向:只拉 HTML、从不拉静态资源的 IP
comm -13 static_only.txt visited_home.txt | head -20
实践中把「蜘蛛段 + UA 白名单 + 行为特征」做成加权判断,比任何单一规则都可靠。判定线建议两条:行为特征命中两项以上即降速,命中三项且不属于官方段则直接封禁。
Q:真蜘蛛被误伤导致收录掉了怎么办?
防误伤的本质是「分级处置」而不是一刀切。建议按信任度分三档:
- 黑名单:确认的爬虫代理段与已知恶意 UA,直接 403 或丢弃。
- 灰名单:可疑但可能误伤的来源,只降速不封禁,降到正常配额的 1/3 观察 24 小时。
- 白名单:官方段且行为正常的蜘蛛,免拦截但要给低配额限速,并保留独立日志。
两条操作红线:不要整段封 ASN,云厂商的大 ASN 里往往同时有真蜘蛛、你的正常用户和其他服务;调整规则前先导出当前白名单备份,误封后能秒级回滚。真要封,只封具体 /24 甚至单个 IP。
Q:确认的爬虫代理段怎么封效率最高?
用 ipset 聚合网段并带超时自动解封,避免把 iptables 规则集写爆:
# 建立网段黑名单,默认 24 小时自动过期
ipset create crawler_block hash:net timeout 86400 -exist
iptables -I INPUT -m set --match-set crawler_block src -j DROP
# 按 C 段聚合封禁
awk '{split($1,a,"."); print a[1]"."a[2]"."a[3]".0/24"}' access.log \
| sort | uniq -c | sort -rn | head -50 | awk '{print $2}' \
| while read net; do ipset add crawler_block $net -exist; done
# 确认命中
ipset list crawler_block | tail -5
要点:优先封 /24 而不是单个 IP,轮换 IP 的爬虫单封 IP 没有意义;务必带 timeout,云段可能被再次分配给别的客户,长期封禁会积累误伤;封禁清单要能一键清空,应急时不要只有加没有减。
Q:怎么量化「蜘蛛流量里到底有多少是假的」?
三个数就够,做成日报持续看:
- 蜘蛛请求占比:正常站点通常在 5% 到 15%,长期超过 40% 说明有批量采集顶着蜘蛛的名义在跑。
- 蜘蛛段内独立 IP 数:官方段内出现的 IP 数量应相对稳定。突然从几百涨到几万,基本可判定段被大规模租用。
- 每 IP 平均请求数:真蜘蛛单 IP 请求数低而分散,采集器大量请求集中在少数 IP 上。
# 蜘蛛流量占比与段内 IP 数(以 Baiduspider 为例)
total=$(wc -l < access.log)
spider=$(grep -c "Baiduspider" access.log)
echo "占比: $spider / $total"
grep "Baiduspider" access.log | awk '{print $1}' | sort -u | wc -l
把这三个数接到日报里,就能在带宽真正被打满之前发现异常。这个动作成本很低,收益比事后救火高得多。
Q:还有什么补充建议?
- robots.txt 不是防护工具,它只对守规矩的爬虫有约束力,恶意采集器根本不读。
- sitemap 是抓取面清单,把 sitemap 拆细、只留规范 URL,能减少被系统遍历的参数页数量。
- 静态资源交给 CDN,爬虫拉图片时消耗的是 CDN 带宽,源站压力会下降一个量级。
- 验证逻辑要写在 WAF 或 Nginx 层,不要放在应用里每次请求都做 DNS 查询,否则验证本身就是性能瓶颈。rDNS 结果必须带缓存。
一句话总结:蜘蛛 IP 段是「机房归属」的证明,不是「抓取意图」的证明;把 IP、UA、行为三层叠加,再配分级处置,才能在放行真蜘蛛的同时挡住借名行事的爬虫。