如何可靠控制外部爬虫的抓取频率

目标读者:有一定运维或后端经验、负责网站稳定性、日志分析或爬虫治理的同学。
目的:可操作、易复用的指南,涵盖 robots.txt、爬虫行为、以及以 nginx limit_req 的平滑限速方案 为核心的部署、测试与排查流程。文中保留完整可复制的配置与命令,便于直接落地。


目录

  1. 概览:常见问题与解决思路
  2. robots.txt 的作用与限制(实用视角)
  3. Crawl-delay 的写法与推荐值(可复制示例)
  4. 为什么有时改了 robots.txt“不管用”?逐项排查清单
  5. 立刻生效的替代措施:nginx 层面限速(为何可行)
  6. 方案 B:平滑限速完整实现(可直接部署的 nginx 配置)
  7. 参数解释与调优建议(rate / burst / zone / realip)
  8. 部署后的测试与日志观测命令(一步步来)
  9. 与 CDN / 反向代理 的协同注意点
  10. 常见问题(FAQ)与处理建议(直接回答可能的疑问)
  11. 快速参考模板(robots.txt 示例 + nginx 快速替换块)
  12. 行动清单(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 但抓取频率仍高,按下面顺序逐项排查:

  1. 确认 robots.txt 在公网可访问curl -I https://yourdomain/robots.txt,确保返回最新内容(200)。
  2. 检查是否被 CDN 缓存:如果启用 CDN,需要刷新 CDN 缓存或在 CDN 控制台更新 robots。
  3. 查看访问日志:在 /var/log/nginx/access.log 中 grep 来访爬虫的 User-Agent,确认真实 UA。
  4. UA 字符串匹配问题:有时爬虫 UA 有版本或额外信息,使用 ~* 正则匹配更稳妥(nginx map 中可以用 ~*AhrefsBot)。
  5. 生效延迟:部分工具需要数小时到 1–2 天来调整抓取速率;若急需降载,采用服务器层措施。
  6. 防火墙 / 服务器层限流可能覆盖或冲突:验证是否已有更上层的限流策略。

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. 部署后的测试与日志观测命令

部署前后要做这些检查:

  1. 测试语法并重载 nginx:
nginx -t && systemctl reload nginx
  1. 模拟请求(用 curl 验证 UA 行为):
# 普通 UA(应正常通过)
curl -I -A "Mozilla/5.0" http://example.com/

# 模拟 Ahrefs UA(观察是否被内部 rewrite 及限速响应)
curl -I -A "AhrefsBot" http://example.com/somepath
  1. 实时查看 access log(只看 Ahrefs UA):
tail -f /var/log/nginx/access.log | grep -E "AhrefsBot|AhrefsSiteAudit"
  1. 检查被限速的响应码(默认超额会得到 503):
# 查看 503 响应示例
grep " 503 " /var/log/nginx/access.log | head
  1. 如果使用 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 返回 429503 并附 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 小时日志,微调 rateburst 参数,确保服务稳定且爬虫被有效节流。
  • 若使用 CDN,确认 realip 设置正确并按 CDN 节点 IP 白名单配置 set_real_ip_from

13. 附:可视化参考图(我们对话里的截图)

示例 robots.txt 编辑截图
图示为你之前贴出的 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 做平滑限速(长期推荐)。"
      }
    }
  ]
}