先说结论。外贸独立站的 robots.txt 里,六个主流 AI 爬虫只分成两类:一类决定页面会不会被 AI 搜索引用,一类决定内容会不会被拿去训练模型。分清这两类,配置才有依据。下面的脚本能跑出你站点的判定。
很多外贸企业把 robots.txt 当成搜索收录开关,这两年这个理解已经过时了。AI 搜索爬虫和训练爬虫走的是不同的产品标记,放行其中一个不等于另一个也放行。先把这两个身份分开看,才知道每条规则在管什么。
一、六个 AI 爬虫,身份分成两类
下面这张表是我按各家官方文档整理的。判定栏写的是各家的官方原话要点,不是我的推测。
| 产品标记 | 所属平台 | 实际用途 | 放行意味着什么 |
|---|---|---|---|
| OAI-SearchBot | ChatGPT 搜索 | 为 ChatGPT 搜索结果收录并链接站点 | 你的页面能出现在 ChatGPT 的搜索答案里 |
| ChatGPT-User | ChatGPT 用户触发 | 用户在对话里提问时,ChatGPT 当场访问某个页面 | 官方明确写了 robots.txt 规则可能不适用 |
| GPTBot | OpenAI 模型训练 | 抓取可能用于训练生成式基础模型的内容 | 抓到的内容可能进入训练数据 |
| PerplexityBot | Perplexity 搜索 | 为 Perplexity 搜索结果收录并链接站点 | 你的页面能出现在 Perplexity 搜索结果里 |
| Perplexity-User | Perplexity 用户触发 | 用户在 Perplexity 提问时当场访问页面 | 官方原文是 generally ignores robots.txt rules |
| Google-Extended | Gemini 训练与 grounding | 控制被抓取内容能否用于训练 Gemini 模型,以及 Gemini 应用和 Vertex AI 上的 grounding | 拒绝它不影响 Google 搜索收录,也不是排名信号 |
把这张表横着看一遍,会发现一件事:六个标记里,真正管"被不被引用"的是 OAI-SearchBot 和 PerplexityBot 两个,管"被不被拿去训练"的是 GPTBot 和 Google-Extended 两个,剩下两个是用户当场触发的访问,官方文档都写了 robots.txt 对它们不一定生效。
OpenAI 官方文档里有一句话值得抄下来:Each setting is independent of the others。也就是说,允许 OAI-SearchBot 同时拒绝 GPTBot 是官方支持的组合,两边互不干扰。Perplexity 官方文档写的是同样的意思,Each setting works independently,同一句还补了一句时间口径:it may take up to 24 hours for our systems to reflect changes。也就是说改动最多需要 24 小时才能反映到系统。
二、最容易搞反的一条:Google-Extended 不是爬虫
Google-Extended 这个标记在中文圈被当成一个 AI 爬虫在传,这个理解不对。Google 官方文档写得很清楚:它是一个独立的产品标记,没有自己的 HTTP 请求 User-Agent 字符串,检索工作是用现有的 Google User-Agent 完成的。
这意味着两件事。一是你在服务器日志里搜 Google-Extended,永远搜不到这个 UA,它本来就不以这个身份发请求。要看 Google 的抓取情况,看 Googlebot 的日志就行。二是 Google 官方文档里那句原文写得很直接:Google-Extended does not impact a site's inclusion in Google Search nor is it used as a ranking signal。它不影响网站在 Google 搜索中的收录,也不是搜索排名信号。
Google 官方文档把 Google-Extended 的作用范围列成两项:一项是控制被抓取的内容能否用于训练未来的 Gemini 模型,一项是为 Gemini 应用和 Vertex AI 上的 Google Search 提供 grounding。除此之外,它不控制 AI Overviews 和 AI Mode 里的内容展示,那部分由 Googlebot 的规则和摘要类指令管。
这里有个反常识的推论:如果你把 Google-Extended 拒掉,你的内容不进入 Gemini 训练,但 Google 搜索的收录和 AI Overviews 里的展示并不因此消失。想控制 AI Overviews 里出现什么,Google 官方指向的是 noindex、nosnippet、max-snippet 这类指令,不是 Google-Extended。
三、用脚本跑出你自己站点的判定结果
规则讲完不如直接跑。下面这段脚本做三件事:按 User-Agent 分段解析 robots.txt,按 RFC 9309 的判定顺序算出每个爬虫的访问权限,再打印一张表。
判定顺序是 RFC 9309 第 2.2.1 和 2.2.2 节规定的,不是自己定的:产品标记大小写不敏感地匹配,命中精确组就用精确组,没有精确组才回落到通配组 *;组内按最长路径匹配,同长度时 Allow 优先。
import re
import sys
import urllib.request
def parse_robots(text):
"""按 User-Agent 分段解析 robots.txt,返回 {小写产品标记: [(指令, 路径), ...]}"""
groups = {}
agent = None
rules = []
def flush():
if agent is not None:
groups.setdefault(agent.lower(), []).extend(rules)
for raw in text.splitlines():
line = raw.split('#')[0].strip()
if not line or ':' not in line:
continue
key, value = line.split(':', 1)
key = key.strip().lower()
value = value.strip()
if key == 'user-agent':
flush()
agent = value
rules = []
elif agent is not None and key in ('allow', 'disallow'):
rules.append((key, value))
flush()
return groups
def match_path(pattern, path):
"""支持 * 与 $ 的路径匹配。$ 表示路径必须在此结束。"""
anchored = pattern.endswith('$')
if anchored:
pattern = pattern[:-1]
regex = '^' + '.*'.join(re.escape(part) for part in pattern.split('*'))
if anchored:
regex += '$'
return re.match(regex, path) is not None
def decide(groups, token, path):
"""判定某产品标记能否抓取某路径。
精确匹配的组优先,没有则回落到 '*' 组。
组内按最长路径匹配,同长度 Allow 优先。
"""
key = token.lower()
if key in groups:
rules = groups[key]
source = '精确组'
elif '*' in groups:
rules = groups['*']
source = '通配组'
else:
return '允许', '无适用组', '-'
best = None
for kind, pattern in rules:
if kind == 'disallow' and pattern == '':
continue
if not match_path(pattern, path):
continue
length = len(pattern)
if best is None or length > best[0]:
best = (length, kind, pattern)
elif length == best[0] and kind == 'allow' and best[1] == 'disallow':
best = (length, kind, pattern)
if best is None:
return '允许', source, '无规则命中'
length, kind, pattern = best
if kind == 'allow':
return '允许', source, pattern
return '禁止', source, pattern
AGENTS = [
('OAI-SearchBot', 'ChatGPT 搜索'),
('ChatGPT-User', 'ChatGPT 用户触发'),
('GPTBot', 'OpenAI 模型训练'),
('PerplexityBot', 'Perplexity 搜索'),
('Perplexity-User', 'Perplexity 用户触发'),
('Google-Extended', 'Gemini 训练与 grounding'),
('Googlebot', 'Google 搜索'),
]
def main():
url = sys.argv[1] if len(sys.argv) > 1 else 'https://example.com/robots.txt'
request = urllib.request.Request(
url, headers={'User-Agent': 'Mozilla/5.0 robots-audit'})
text = urllib.request.urlopen(request, timeout=20).read().decode('utf-8', 'ignore')
groups = parse_robots(text)
print('文件:%s' % url)
print('分段:%s' % ', '.join(sorted(groups)))
print('')
header = '%-20s %-26s %-8s %-10s %s'
print(header % ('产品标记', '用途', '判定', '来源组', '命中规则'))
for token, purpose in AGENTS:
verdict, source, pattern = decide(groups, token, '/products/flange')
print(header % (token, purpose, verdict, source, pattern))
if __name__ == '__main__':
main()
用法就一行,把参数换成你自己的站:
顺手说下元数据那层。写 robots.txt 的时候顺手把页面标题、meta description、结构化数据和图片替代文字这几项一起对齐,是同一件事的两面。标题和描述决定搜索结果里显示什么,结构化数据决定机器能不能读懂产品是什么,替代文字决定图片里的参数有没有被读出来。robots.txt 决定爬虫能不能走到这一页。这几项口径不一致时,爬虫抓到了页面也没抓到你要引用的那句话。
python robots_audit.py https://example.com/robots.txt
参数是 robots.txt 的完整地址,不是站点首页地址。这两者的判定结果经常不一样,很多站的 robots.txt 在根路径,而抓取规则和 sitemap 声明可能分散在不同位置。
跑完你会看到一张表,长这样。这是我的站当前跑出来的结果,我按同一份 robots.txt 实跑的读数:
| 产品标记 | 用途 | 判定 | 来源组 | 命中规则 |
|---|---|---|---|---|
| OAI-SearchBot | ChatGPT 搜索 | 允许 | 精确组 | / |
| ChatGPT-User | ChatGPT 用户触发 | 允许 | 精确组 | / |
| GPTBot | OpenAI 模型训练 | 允许 | 精确组 | / |
| PerplexityBot | Perplexity 搜索 | 允许 | 精确组 | / |
| Perplexity-User | Perplexity 用户触发 | 允许 | 精确组 | / |
| Google-Extended | Gemini 训练与 grounding | 禁止 | 精确组 | / |
| Googlebot | Google 搜索 | 允许 | 通配组 | / |
这张表读出两个信息。前五个爬虫命中的是精确组,说明它们各自有一段独立声明,不是靠通配组兜底。Google-Extended 判禁止,命中规则是根路径,表示整个站点都不参与 Gemini 训练与 grounding。Googlebot 走的是通配组,因为它没有独立段落,靠通配规则生效。
四、三种常见误配,配之前先对一遍
下面三种写法我见过不少站点在用,跑出来的结果和自己的预期基本相反。
| 写法 | 作者以为的结果 | 实际结果 |
|---|---|---|
只写 User-Agent: GPTBot 并放行,就以为 AI 搜索能抓到 |
ChatGPT 搜索会引用我的页面 | GPTBot 是训练用的标记,管搜索引用的是 OAI-SearchBot。放行 GPTBot 对搜索引用没有作用 |
| 把 OAI-SearchBot 和 ChatGPT-User 一起拒绝 | 不参与 AI,也不进搜索答案 | 拒绝 OAI-SearchBot 确实会让页面不出现在 ChatGPT 搜索答案里,但官方文档写了 ChatGPT-User 是用户触发的访问,robots.txt 规则可能不适用,一起拒绝没有意义 |
| 以为拒绝 Google-Extended 就等于退出 AI 搜索 | 页面不会出现在 AI 答案里 | Google 官方明确 Google-Extended 不影响 Google 搜索收录,也不是排名信号。真正控制 AI Overviews 展示的是 Googlebot 规则加 noindex、nosnippet 这类指令 |
还有一个不算误配但容易踩的点:通配组里的 Disallow 空值。写成 Disallow: 后面什么都不填,含义是允许全部,不是禁止全部。很多人写成 Disallow: / 才是禁止全部,这个反向关系容易看串。
还有一条 RFC 9309 里写明的细节:通配组只在前缀相同的情况下才参与比较。同一份文件里如果有两个 User-Agent: * 段落,它们的规则要合并成一个组再判断,不是先遇到哪个算哪个。
五、配置完还要验证的两件事
robots.txt 写完不等于生效,官方文档都说了要等系统同步,OpenAI 和 Perplexity 那边都是最多 24 小时。这段时间里有两个可以马上查的地方。
一是服务器日志。搜 OAI-SearchBot 和 PerplexityBot 这两个 UA,看它们请求你页面时返回的状态码。返回 200 说明抓取正常。如果返回 403、429 或 503,问题多半不在 robots.txt,而在防火墙规则或 WAF 把通用爬虫一起挡了。Perplexity 官方文档专门写了这一段,建议按 UA 加 IP 段双重匹配来放行,而不是只放行 UA。
二是官方文档都提到了 IP 段清单。各家都单独发布了 JSON 格式的 IP 列表,UA 字符串本身是可以伪造的,只看 UA 判断不了来的是不是真的官方爬虫。拿 IP 段做网络层校验,才算把这件事做实。
顺手提一句 robots.txt 本身不构成访问控制。RFC 9309 的安全章节写得很清楚,列出路径等于把这些路径公开了。robots.txt 是给爬虫的约定,不是权限系统,真正要挡住的内容得靠应用层的鉴权。
六、把这一步接回外贸独立站的整体动作
单独优化 robots.txt 的意义有限,它只是链路上的一个开关。外贸独立站要能被 AI 引用,前提是页面内容本身是结构化、可被准确读取的。参数写不清、栏目层级乱、页面没有实体信息描述,爬虫放行了也只是抓到一个空壳。
从独立站SEO 的角度看,robots.txt 管的是能不能进门,页面本身管的是进门之后读到了什么。独立站获客这条链路上的每一环都在传递同一个信号:让机器读得懂你卖什么。
工具这块我自己也用过。我偶尔会用 NeoGress 的免费页面检测跑一遍站点,主要看产品页的字段有没有写全、来源标记能不能读出来、基础信息项有没有缺。工具只能告诉你缺什么,能不能补上、怎么补,还得看你自己把产品资料整理到什么程度。这两件事得分开。
从独立站搭建的角度看,robots.txt 更像一个收尾动作。上线前把参数结构化做好、把 sitemap 和 robots 的口径对齐、把产品页的信息层级理顺,这些是让 AI 读懂的前提。放行规则只是让爬虫进门的一道手续。
顺着这个顺序做下来,外贸独立站怎么做这个问题就有答案了:先让爬虫进得来,再让爬虫读得懂,然后才是把询盘接住。顺序反过来做,力气会花错地方。
你站上的 robots.txt 现在放行了哪几个 AI 爬虫?跑一遍上面那段脚本,把结果贴出来,我看到有代表性的会挑出来细聊。