先把结论放在前面:这项研究统计的是,在所有屏蔽了 GPTBot 的网站里,有 57% 的网站没有屏蔽 ChatGPT-User 爬虫。 也就是说,站长以为自己在 robots.txt 里拒绝了 OpenAI 的抓取,实际上只是挡住了一部分,另一条通道仍然开着。这个问题的技术点不算复杂,但它暴露了一个非常典型的配置习惯:只写了一条 User-agent 规则,却没有按爬虫身份一一处理。如果你正在维护网站、管理服务器,或者给客户做站点优化,这篇文章会帮你把爬虫控制这件事彻底理清楚。
这类配置问题最坑的地方在于:它不会直接报错,也不会让网站无法访问。你看到的只是搜索引擎爬虫、AI 爬虫和其他抓取工具按照 robots.txt 各自进出,但只要有一条规则写漏了,政策上想挡的人就还在悄悄访问站点内容。下面我按实际排查的顺序拆开讲。
1. 先确认一个前提:GPTBot 和 ChatGPT-User 是两个不同的 User-agent
1.1 它们各自负责什么任务
很多人会把 GPTBot 和 ChatGPT-User 当成同一个爬虫,这是最常见的误解来源。
GPTBot 是 OpenAI 用于抓取公开网页内容的爬虫,抓取到的内容主要用于训练大语言模型。它的标识字符串是:
code复制GPTBot
ChatGPT-User 虽然名字里也带 ChatGPT,但它的工作方式不同。它是用于支持 ChatGPT 中的“浏览功能”的爬虫,也就是用户通过 ChatGPT 发起浏览请求时,OpenAI 的服务器会以 ChatGPT-User 的身份去访问你网站的内容,然后把内容返回给用户对话。它的标识字符串是:
code复制ChatGPT-User
这两者的“使用场景”不一样:一个偏向后台训练抓取,一个偏向实时浏览问答。对应的 robots.txt 控制诉求也不一样——你可能希望训练抓取被屏蔽,但不一定想屏蔽浏览功能;反过来,如果你对网站内容有严格的使用授权要求,两条都应该统一控制。
关键在于:robots.txt 的规则是按 User-agent 独立匹配的,不是按公司维度匹配的。 你写了一条针对 GPTBot 的规则,它只对 GPTBot 生效,不会自动对 ChatGPT-User 生效。
1.2 robots.txt 是怎么匹配身份的
robots.txt 是网站通过 HTTP 接口暴露给爬虫的一份文本文件,通常放在域名根目录下。爬虫在抓取网站之前,会先请求这个文件,然后根据里面的规则决定抓哪条路径。
匹配的核心逻辑有几点:
- 不区分大小写,
gptbot、GPTBot、GptBot在匹配时视为相同 - 每条 User-agent 声明开始一条规则组,后续的 Allow 和 Disallow 只作用于当前组
*表示匹配所有没有明确声明的爬虫- 更具体的 User-agent 规则优先于通配规则
很多网站在写配置时,只写了这样一段:
txt复制User-agent: GPTBot
Disallow: /
这段规则的含义是“禁止 GPTBot 抓取整个站点”。它确实生效了,但它不会阻止 ChatGPT-User。因为 ChatGPT-User 是另一个 User-agent,匹配不到 GPTBot 这一组。
如果 robots.txt 里只有这一段,那么 ChatGPT-User 会继续访问全站,而且它不会因为 GPTBot 的规则被拒。对网站来说,这就是一条没关上的门。
注意:robots.txt 本身是一种“君子协议”,它依赖爬虫程序的自觉遵守,不是强制访问控制。真正要做数据防护,还需要考虑额外的鉴权、IP 限制或服务端验证。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 为什么屏蔽 GPTBot 时很容易漏掉 ChatGPT-User
2.1 只看文档名称带来的错觉
OpenAI 的爬虫文档里,GPTBot 出现频率最高,讨论也最多。很多人看到官方说明后,第一反应就是“屏蔽 GPTBot”。如果用的是 WordPress、Shield Security、Cloudflare 的规则模板,很多模板里也只写了 GPTBot 这一条。
于是问题就出现了:站长认为“已经屏蔽了 AI 爬虫”,但从 robots.txt 的角度看,只是“屏蔽了名为 GPTBot 的 User-agent”。一旦别的工作人员把 ChatGPT-User 看成 GPTBot 的同义词,这条规则就会漏掉。
实测时我一般会先做一个动作:直接拉取网站根目录的 robots.txt,然后用爬虫模拟工具分别以 GPTBot、ChatGPT-User 的身份去请求一次网站首页,看返回状态。这个方法不需要任何特殊工具,几分钟能完成。
但更关键的是养成一个习惯:凡是涉及爬虫控制,先把 User-agent 列表整理出来,再决定放行和拒绝名单。 不要按公司名去记忆,要按具体的 User-agent 字符串去配置。
2.2 通配规则与精确规则同时存在时的优先级
还有一类网站,robots.txt 里既有通配规则,也有精确规则。常见写法是:
txt复制User-agent: *
Disallow: /private/
User-agent: GPTBot
Disallow: /
这段配置想要表达的是:默认情况下只有 /private/ 目录不允许抓取,其他路径正常;但 GPTBot 被禁止访问全站。
如果在这段配置里没有加:
txt复制User-agent: ChatGPT-User
Disallow: /
那么 ChatGPT-User 会落到哪一组里?
因为 GPTBot 那组是精确匹配,ChatGPT-User 匹配不到,所以它会被 User-agent: * 的规则接管,也就是只能看到 /private/ 被禁止。也就是说,整个站点的公开部分它都可以访问。
57% 这个数字能说明的问题就在这里:它不是说 57% 的网站完全没有控制 AI 爬虫,而是说有一大部分站长做了“看似完整”的屏蔽,实际只覆盖了一半。这类半数级遗漏,往往不是技术能力不足,而是配置思维停留在了单条规则上。
2.3 第三方服务也不会自动帮你补齐规则
另一个常见的误区是:使用了 CDN、防火墙、安全插件,就以为它会自动处理新的 AI 爬虫。
实际上,CDN 或安全插件能做的主要是提供预设规则模板、拦截已知恶意 IP、对特定 User-agent 做节点级限制。如果预设模板没有包含 ChatGPT-User,它不会自动补齐 robots.txt。换句话说,第三方服务能辅助你执行规则,但“规则本身由谁声明”仍然要你自己确认。
所以我在国内的项目里做爬虫管控时,不会依赖某个安全插件的默认开关,而是会直接把规则写进服务器配置文件或 robots.txt,并留一个可更新的爬虫清单文件。这样做的好处是:出问题时追查链路短,换服务器或迁站时规则也不容易丢失。
3. 正确的屏蔽与放行配置:按身份逐个写清楚
3.1 基础配置:明确拒绝指定的 User-agent
先明确需求:如果网站不希望 GPTBot 和 ChatGPT-User 访问任何路径,那么 robots.txt 中的配置不能只写一个 GPTBot。
标准写法可以这样:
txt复制User-agent: GPTBot
Disallow: /
User-agent: ChatGPT-User
Disallow: /
这段配置会把两个爬虫都挡在全站路径之外。
如果你还想挡住其他 AI 爬虫,比如 Google 的 Google-Extended、Common Crawl 的 CCBot,需要按同样的方式追加规则:
txt复制User-agent: Google-Extended
Disallow: /
User-agent: CCBot
Disallow: /
这一点容易变成“无底洞”,因为新的 AI 爬虫在不断出现。所以更值得建议的是:建立一个自己的爬虫管理清单,定期更新,而不是每次看到新爬虫才想起来补规则。
3.2 中间方案:允许浏览引用,但禁止全文训练
有些网站愿意在 ChatGPT 的浏览功能里被引用,但不希望自己的内容被拿去训练模型。这个需求在 robots.txt 层面可以实现。
配置思路是把 GPTBot 和 ChatGPT-User 分开处理:
txt复制User-agent: GPTBot
Disallow: /
User-agent: ChatGPT-User
Allow: /
这样写的意思是:GPTBot (训练抓取)被禁止访问全站;ChatGPT-User(用户浏览功能)可以访问全站。这样 ChatGPT 用户在对话中需要引用当前页面时,网站内容仍然能被读取。
不过需要注意:robots.txt 只能表达“是否允许抓取”,不能授权其他形式的传播与再利用。即使开通了 ChatGPT-User 的访问,引用后的内容展示方式仍然由 OpenAI 的产品逻辑决定,网站方无法在 robots.txt 里再做精细化控制。
如果你想做更细的限制,比如在某个目录下放行、在另一个目录下拒绝,可以这样写:
txt复制User-agent: ChatGPT-User
Allow: /public/
Disallow: /private/
按我的经验,实际项目中“全部禁止训练抓取,但允许浏览引用”的诉求是比较多的。特别是内容型网站和知识库站点,站长既想留在搜索结果和聊天浏览里,又不想被无成本地批量训练。这个方案是可行的,但它要求你先分清楚两个爬虫的身份,而不是一刀切。
3.3 名称变更和系统日志中的真实标识
还有一个细节:爬虫的 User-agent 可能会随着产品迭代变化。有的服务会在请求头里带多个标识,有的会带版本号。你在日志里看到的可能是:
code复制GPTBot/1.0
Mozilla/5.0 AppleWebKit ...
robots.txt 匹配时不会管版本号,只要基础名称匹配即可。但如果你在服务器日志分析工具里搜索 “GPTBot” 时用了严格匹配,可能漏掉大小写变化或带额外路径参数的记录。排查日志时建议用模糊匹配,先看完整请求头,再决定如何归类。
另外,OpenAI 官方文档里还出现过 OAI-SearchBot 等爬虫名称。如果站点对内容使用有比较严格的要求,建议不要只维护两个名称,而是把官方公布的所有爬虫列表都纳入管理。不过,这个列表变化的频率并不高,普通站点按月或按季度维护一次就可以了。
4. 配置之后必须做的验证与排查
4.1 先看当前的 robots.txt 是否被正常加载
维护爬虫控制的第一步,不是修改,而是先看现状。
查看方法很简单,用浏览器访问:
code复制https://你的域名/robots.txt
也可以用命令行请求:
bash复制curl -I https://你的域名/robots.txt
curl https://你的域名/robots.txt
需要确认三点:
- 是否能返回 200 状态码
- 是否返回了完整内容,而不是被 CDN 误拦截后的错误页
- 内容编码是否正确,乱码会导致某些爬虫解析异常
如果 robots.txt 本身无法访问,爬虫通常会按照“没有声明任何规则”来处理,这时候你想屏蔽的 GPTBot 和 ChatGPT-User 都可能畅通无阻。这个前提经常被忽视:很多人改了半天规则,却不知道 robots.txt 在服务器上根本没有生效,要么是路径错了,要么是被安全策略拦截了。
4.2 用模拟请求观察不同身份的实际结果
验证规则是否生效,最直接的方法是模拟两个 user-agent 分别请求你的域名。
你可以用命令行工具测试:
bash复制curl -A "GPTBot" -I https://你的域名/
curl -A "ChatGPT-User" -I https://你的域名/
需要注意的是:robots.txt 只对遵守规范的爬虫有效,它不会返回 403 状态码。如果服务器本身对特定 User-agent 做了访问控制,可能返回 403;如果在 robots.txt 层拒绝,那么爬虫会依据 Disallow 规则自行决定放弃抓取,但 HTTP 状态码依然是 200。
所以模拟验证时,不能只看 HTTP 状态码,还要看内容是否能被正常获取。更完整的验证方式是:
- 先请求 robots.txt,确认你对 GPTBot 返回的是
Disallow: / - 再请求网站首页,确认页面内容正常返回
- 把 User-agent 切换到 ChatGPT-User,再请求首页
- 对比返回结果和响应头
如果页面内容直接返回给了 ChatGPT-User,说明当前配置没有挡住它。如果服务端配置了额外的 User-agent 拦截,可能返回 403 或 444,这时说明节点层做了限制,但不是 robots.txt 的功劳。
4.3 通过服务器访问日志验证抓取记录
如果你不确定配置是否已经生效,可以观察服务器访问日志。常见日志路径包括:
code复制/var/log/nginx/access.log
/var/log/apache2/access.log
在日志里搜索关键词:
bash复制grep -i "GPTBot" /var/log/nginx/access.log | tail -n 20
grep -i "ChatGPT-User" /var/log/nginx/access.log | tail -n 20
重点看两个维度:
- 配置修改后是否还有新的请求出现
- 如果有请求,看看请求了哪些路径,是首页、目录页还是具体文章页
需要注意,访问日志里显示的 User-agent 不一定完全和 robots.txt 里的名称一致,有的会带版本号或额外的注释信息。例如实际请求头可能是:
code复制User-Agent: GPTBot/1.0 (+http://openai.com/gptbot)
所以用 grep 搜索时,建议用模糊匹配:
bash复制grep -i "OpenAI" /var/log/nginx/access.log | tail -n 50
这里的思维是:不要只看某一个字符串,而是要按“来源公司特征词”来归组。因为 OpenAI 系爬虫在不同产品下可能有不同的 User-agent 名称,但它们的特征词通常是可以归类的。
在实际排查时,我一般会分三步走:
- 先查 robots.txt 文件当前内容,确认规则有没有漏写
- 再用模拟请求测试两条身份,确认规则逻辑是否符合预期
- 最后看最近一两天的访问日志,确认真实抓取记录是否已经停止或减少
按这个顺序做,能快速定位问题到底出在“规则没写”还是“规则写了但没生效”。
5. 这个配置问题的真正边界:别把误伤当防护
5.1 不要因为怕 AI 抓取就关掉所有正常爬虫
当发现网站被 AI 爬虫抓取时,有人会把手动规则写成:
txt复制User-agent: *
Disallow: /
这确实能把绝大多数爬虫挡在外面,但也会把搜索引擎的正常抓取全部禁止。对普通内容站点来说,这意味着页面无法出现在 Google 或百度搜索结果里。对于依赖自然流量的业务,这不是一个可接受的代价。
更合理的做法是:不要使用全局禁止,而是按爬虫名单单独屏蔽。把通配规则用来控制“默认行为”,把需要禁止的爬虫用精确规则覆盖。
5.2 robots.txt 不解决服务端鉴权和数据保护
再强调一遍:robots.txt 是爬虫礼貌约定,不是安全机制。对于不希望被抓取的内容,正确的做法是同时叠加服务端控制。
比如:
- 私密页面放在需要登录的目录下
- 敏感接口做鉴权和签名
- 对已知爬虫 IP 段做访问频率限制
- 对外部 AI 服务做单独的风控策略
这些才是在 robots.txt 之外真正能兜住数据的措施。如果你发现 ChatGPT-User 在配置之后仍然访问到受限页面,可能问题不在 robots.txt,而是页面本身的权限控制没有生效。
这点容易被忽略,因为很多网站部署时只有一层防护——靠 robots.txt 来决定一切。一旦爬虫不遵守规则,或者请求来自非标准 User-agent,防护就等于没有了。把规则和资源权限分开设计,才是更稳的结构。
5.3 检查配置时的几个常见误判
实际维护中容易出现的误判有好几类,我列一下:
第一,认为规则顺序越靠前越优先。robots.txt 的实际逻辑是按 User-agent 匹配,再按路径匹配。对于路径匹配,Allow 和 Disallow 的优先级在不同爬虫实现上有差异,不能想当然。
第二,认为同一条规则可以管住所有子路径。如果写的是:
txt复制Disallow: /api
那么 /api 和 /api/versions 都会被禁止,但 /notapi 不会被禁止。路径匹配不是按目录深度来限制的,它匹配的是路径前缀。
第三,认为“不做任何配置等于默认允许所有爬虫”。对大多数爬虫来说,没有声明规则确实等于允许抓取。但也有少数爬虫可能使用自己的一套策略,或者完全无视 robots.txt。所以评估抓取风险时,永远要把服务端访问控制作为最后防线。
第四,认为验证一次就一劳永逸。爬虫名称、IP、产品策略都会变化。这次的 GPTBot 和 ChatGPT-User 问题,本质上就是一份旧的爬虫清单没有更新带来的。建议每月或每季度检查一次官方文档,把所有需要控制的 User-agent 统一维护在配置注释里,避免下一次又漏掉一个新名字。
5.4 如果网站在国内环境运行,还要注意 CDN 和加速层的影响
国内网站使用 CDN、加速节点或云防护服务时,robots.txt 的请求可能经过多级节点。CDN 节点可能会缓存 robots.txt 文件,也可能对特定 User-agent 做节点级拦截。修改 robots.txt 之后,如果发现短时间内没有生效,先别急着怀疑规则写法,可能只是缓存还没过期。
比较稳妥的做法是,在修改配置后,给 robots.txt 加一个较短的 Cache-Control 头,或者在 CDN 控制台手动刷新缓存。另外一个容易被忽略的点是:部分 CDN 默认会把不认识的 User-agent 当成正常访问,而不会自动执行服务器上的爬虫阻断逻辑。这时候必须把判断条件配置在 CDN 规则里,或者让源站通过返回头方式告诉 CDN 如何处理。
对于有独立服务器的站点,我更喜欢直接在 Nginx 层做 User-agent 拦截,而不是只依赖 robots.txt。目的也很简单:robots.txt 只能约束遵守规则的爬虫,Nginx 拦截可以做到“来一个挡一个”。比如在 server 配置里加一段:
code复制if ($http_user_agent ~* "(GPTBot|ChatGPT-User)") {
return 404;
}
这类配置可以把请求直接挡在接入层。它的好处是:响应速度快,不经过后端程序,也不依赖 robots.txt 的解析。但它的缺点也很明显:一旦官方修改了 User-agent 名称,你需要跟着更新配置。所以实际项目里我一直是“双轨并行”:robots.txt 表达政策,接入层做执行。
6. 一次完整的处理过程示例
为了让你能直接照着操作,我给出一个完整的处理流程示例。
第一步,备份当前 robots.txt:
bash复制cp /var/www/html/robots.txt /var/www/html/robots.txt.bak
第二步,编辑 robots.txt。假设你的目标是“阻止 OpenAI 系爬虫训练抓取,但不影响搜索引擎和其他正常爬虫”,可以这样写:
code复制User-agent: GPTBot
Disallow: /
User-agent: ChatGPT-User
Disallow: /
User-agent: Google-Extended
Disallow: /
User-agent: CCBot
Disallow: /
User-agent: *
Allow: /
如果你希望允许 ChatGPT 的浏览功能,而只禁止训练抓取,就把 ChatGPT-User 那行改成 Allow: /。
第三步,用 curl 检查文件内容是否正常:
bash复制curl https://你的域名/robots.txt
第四步,确认 CDN 层面的缓存已经刷新。如果网站用的是云 CDN,到 CDN 控制台找到 robots.txt 对应的缓存条目,手动刷新。如果没做任何缓存配置,可以跳过这一步。
第五步,模拟请求测试。
bash复制curl -A "GPTBot" -I https://你的域名/
curl -A "ChatGPT-User" -I https://你的域名/
curl -A "Mozilla/5.0" -I https://你的域名/
第六步,观察日志:
bash复制grep -i "GPTBot" /var/log/nginx/access.log | tail -n 20
grep -i "ChatGPT-User" /var/log/nginx/access.log | tail -n 20
这一步要特别注意时间戳。如果配置生效后仍有大量新请求进来,说明不是 robots.txt 没生效,就是对方的爬虫没有遵守规则。这时需要切换到接入层拦截。
这些操作按顺序走完,一般十分钟内能完成一次完整的爬虫管控验证。长期来看,最该保留的是一个“爬虫管理文档”,里面写明哪些 User-agent 被屏蔽、哪些被允许、规则最后更新日期、以及接入层是否做了配套拦截。有了这份文档,以后哪怕有人误改了配置,也能快速恢复。
回到最初那个 57% 的问题,它真正提醒我们的不是“GPTBot 和 ChatGPT-User 有多难防”,而是配置爬虫规则时,永远要基于 User-agent 全量清单来做判断,而不是想当然地认为一家公司的所有爬虫都共享同一条规则。把网站当成一个需要持续维护的线上服务来看,爬虫管理就会从“写一次规则”变成“定期检查的常规巡检项”,这样才不会在下一个新爬虫出现时再次手忙脚乱。
