如何可靠控制外部爬虫的抓取频率
目标读者:有一定运维或后端经验、负责网站稳定性、日志分析或爬虫治理的同学。
目的:可操作、易复用的指南,涵盖robots.txt
、爬虫行为、以及以 nginx limit_req 的平滑限速方案 为核心的部署、测试与排查流程。文中保留完整可复制的配置与命令,便于直接落地。
目录
-
概览:常见问题与解决思路 -
robots.txt
的作用与限制(实用视角) -
Crawl-delay
的写法与推荐值(可复制示例) -
为什么有时改了 robots.txt
“不管用”?逐项排查清单 -
立刻生效的替代措施:nginx 层面限速(为何可行) -
方案 B:平滑限速完整实现(可直接部署的 nginx 配置) -
参数解释与调优建议(rate / burst / zone / realip) -
部署后的测试与日志观测命令(一步步来) -
与 CDN / 反向代理 的协同注意点 -
常见问题(FAQ)与处理建议(直接回答可能的疑问) -
快速参考模板(robots.txt 示例 + nginx 快速替换块) -
行动清单(3 天内可完成的步骤)
1. 概览:常见问题与解决思路
很多站点管理员遇到的场景类似:某个第三方工具或搜索型爬虫抓得太猛,引发服务器响应变慢或报错。常见处理方式有两类:
-
用 robots.txt
指定爬虫的抓取间隔(Crawl-delay) —— 简单、标准化(但并非所有爬虫都遵守),适合长期友好提示。 -
在服务器层(例如 nginx)做强制限速或退避 —— 立即生效、可控、不会依赖对方是否守规。我们在对话中最终选择“平滑限速(方案 B)”,既能保护服务器也尽量不完全拒绝爬虫访问。
本文主线:先用 robots.txt
做提示;当提示无效或需要立即缓解时,用 nginx 的 limit_req
做平滑限速并保留短突发能力。
2. robots.txt
的作用与限制
-
robots.txt
放在网站根目录(https://你的域名/robots.txt
),是对合规爬虫的“建议与规则”。 -
语法简单,按 User-agent
分段定义规则(Allow / Disallow / Crawl-delay 等)。 -
重要限制: Crawl-delay
并非所有爬虫都支持;有些爬虫在站长工具中提供独立设置;而且robots.txt
的生效不是即时的,通常需要一定时间让对方调整抓取策略。
3. Crawl-delay
的写法与推荐值
基本语法(示例,直接复制放到 robots.txt
):
User-agent: *
Allow: /
User-agent: AhrefsBot
Crawl-delay: 5
User-agent: AhrefsSiteAudit
Crawl-delay: 5
针对性的例子(按爬虫分别控制):
User-agent: AhrefsBot
Crawl-delay: 5
User-agent: bingbot
Crawl-delay: 10
User-agent: Yandex
Crawl-delay: 10
User-agent: *
Crawl-delay: 2
推荐的经验值(供参考):
-
站点资源充足、更新不频繁: 1–5
秒常见且安全。 -
服务器资源紧张或被刷: 10–30
秒可以显著降低并发压力。 -
注意:将 Crawl-delay
设得太大,会降低爬虫覆盖率(如果站点页数多,需要权衡)。
4. 为什么有时改了 robots.txt
“不管用”?逐项排查清单
当你改了 robots.txt
但抓取频率仍高,按下面顺序逐项排查:
-
确认 robots.txt 在公网可访问: curl -I https://yourdomain/robots.txt
,确保返回最新内容(200)。 -
检查是否被 CDN 缓存:如果启用 CDN,需要刷新 CDN 缓存或在 CDN 控制台更新 robots。 -
查看访问日志:在 /var/log/nginx/access.log
中 grep 来访爬虫的 User-Agent,确认真实 UA。 -
UA 字符串匹配问题:有时爬虫 UA 有版本或额外信息,使用 ~*
正则匹配更稳妥(nginxmap
中可以用~*AhrefsBot
)。 -
生效延迟:部分工具需要数小时到 1–2 天来调整抓取速率;若急需降载,采用服务器层措施。 -
防火墙 / 服务器层限流可能覆盖或冲突:验证是否已有更上层的限流策略。
5. 立刻生效的替代/补充方法(为何在 nginx 做更稳妥)
-
robots.txt
依赖对方遵守与延迟;nginx 可以即时控制请求的到达速率。 -
使用 limit_req
+map
可针对特定 UA(如AhrefsBot
)进行平滑限速:允许正常抓取但限制每秒平均请求数,并允许短突发(burst)以减少误伤。 -
在有 CDN 或反向代理时,需确保采用正确的真实客户端 IP(realip)配置,否则限速会按 CDN 节点 IP 生效,达不到目的。
6. 方案 B:平滑限速 — 完整可部署 nginx 配置
把以下
limit_req_zone
放到http {}
范围,把server
段放到你站点的 conf(或整合到现有 server{} 中)。
# ===========================
# 放到 http { ... } 范围内
# ===========================
# 1) 识别 Ahrefs UA(可扩展)
map $http_user_agent $is_ahrefs {
default 0;
"~*AhrefsBot" 1;
"~*AhrefsSiteAudit" 1;
}
# 2) 定义限速令牌桶:按客户端 IP 限速
# zone 名为 ahrefs_zone,存储 10MB 状态,rate 可按需调整(见说明)
limit_req_zone $binary_remote_addr zone=ahrefs_zone:10m rate=1r/s;
# 可选:普通用户的速率区(非必需)
limit_req_zone $binary_remote_addr zone=normal_zone:10m rate=20r/s;
# ===========================
# 放到对应 server { ... } 块内(site conf)
# ===========================
server {
listen 80;
server_name example.com;
# 正常入口: 匹配到 Ahrefs UA 则内部 rewrite 到受限 path
location / {
if ($is_ahrefs) {
# 将请求内部重写到 /__ahrefs_throttle 前缀,保留原始 path
rewrite ^(.*)$ /__ahrefs_throttle$1 break;
}
# 对普通流量也可加一个宽松限速(可选)
limit_req zone=normal_zone burst=30 nodelay;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://backend;
}
# 受限内部 location:只允许内部 rewrite 访问,并对 Ahrefs 应用更严格的限速
location ~ ^/__ahrefs_throttle(.*) {
internal; # 只能被内部 rewrite 访问,外部无法直接请求
limit_req zone=ahrefs_zone burst=5 nodelay;
# 恢复原始 URI 给后端($1 是被捕获的 path)
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_pass http://backend$1$is_args$args;
}
# 可选:用于健康检查或测试
location = /__throttle_test {
return 200 "ok\n";
}
# 其它 location / error_page ... 根据你原有配置保留
}
注意:
proxy_pass http://backend
要替换为你自己的后端 upstream(或原有 proxy_pass),并保留原来的 proxy_set_header 配置以传递真实头。
7. 参数解释与调优建议
下表总结常见取值与含义,供你在生产环境中调整:
参数 | 含义 | 常见起点 | 调整建议 |
---|---|---|---|
rate | 平均允许速率,示例 1r/s 表示每秒 1 次 |
1r/s (起点) |
想更保守改 0.2r/s (相当 1 次 / 5 秒) |
burst | 短时突发允许的额外请求数 | burst=5 |
高突发场景增大,结合 nodelay 决定是否拒绝或排队 |
nodelay | 是否立即拒绝超额请求 | 有(nodelay)则立即拒绝(返回 503) | 去掉 nodelay 会排队等待,不会立刻返回错误 |
zone size | 状态存储大小(10m) | 10m 通常足够 |
大站点并发多,可增大到 20m / 50m |
限速依据 | $binary_remote_addr (按 IP) |
常用 | 若前端有 CDN,请配合 realip 使用真实 IP |
实务建议:
-
初次上线时用保守值(例如 rate=1r/s, burst=5
),观察 24 小时日志再收敛。 -
若发现限速命中过多,检查是否误将正常用户也当成目标(UA 匹配是否过宽或 CDN 未传递真实 IP)。
8. 部署后的测试与日志观测命令
部署前后要做这些检查:
-
测试语法并重载 nginx:
nginx -t && systemctl reload nginx
-
模拟请求(用 curl 验证 UA 行为):
# 普通 UA(应正常通过)
curl -I -A "Mozilla/5.0" http://example.com/
# 模拟 Ahrefs UA(观察是否被内部 rewrite 及限速响应)
curl -I -A "AhrefsBot" http://example.com/somepath
-
实时查看 access log(只看 Ahrefs UA):
tail -f /var/log/nginx/access.log | grep -E "AhrefsBot|AhrefsSiteAudit"
-
检查被限速的响应码(默认超额会得到 503):
# 查看 503 响应示例
grep " 503 " /var/log/nginx/access.log | head
-
如果使用 realip,需要确认 $remote_addr
是客户真实 IP,再观察限速行为是否按预期:
# 在 access_log 中加入 $remote_addr $http_x_forwarded_for $http_user_agent 以便对照
# 示例:修改 log_format 或在现有 log 中查看
tail -n 200 /var/log/nginx/access.log | awk '{print $1, $(NF-6), $(NF-1)}' | grep AhrefsBot
9. 与 CDN / 反向代理 的协同注意点
如果你在 CDN 之后或用 load balancer,常见问题是 $remote_addr
变成了 CDN 节点 IP,导致限速按 CDN 节点维度生效、失效或误判。解决方法(要在 http {}
里设置):
# 简单示例(仅在你知道并信任 CDN 源 IP 范围时使用)
real_ip_header X-Forwarded-For;
set_real_ip_from 0.0.0.0/0; # 建议替换为 CDN 的 IP 段,或列出可信的代理段
小提示:在生产中尽量只把已知 CDN 的 IP 段列为
set_real_ip_from
,不要使用0.0.0.0/0
以免被伪造头欺骗。
10. 常见问题(FAQ)—— 我猜你会问的问题,并直接回答
问:我改了 robots.txt
,为什么爬虫还是不停?
答:可能原因包括 CDN 缓存、UA 字符串不匹配、爬虫需要时间调整,或目标爬虫根本不遵守 Crawl-delay
。查询 access.log、确认 robots.txt 是否可访问是首要步骤。
问:我想立刻把某个爬虫“暂停”,有什么快速方法?
答:临时可在 nginx 中对该 UA 返回 429
或 503
并附 Retry-After
,见我们对话中的“方案 A”。但这是一种短期应急手段,不建议长期使用(会影响对方抓取行为)。
问:限速后会不会影响我的正常用户或流量统计?
答:只要 UA 匹配准确,并且你对 realip 做了正确配置,正常用户不会被误伤。上线后 24–48 小时监控 access_log 和关键页面响应即可确保无误伤。
问:如果我用了 CDN,限速还有效吗?
答:有效性取决于 CDN 是否把真实客户端 IP 传给后端。若没有,你需要在 CDN 层做相应配置或在 nginx 使用 realip 模块并设置可信代理 IP 段。
问:如何判断是否是 Ahrefs 的抓取?
答:在日志中看 User-Agent(例如 AhrefsBot/7.0 (+http://ahrefs.com/robot/)
),也可以在日志里 grep 出完整 UA 并确认是否匹配我们配置的正则。
11. 快速参考模板(便于快速复制粘贴)
robots.txt(快速版)
User-agent: *
Allow: /
User-agent: AhrefsBot
Crawl-delay: 5
User-agent: AhrefsSiteAudit
Crawl-delay: 5
nginx limit_req(关键片段,放到 http{} 和 server{})
(见上文 完整可部署配置,也可直接复制到配置文件)
12. 行动清单(3 天内可完成)
第 1 天
-
检查并确认 https://你的域名/robots.txt
返回最新内容(并检查 CDN 缓存)。 -
在 access_log 中 grep 近期爬虫 UA,确认是否为 AhrefsBot
或其他。
第 2 天
-
将 limit_req_zone
放到http {}
中,把server{}
中的受限 location 部署到测试站或主站(按需)。 -
nginx -t && systemctl reload nginx
,并用 curl 模拟 UA 测试。
第 3 天
-
观察 48 小时日志,微调 rate
与burst
参数,确保服务稳定且爬虫被有效节流。 -
若使用 CDN,确认 realip 设置正确并按 CDN 节点 IP 白名单配置 set_real_ip_from
。
13. 附:可视化参考图(我们对话里的截图)
图示为你之前贴出的 robots.txt 编辑窗口,语法上看起来没问题,但可能存在 CDN 缓存或 UA 未匹配等外部因素导致不生效。
14. 结构化标记(HowTo / FAQ)—— 方便系统采集与调用
下方为可直接插入页面的 JSON-LD(HowTo + FAQ)。如果你不需要前端直接输出,可忽略;如果需要,把它放在页面
<head>
或合适位置。
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "控制特定爬虫抓取频率(robots.txt + nginx 平滑限速)",
"description": "通过 robots.txt 提示及在 nginx 中配置 limit_req 实现对特定爬虫的平滑限速。",
"step": [
{ "name": "确认 robots.txt 可访问", "text": "访问 https://yourdomain/robots.txt,确认内容并排除 CDN 缓存。" },
{ "name": "查看 access.log", "text": "grep 出目标爬虫的 User-Agent,确认真实请求来源。" },
{ "name": "部署 nginx 限速配置", "text": "在 http{} 定义 limit_req_zone,server{} 内对匹配 UA 的请求进行内部 rewrite 到受限 location。" },
{ "name": "测试与监控", "text": "用 curl 模拟请求并观察 access_log,调整 rate 与 burst。"}
]
}
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "为什么改了 robots.txt 抓取频率仍高?",
"acceptedAnswer": {
"@type": "Answer",
"text": "可能被 CDN 缓存、UA 匹配不准、目标爬虫不遵守 Crawl-delay,或需要时间调整。先检查 access.log 并确认 robots.txt 可访问。"
}
},
{
"@type": "Question",
"name": "如何立刻缓解爬虫对服务器的压力?",
"acceptedAnswer": {
"@type": "Answer",
"text": "可在 nginx 层返回 429/503 + Retry-After(应急),或使用 limit_req 做平滑限速(长期推荐)。"
}
}
]
}