
谁在爬你的站
个人站最常遇到的不是"恶意攻击",而是一堆 SEO 数据商 / 采集爬虫在持续抓取:
AhrefsBot、SemrushBot、DataForSeoBot、MJ12bot、DotBot、BLEXBot、ZoominfoBot、Amazonbot、serpstatbot、SeznamBot、Cliqzbot、MauiBot、Barkrowler、Megalodon……
它们对你的站没有 SEO 价值(不会带来流量,也不会提升排名),但会:
- 吃掉带宽(尤其是 5M 小带宽的机器);
- 占用 PHP-FPM worker(回源一次就是一次开销);
- 在访问日志里刷出大量噪音,把真正的问题淹没。
一、两种手段的本质区别
| 手段 | 性质 | 成本 | 有效性 |
|---|---|---|---|
robots.txt 里 Disallow | 声明式 | 极低——爬虫读到之后根本不会发请求 | 只对"守规矩"的爬虫有效 |
| nginx 返回 403 | 强制式 | 每条 URL 仍要回源一次(你花 CPU 去拒绝) | 对伪造 UA 的也有效 |
所以正确做法是两个一起用:
robots.txt负责劝退大部分(成本低、省掉绝大部分请求);- nginx 403 负责兜底不守规矩、伪造 UA 的那些。
二、⚠️ 关键坑:nginx 拦截必须放行 /robots.txt
这是"双保险"里最容易出的错。
如果你在 nginx 里按 UA 一律 return 403,那么爬虫连 /robots.txt 都读不到——它不知道你要求它别抓,只能继续一条条试探。
于是你既没省下请求,又白白浪费了 robots.txt 的作用。这套配置必须成对出现。
对应写法:先按 UA 判定,再给 robots.txt 开一个例外。
set $deny_by_ua 0;
if ($http_user_agent ~* "(DataForSeoBot|SemrushBot|AhrefsBot|MJ12bot|DotBot|BLEXBot|ZoominfoBot|Amazonbot|Megalodon|serpstatbot|SeznamBot|Cliqzbot|MauiBot|Barkrowler|serpstat|SERankingBacklinksBot|SERankingBot)") {
set $deny_by_ua 1;
}
if ($uri = /robots.txt) { set $deny_by_ua 0; } # ← 这一行不能少
if ($deny_by_ua = 1) { return 403; }
用「变量 + 单个
if判最后」的写法,而不是在一个if里堆一串条件——可读性好,也不容易踩 nginxif的嵌套坑。
三、robots.txt 里对应的声明
实体文件(放站点根目录,nginx 会优先命中它、不再进 PHP):
User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Sitemap: https://www.example.com/sitemap_index.xml
User-agent: AhrefsBot
Disallow: /
User-agent: SemrushBot
Disallow: /
# ... 其余爬虫各一段
两个细节:
- 每一段都是独立的
User-agent+Disallow: /,而不是写在一个 User-agent 下面用逗号隔开——robots.txt 的语法不支持逗号列表; Sitemap:那一行要留,别忘了给搜索引擎留指路。
四、名单要保持两边一致
robots.txt 的 UA 分组和 nginx 的正则名单必须对应。不一致的后果是:
- 只在 nginx 拦、不在 robots.txt 声明 → 爬虫一直试探,每条都回源;
- 只在 robots.txt 声明、nginx 不拦 → 伪造 UA 的照样抓。
改名单时两个文件一起改,并在注释里写明"与另一个文件的名单保持一致"。
五、别误伤有用的爬虫
名单里绝对不要加:Googlebot、Baiduspider、bingbot、Bytespider(字节)等。
一个实用的自检习惯:改完名单,用真实 UA 测一遍:
# 期望 403
curl -sk -o /dev/null -w '%{http_code}\n' -A 'AhrefsBot/7.0' https://www.example.com/
# 期望 403
curl -sk -o /dev/null -w '%{http_code}\n' -A 'SemrushBot' https://www.example.com/
# 期望 200 ← 这条错了就是误伤
curl -sk -o /dev/null -w '%{http_code}\n' -A 'Mozilla/5.0 (compatible; Googlebot/2.1)' https://www.example.com/
# 期望 200 ← robots.txt 必须能读到
curl -sk -o /dev/null -w '%{http_code}\n' -A 'AhrefsBot/7.0' https://www.example.com/robots.txt
最后一条是最关键的验收点。
六、回滚
删掉 nginx 那段(或整个独立配置文件)→ nginx -t && nginx -s reload。robots.txt 是实体文件,删掉即恢复 WordPress 动态输出。
一句话总结:对付采集爬虫要"声明 + 强制"两条腿——robots.txt 让守规矩的别来,nginx 403 拦住不守规矩的;但nginx 拦 UA 时必须放行 /robots.txt,否则爬虫读不到你的声明,只会继续试探。

评论 (0)