所有爬虫一个速率,松了被采集打崩,紧了蜘蛛被限速伤收录。本文用 10 个问答讲清爬虫分级限速的分档模型、Nginx 配额配置、参数怎么定、怎么验证,附可直接复制的命令。
Q:为什么不能给所有爬虫同一个限速?
- 爬虫的价值差别极大:搜索引擎蜘蛛带来收录和流量,AI 训练爬虫只带走内容不回吐流量,工具类爬虫九成是采集。
- 用一个速率档喂所有爬虫,必然两头不讨好:设松了恶意采集拖着源站跑,设紧了蜘蛛被限速、收录慢慢往下掉。
- 分级限速的目的不是「拦」,而是把有限的源站资源按价值分配,谁重要谁多拿。
- 只有单档限速(只盯蜘蛛)也不够:AI 训练爬虫和采集脚本根本不在这一档里,等于漏掉了真正吃资源的那部分。
- 一句话:限速的精度,决定了你既不被抓崩,也不被降权。
Q:爬虫分几档比较合适?
- 四档够用:搜索引擎(Baidu、Google、Bing、搜狗、360)、AI 训练(GPTBot、ClaudeBot、CCBot、Bytespider)、工具与脚本(Scrapy、python-requests、curl、无头浏览器)、其他未知 UA。
- 档位顺序就是配额顺序:引擎档最松,脚本档最紧,未知档居中偏紧。
- 不建议超过四档。档位越多,配额越难解释,出了误伤也难定位是哪一档。
- 档位表必须写进配置注释,标注谁改的、哪天改的,半年后还能看懂。
Q:分档只看 User-Agent 靠得住吗?
- UA 只是个分类标签,不是身份证明,任何人改一行请求头就能写成 Googlebot。
- 分级限速解决「速率怎么分」,不解决「是不是真的」,真伪要靠 IP 段和反向解析校验,那是另一条线。
- 正确顺序是:先按 UA 分档限速(成本几乎为零、立即生效),再对高配额档追加 IP 校验。
- 别指望 UA 黑名单兜底,攻击者把 GPTBot 改成 GPTBot-1.0 就绕过去了,黑名单永远追不上。
Q:Nginx 怎么按档位给不同速率?给份能直接用的配置
- 关键思路:给每一档生成专属限流键,非本档的请求键为空,空键不计数,于是多条
limit_req可以同时挂在同一个 location 上互不干扰。 - 下面的配置分四段:UA 打标签、生成专属键、每档一个 zone、server 块里叠加。
limit_req_status 429必须显式写。默认是 503,会被 CDN 缓存成一张「站点故障」页,误伤所有访客。
# ① http 块:按 UA 打标签
map $http_user_agent $crawler_tier {
default "other";
"~*(baiduspider|googlebot|bingbot|sogou|360spider|yisouspider)" "engine";
"~*(gptbot|claudebot|ccbot|bytespider|perplexitybot|amazonbot)" "ai";
"~*(scrapy|python-requests|aiohttp|go-http-client|headlesschrome)" "tool";
}
# ② 每档生成专属键,非本档的键为空(空键不计入限流)
map $crawler_tier $key_engine { "engine" $binary_remote_addr; default ""; }
map $crawler_tier $key_ai { "ai" $binary_remote_addr; default ""; }
map $crawler_tier $key_tool { "tool" $binary_remote_addr; default ""; }
map $crawler_tier $key_other { "other" $binary_remote_addr; default ""; }
# ③ 每档一个 zone,速率各自独立
limit_req_zone $key_engine zone=cr_engine:10m rate=20r/s;
limit_req_zone $key_ai zone=cr_ai:10m rate=2r/s;
limit_req_zone $key_tool zone=cr_tool:10m rate=1r/s;
limit_req_zone $key_other zone=cr_other:10m rate=5r/s;
# ④ server 块:四条叠加,只有命中本档的那条会生效
limit_req zone=cr_engine burst=40 nodelay;
limit_req zone=cr_ai burst=5 nodelay;
limit_req zone=cr_tool burst=2 nodelay;
limit_req zone=cr_other burst=10 nodelay;
limit_req_status 429;
- 上线前务必
nginx -t,再systemctl reload nginx,不要 restart,restart 会断当前连接。 - 改完先用下面的 curl 复现一遍,别等搜索引擎来告诉你配错了。
Q:burst 和 nodelay 该怎么定?
rate是平均速率,burst是允许的突发队列长度。不带nodelay时请求会排队变慢,带了就直接放行或直接拒绝。- 蜘蛛翻页、sitemap 校验往往在几秒内打出一组请求,burst 给小了会把正常蜘蛛打回去,这是最常见的误伤来源。
- 经验值:引擎档 burst 给 30~50,AI 档 5~10,工具档 2~5,未知档 10 左右。
- 静态站可以全用
nodelay;动态接口建议 AI 档和工具档不加nodelay,让请求排队,避免瞬时打穿数据库连接池。
Q:搜索引擎那一档到底要不要真限速?
- 不要把引擎档当过滤器用,它的限速值应当只做「洪水保险」——正常抓取速率远低于阈值,一旦触发就说明出了问题(伪装 UA,或者站内链接爆炸)。
- 触发时返回 429 而不是 503。两者都会让搜索引擎降低抓取频率,但 429 语义准确,不会被判成宕机,也不容易被 CDN 缓存。
- 给
robots.txt和sitemap.xml单独放行,不参与限速,否则蜘蛛拉不到规则,抓取策略会乱。 - 判断标准很简单:引擎档一周内的 429 条数应当是个位数,上百条就说明阈值定错了。
Q:有人冒充 Googlebot 骗高配额怎么办?
- 这是分档配额最大的漏洞:引擎档配额最高,攻击者只要改个 UA 就能白拿一份高配额。
- 三道补丁:① 引擎档做 IP 段或正反向 DNS 校验,校验不过降级到「其他」档;② 引擎档同样设绝对上限(比如 50r/s),不做无限放行;③ 引擎档单独统计,UA 写着引擎但来源段不对的请求单独计数并告警。
- 校验结果做缓存,别每个请求都去查 DNS,
ngx_http_geo或本地 IP 库文件比在线反查稳。 - 没有校验条件的站点,就把引擎档配额定在「够用但不夸张」的位置,宁可偶尔慢一点,也别开一道免费的加速门。
Q:各档配额到底定多少?给个能算的方法
- 从源站容量反推,不要凭感觉。先用压测拿到「稳定状态下每秒能处理多少动态请求」。
- 把峰值处理能力的 60% 留给真实用户,剩下 40% 按档位比例分配。
- 举例:源站稳定处理 300 QPS,则用户 180、引擎 40、AI 10、工具 5、其他 10,余下 55 作缓冲。
- 扩容或上线大促前重算一次,配额不跟着容量走,等于没定。
Q:怎么验证分档真的生效了?
- 换 UA 复现:同一个 URL,用三个典型 UA 各打 10 次,看返回码分布是否符合预期。
- 看日志分布:按档统计请求量与 429 条数,429 的占比应当集中在紧的那两档,而不是散在所有档。
- 重点盯误伤:429 大量出现在正常搜索引擎 UA 上,说明引擎档太紧,第二天就要调。
- 一周看一次就够,别天天改阈值,改动本身也会带来波动。
# 换 UA 复现:同一 URL 各打 10 次,看返回码
for ua in "Baiduspider" "GPTBot/1.0" "python-requests/2.31"; do
echo "== $ua"
for i in $(seq 1 10); do
curl -s -o /dev/null -w "%{http_code} " -A "$ua" https://www.example.com/
done; echo
done
# 按档统计请求量与 429 占比
awk '{t="other"}
/Baiduspider|Googlebot|bingbot/ {t="engine"}
/GPTBot|ClaudeBot|CCBot/ {t="ai"}
/Scrapy|python-requests/ {t="tool"}
{n[t]++; if($9==429) e[t]++}
END{for(k in n) printf "%-7s 请求 %7d 429 %6d (%.1f%%)\n", k, n[k], e[k], e[k]*100/n[k]}' \
/var/log/nginx/access.log
Q:还有什么补充建议?
- 分级限速挡不住慢速分布式爬虫:每个 IP 一分钟只来一次,永远碰不到阈值,这类要靠会话、指纹、访问路径序列来识别,和速率限制是两套东西。
- 换 IP 池的采集同理,按 IP 限速只能压峰值,压不住总量,还得配合 ASN 或网段维度的统计。
- 把档位配额写进一份配置说明文档,和压测基线放在一起,交接时不用口头解释。
- 最后一句:爬虫分级限速的价值不在「拦掉多少」,而在把资源分给值得的爬虫,好蜘蛛跑得快,坏蜘蛛跑不动。