如何在服务器日志中查找 AI 爬虫

发布于

简短回答

在访问日志的 user agent 字段中搜索 GPTBot、OAI-SearchBot、ClaudeBot、Claude-SearchBot 和 PerplexityBot 等 token,然后查看它们收到的状态码。仅凭 user agent 说明不了任何问题,所以要把每个来源 IP 与厂商公布的 IP 列表比对;对 Google 和 Apple,则使用反向和正向 DNS 验证。

Robots.txt 说明的是你要求爬虫做什么。访问日志则显示实际发生了什么:哪些 AI 爬虫来过,请求了哪些页面,以及你的服务器作何回应。这是你手头最直接的证据,只需要日志文件和一个终端。下面的示例使用 nginx 和 Apache 默认采用的 combined 日志格式。

本页内容
  1. 访问日志中的 AI 爬虫访问是什么样子?
  2. 如何统计 AI 爬虫的访问次数?
  3. 每个爬虫实际收到了什么?
  4. 如何验证某次访问确实来自 OpenAI、Anthropic 或 Perplexity?
  5. 如何验证 Googlebot、Applebot 和 CCBot?
  6. 伪造的 AI 爬虫是什么样子?
  7. 日志无法告诉你什么?

访问日志中的 AI 爬虫访问是什么样子?

在 combined 格式中,每一行包含客户端 IP、时间、请求行、状态码、响应大小、referrer 和 user agent。nginx 将其定义为 $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent",Apache 的 combined 格式有相同的字段。来自 OpenAI 训练爬虫的一次访问如下:

20.171.206.5 - - [12/Nov/2026:10:00:01 +0000] "GET /pricing HTTP/1.1" 200 5120 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot"

需要查找的是各厂商公布的 token:GPTBot、OAI-SearchBot 和 ChatGPT-User(OpenAI);ClaudeBot、Claude-SearchBot 和 Claude-User(Anthropic);PerplexityBot 和 Perplexity-User(Perplexity);Googlebot、Applebot、meta-externalagent、meta-webindexer 和 CCBot。你永远不会看到 Google-Extended 或 Applebot-Extended。Google 表示 Google-Extended 没有单独的 user agent 字符串,Apple 表示 Applebot-Extended 不抓取内容;两者都只是 robots.txt token。

如何统计 AI 爬虫的访问次数?

按双引号字符拆分每一行,user agent 就位于第 6 个字段。只匹配这个字段,可以避免因 URL 恰好包含某个机器人的名称而产生误报。下面的命令统计当前日志以及已轮转、已压缩日志中每个爬虫的访问次数:

zcat -f /var/log/nginx/access.log* \
  | awk -F'"' '{print $6}' \
  | grep -Eo 'GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-SearchBot|Claude-User|PerplexityBot|Perplexity-User|Googlebot|bingbot|Applebot|meta-externalagent|meta-webindexer|CCBot' \
  | sort | uniq -c | sort -rn

请根据 Apache 调整路径,通常是 /var/log/apache2/access.log* 或 /var/log/httpd/access_log*。zcat -f 可同时读取普通文件和 gzip 文件。如果缺少某个你预期会出现的爬虫,仅凭这一点还不能证明它被屏蔽:它可能只是没有在你的日志所覆盖的时间段内来过。

每个爬虫实际收到了什么?

访问次数不如响应重要。一个每次请求都收到 403 的爬虫,虽然来过,却什么也没读到。下面的命令显示状态码、被请求最多的路径,以及爬虫是否获取过 robots.txt:

# Status codes returned to PerplexityBot
zcat -f /var/log/nginx/access.log* | awk -F'"' '$6 ~ /PerplexityBot/ {split($3, s, " "); print s[1]}' | sort | uniq -c

# Most requested paths for OAI-SearchBot
zcat -f /var/log/nginx/access.log* | awk -F'"' '$6 ~ /OAI-SearchBot/ {split($2, r, " "); print r[2]}' | sort | uniq -c | sort -rn | head -20

# Did ClaudeBot fetch robots.txt, and what did it get?
zcat -f /var/log/nginx/access.log* | awk -F'"' '$6 ~ /ClaudeBot/ && $2 ~ /robots\.txt/ {split($3, s, " "); print s[1]}' | sort | uniq -c

以 200 为主是你希望看到的结果。大量的 403 或 429 指向防火墙规则或速率限制。robots.txt 返回 5xx 则很严重:根据 RFC 9309,爬虫在获取 robots.txt 时收到服务器错误,就必须假定整个网站都被禁止。

如果你的网站位于 CDN 之后,会有两点变化。被 CDN 拦截的请求根本不会到达源站,因此完全不会出现在源站日志中;请改为查看 CDN 自己的安全事件。而且除非你还原访客 IP,否则源站记录的是 CDN 的地址。例如,Cloudflare 会在 CF-Connecting-IP 请求头中发送原始 IP,并且默认记录的是 Cloudflare 的 IP。

如何验证某次访问确实来自 OpenAI、Anthropic 或 Perplexity?

这些厂商公布了其代理使用的 IP 范围:OpenAI 在 openai.com/gptbot.json、openai.com/searchbot.json 和 openai.com/chatgpt-user.json;Anthropic 在 claude.com/crawling/bots.json;Perplexity 在 perplexity.ai/perplexitybot.json 和 perplexity.ai/perplexity-user.json。Anthropic 表示,来源 IP 出现在其列表中,说明该爬虫来自 Anthropic。这三家都没有记载反向 DNS 验证,所以请使用这些列表。

这些文件结构相同,都是由 ipv4Prefix 或 ipv6Prefix 条目组成的 prefixes 列表,所以一个小脚本就能把某个 IP 与其中任何一个比对:

python3 - 20.171.206.5 https://openai.com/gptbot.json <<'EOF'
import ipaddress, json, sys, urllib.request
ip = ipaddress.ip_address(sys.argv[1])
req = urllib.request.Request(sys.argv[2], headers={"User-Agent": "log-check"})
prefixes = json.load(urllib.request.urlopen(req))["prefixes"]
nets = [ipaddress.ip_network(p.get("ipv4Prefix") or p.get("ipv6Prefix")) for p in prefixes]
print(ip, "listed" if any(ip in n for n in nets) else "NOT listed")
EOF

要列出自称是某个爬虫的 IP,请在日志上运行 awk -F'"' '$6 ~ /GPTBot/ {split($1, a, " "); print a[1]}',并通过管道传给 sort | uniq -c | sort -rn。再把每个 IP 与对应的列表比对。这些列表会变化,所以请重新获取,而不要使用旧的副本。

如何验证 Googlebot、Applebot 和 CCBot?

Google、Apple 和 Common Crawl 都记载了反向加正向 DNS 的检查方法。先查询该 IP 的主机名,检查其域名,再查询这个主机名,确认它指回同一个 IP:

host 66.249.66.1
# 1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.
host crawl-66-249-66-1.googlebot.com
# crawl-66-249-66-1.googlebot.com has address 66.249.66.1

对 Google 而言,主机名必须以 googlebot.com、google.com 或 googleusercontent.com 结尾,具体取决于爬虫;Google 也公布了它的 IP 范围,Googlebot 的在 common-crawlers.json 中。对 Apple 而言,必须属于 applebot.apple.com,IP 范围在 applebot.json 中。对 Common Crawl 而言,必须位于 crawl.commoncrawl.org 之下,并且 Common Crawl 警告说,有其他爬虫冒用 CCBot 这个名称。

伪造的 AI 爬虫是什么样子?

抓取程序经常借用知名爬虫的 user agent 来绕过过滤。典型迹象:

反过来的问题同样存在:使用普通浏览器 user agent 的爬虫,根本无法从日志行中识别出来。2025 年,Cloudflare 表示观察到 Perplexity 使用未声明的、类似浏览器的 user agent,从其公布范围之外的 IP 进行爬取;Perplexity 对这一说法提出异议,并把一部分流量归因于第三方服务。仅凭日志无法裁定这类情况,这就是为什么按公布的 IP 范围验证在两个方向上都很重要。

日志无法告诉你什么?

日志显示的是到达你服务器的内容。它们不会显示 CDN 在到达源站之前拦截了什么,也不会显示返回 200 的页面包含的是正文还是只有脚本外壳,更不会显示如果爬虫今天来访是否会被允许。它们也只涵盖你保留的时间段,而访问量很小的网站可能很少见到 AI 爬虫。

在 AISeeWhy 账户中,你可以上传 combined 格式的访问日志(普通文件或 .gz,最大 50 MB);日志会被分析后丢弃,每个 AI 爬虫的请求都会连同状态码一起统计,并与厂商公布的 IP 范围比对。

常见问题

为什么我在日志中看不到 Google-Extended?

Google 表示 Google-Extended 没有单独的 user agent 字符串。抓取由 Google 现有的爬虫完成,这个 token 只控制内容可以如何使用。Applebot-Extended 同样如此,Apple 表示它不抓取内容。

我可以信任日志中的 user agent 吗?

不可以。任何人都可以发送任意 user agent。请把它当作一种声明,并通过厂商公布的 IP 范围加以确认;对 Google、Apple 和 Common Crawl,则使用反向和正向 DNS 查询。

我的日志里没有任何 AI 爬虫的访问。我被屏蔽了吗?

不一定。爬虫可能还没来过,你的 CDN 可能在到达源站之前就拦截了它,或者你的日志只记录了 CDN 的 IP 地址。请查看 CDN 的安全事件,并用每个爬虫的 user agent 测试页面。

ChatGPT-User 的流量算爬虫吗?

OpenAI 表示,ChatGPT-User 用于某些用户操作,不用于自动抓取网络。它的访问通常发生在有人向 ChatGPT 询问某个页面之后,所以数量很少。

参考资料

更多文章