很多人配完 Disallow: / 就以为 AI 爬虫不来了,过一周翻日志发现 GPTBot 的请求一条没少。问题不在配置写错,而在于对 robots.txt 的能力边界有误解。这篇按「先看清现状 → 写规则 → 服务端兜底 → 日志验证」四步走,每一步都给能直接跑的命令。
它是一个放在域名根目录、路径固定为 /robots.txt 的纯文本文件。爬虫在抓取前会来读它,读到之后自行决定是否遵守。
这句话里有三个硬约束:
/blog/robots.txt 无效,爬虫不会去读。noindex,但注意:如果你先用 Disallow 挡住抓取,爬虫就读不到页面里的 noindex,两件事会互相打架。这是最容易踩坑的地方。同一个厂商往往有多个 UA,各自干不同的活,只拦一个等于只关了一扇门。
User-agent | 用途 | 只拦它的后果 |
|---|---|---|
| 内容抓取 | 已抓走的内容不受影响,抓取频率下降但不会归零 |
| 检索与展示 | 页面可能不再出现在相关检索结果里 |
| 用户提问时实时访问 | 用户主动询问时仍然会去抓你的页面 |
| 内容抓取 | 同上 |
| 检索索引 | 同上 |
| Common Crawl 采集 | 拦了只影响这一条上游,其他数据集照旧 |
所以第一件要决定的事不是「拦不拦」,而是「拦哪几个」。常见策略是:
OAI-SearchBot、PerplexityBot、ChatGPT-User,只拦纯训练抓取。Disallow。robots.txt 真正能做到的具体能力只有四项:
Disallow: /checkout/ 这类。这一节比上一节更重要,因为它决定了你要不要做服务端兜底。
Disallow 挡不住「展示」。 页面被引用、被摘要,往往发生在检索层,不发生在抓取层。结论:robots.txt 是「礼貌通知」,服务端才是「门禁」。两者要一起用。
先别急着改配置。先确认两件事:谁在抓、抓了哪些路径。
假设 nginx 用默认 combined 格式,日志长这样:
203.0.113.10 - - [21/Oct/2026:10:00:00 +0800] "GET /blog/post HTTP/1.1" 200 15320 "-" "GPTBot"统计各 AI 爬虫的请求量:
for ua in GPTBot OAI-SearchBot ChatGPT-User ClaudeBot PerplexityBot CCBot Bytespider; do
n=$(grep -c "$ua" access.log)
printf '%-16s %8s\n' "$ua" "$n"
done看 GPTBot 都在抓什么:
# 请求行里的路径,按次数排序
grep GPTBot access.log | awk -F'"' '{print $2}' | awk '{print $2}' | sort | uniq -c | sort -rn | head -20
# 状态码分布
grep GPTBot access.log | grep -oE '" [0-9]{3} ' | sort | uniq -c | sort -rn按天看趋势(日志被切割或压缩过就用 zcat):
zcat access.log.*.gz | grep GPTBot | awk '{print $4}' | cut -c2-12 | sort | uniq -c如果发现某个 UA 集中在 /wp-login.php、/?s= 这类路径,那多半不是真的 AI 爬虫,是扫描器在借 UA。这种直接进下一步的服务端拦截。
先给一个可以直接改的版本:
# 默认放行,搜索引擎正常抓
User-agent: *
Allow: /
Disallow: /wp-admin/
Disallow: /cart/
Disallow: /checkout/
Disallow: /*?s=
# 训练类抓取:整站不抓
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: CCBot
Disallow: /
# 检索类:保留曝光,只挡后台和交易路径
User-agent: OAI-SearchBot
Allow: /
Disallow: /wp-admin/
Disallow: /cart/
Disallow: /checkout/
User-agent: PerplexityBot
Allow: /
Disallow: /wp-admin/
Disallow: /cart/
Disallow: /checkout/
Sitemap: https://example.com/sitemap.xml几个必须注意的点:
Disallow: /wp-content/。CSS、JS、图片都在里面,挡掉之后爬虫拿到的页面是残的,反而更容易被判定为低质量。User-agent 写在连续行里,规则共享。* 和结尾的 $ 大多数爬虫支持,路径中间的通配符支持程度参差。Disallow: /*?s= 这种写法在部分爬虫上不生效,别把它当唯一防线。Allow 和 Disallow 谁更长谁生效。/robots.txt 这个路径本身不能按 UA 拦截。robots.txt 只对守规矩的有效,所以要有一层硬拦截。
用 map 定义变量,再在 location 里返回 403:
map $http_user_agent $aum_ai_bot {
default 0;
"~*GPTBot" 1;
"~*ClaudeBot" 1;
"~*CCBot" 1;
"~*Bytespider" 1;
}
server {
listen 443 ssl;
server_name example.com;
# robots.txt 永远放行,不加任何 UA 判断
location = /robots.txt {
try_files $uri =404;
add_header Cache-Control "public, max-age=3600";
}
location / {
if ($aum_ai_bot) {
return 403;
}
try_files $uri $uri/ /index.php?$args;
}
}注意 if 放在 location 内、只用来 return,这是官方认可的用法;不要在里面写 proxy_pass 之类的指令。如果你的站有多个 location,每个都要加,或者用 limit_req 做统一的速率兜底。
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (GPTBot|ClaudeBot|CCBot|Bytespider) [NC]
RewriteCond %{REQUEST_URI} !^/robots\.txt$ [NC]
RewriteRule ^ - [F]返回 403 是明确拒绝,部分爬虫会就此放弃。不要用「200 + 空内容」——那会让对方以为抓到了空页面,还可能被记成一次成功抓取。流量特别大时用 429 配合 Retry-After 更合适。
所以对高价值路径,再加一层来源校验:把请求 IP 反查到域名,再正向解析一次,确认解析回来的 IP 和原 IP 一致(forward-confirmed 反查)。正经爬虫的 IP 段是公开的,可以拿来做白名单;对不上的一律按普通流量处理。
配完不做验证,等于没配。四条命令,覆盖四个面:
# 1. robots.txt 本体是否正常返回 200,内容是否是你写的版本
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/robots.txt
curl -sS https://example.com/robots.txt
# 2. 带 AI 爬虫 UA 请求 robots.txt —— 应该仍然是 200,不是 403
curl -sS -o /dev/null -w '%{http_code}\n' -A 'GPTBot' https://example.com/robots.txt
# 3. 带 AI 爬虫 UA 请求一个正常页面 —— 走服务端拦截应该是 403
curl -sS -o /dev/null -w '%{http_code}\n' -A 'GPTBot' https://example.com/blog/post
# 4. 普通 UA 请求同一页面 —— 必须还是 200
curl -sS -o /dev/null -w '%{http_code}\n' -A 'Mozilla/5.0' https://example.com/blog/post如果第 3 条返回 200,说明拦截没生效:检查 map 是否写在 http 块里、location 是否真的命中了这个请求、有没有 CDN 在前面把请求吃掉了。
日志侧的验证才是真验证,配置对不代表爬虫行为变了:
# 拦截上线后,被拦截的请求应该出现 403
grep -E 'GPTBot|ClaudeBot' access.log | grep -oE '" [0-9]{3} ' | sort | uniq -c
# 对比上线前后三天的请求量,看是否真的下降
grep GPTBot access.log | awk '{print $4}' | cut -c2-12 | sort | uniq -c判断标准:
200 数量下降,403 数量上升 → 拦截生效。403 持续几天后归零 → 对方已经放弃。403 一直很高、请求量不降 → 对方不遵守,靠服务端扛着,这是预期内的。一次配置不可能一劳永逸,UA 会变、策略会变。想省掉每天 grep 的功夫,可以用 AumCrawl 在 WordPress 后台直接看有哪些 AI 爬虫在抓你的站、分别抓了哪些路径,并按爬虫单独放行或拦截。它是免费的,和上面这套 nginx/Apache 规则可以并存——服务端做兜底,后台做日常观察。
/robots.txt 返回 404,等于告诉爬虫「随便抓」。GPTBot,忘了 ChatGPT-User,用户实时访问照样抓。Disallow 挡了页面,又想靠页面里的 noindex 防索引,结果爬虫读不到 noindex。/wp-content/,页面渲染残缺。Crawl-delay 当限流用,实际不生效。/robots.txt,爬虫读不到规则,反而全放行。map + 403 是成本最低的一层。curl 验四件事,再用日志看 200/403 的比例变化,否则你不知道自己改了什么。更多免费插件和用法可以看 AumCreate 插件列表。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。