服务器日志里的 AI 爬虫:识别、放行与访问周报的工程实践
你的站点日志里,可能已经来过一批特殊的访客:GPTBot、ClaudeBot、Bytespider、PerplexityBot……它们是各大 AI 平台的爬虫,决定了你的内容能不能进入模型的训练语料和联网检索池。
但大部分团队对这些访客一无所知:不知道来没来过、抓了哪些页、有没有被 WAF 误拦。这篇给一套完整的日志工程实践:UA 识别清单、放行配置、周报脚本、误拦排查。
一、先认识这些访客:AI 爬虫分三类
| 类型 | 代表 UA | 行为特征 |
|---|---|---|
| 训练爬虫 | GPTBot、ClaudeBot、Bytespider、CCBot、Amazonbot | 全站广度抓取,频率高,遵守 robots |
| 检索爬虫 | OAI-SearchBot、Claude-SearchBot、PerplexityBot、Google-Extended | 按查询实时抓取单页,突发性强 |
| 用户代理 | ChatGPT-User、Claude-User、Perplexity-User | 用户让 AI 读某页面时代抓,一次一页 |
三类的价值不同:训练爬虫决定"长期记忆"里有没有你(月级滞后);检索爬虫决定 AI"现在"能不能查到你(周级生效);代理抓取决定用户主动分享你页面时 AI 能不能读。
一个容易踩的点:Google-Extended 和 Googlebot 是独立 UA。拦前者只影响 Gemini 训练,不影响 Google 搜索排名——这是官方明确的解耦设计,可以分开决策。
二、日志分析:一条命令看清 AI 爬虫访问
假设 nginx 默认日志格式($http_user_agent 在第 12 字段附近,按实际格式调整):
# 各 AI 爬虫的访问总量
grep -oE "GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-SearchBot|Claude-User|Bytespider|PerplexityBot|Perplexity-User|Google-Extended|Amazonbot|Applebot-Extended|CCBot" \
/var/log/nginx/access.log | sort | uniq -c | sort -rn
# 某个爬虫抓了哪些页面(按频次排序)
grep "Bytespider" /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20
# 有没有被拒(4xx/5xx 占比)
grep "GPTBot" /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c
第三条命令最关键:大量 403/429 说明 WAF 或限流规则在拦——robots.txt 放行和 WAF 放行是两层,很多站点 robots 配对了但 CDN 的 Bot 防护把 AI 爬虫当恶意流量(GPTBot 抓取频率确实不低,容易触发默认阈值)。
三、放行配置
robots.txt 参考模板(黑名单思路:公开内容全放,私密路径靠鉴权):
# AI 训练与检索爬虫
User-agent: GPTBot
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: Bytespider
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: CCBot
Allow: /
# 兜底开放(AI 爬虫 UA 名单每月都在变,白名单必漏)
User-agent: *
Allow: /
# 私密路径单独拦
Disallow: /admin/
Disallow: /api/internal/
Sitemap: https://example.com/sitemap.xml
WAF 侧:把上述 UA 加入 Bot 白名单,限流阈值单独放宽(或按 IP 段验证后放行——各家爬虫的 IP 段可以在官方文档查到并定期同步)。
提醒:robots.txt 不是安全层,它只是君子协定。私密接口的防护必须靠应用鉴权和 ACL。
四、AI 爬虫访问周报(可直接跑的脚本框架)
#!/usr/bin/env python3
"""AI 爬虫访问周报:解析 nginx 日志,输出三个核心指标"""
import re, sys
from collections import Counter, defaultdict
from datetime import datetime, timedelta
AI_UAS = ["GPTBot", "OAI-SearchBot", "ChatGPT-User", "ClaudeBot",
"Claude-SearchBot", "Bytespider", "PerplexityBot",
"Google-Extended", "CCBot", "Amazonbot"]
LOG_PATTERN = re.compile(
r'(?P<ip>\S+) \S+ \S+ \[(?P<time>[^\]]+)\] "(?P<req>[^"]*)" '
r'(?P<status>\d{3}) \S+ "[^"]*" "(?P<ua>[^"]*)"')
def parse(path, days=7):
since = datetime.now() - timedelta(days=days)
visits, pages, errors = Counter(), defaultdict(Counter), Counter()
for line in open(path, encoding="utf-8", errors="ignore"):
m = LOG_PATTERN.match(line)
if not m: continue
ua = m.group("ua")
hit = next((u for u in AI_UAS if u in ua), None)
if not hit: continue
visits[hit] += 1
path_ = m.group("req").split(" ")[1] if " " in m.group("req") else ""
pages[hit][path_] += 1
if m.group("status")[0] in "45":
errors[hit] += 1
return visits, pages, errors
def report(path):
visits, pages, errors = parse(path)
print("== AI 爬虫周报 ==")
for ua, n in visits.most_common():
err = errors.get(ua, 0)
flag = " ⚠️高拒绝率" if err / max(n, 1) > 0.1 else ""
print(f"{ua}: {n} 次访问, {err} 次被拒{flag}")
top = ", ".join(p for p, _ in pages[ua].most_common(5))
print(f" TOP页面: {top}")
if __name__ == "__main__":
report(sys.argv[1] if len(sys.argv) > 1 else "/var/log/nginx/access.log")
周报盯三件事:
- 各 UA 周访问次数——新内容发布后 3-7 天有没有对应抓取(没有=没被发现,查 sitemap 和内链)
- 被抓页面清单——核心事实页(FAQ/定价/文档/案例)在不在清单里
- 拒绝率——超 10% 就排查 WAF/限流
五、观测不到的情况怎么排查
日志里完全没有 AI 爬虫?按序检查:
- robots.txt 是否有
User-agent: * Disallow: /类全拦规则 - CDN 层的 Bot 管理是否开启"拦截未知爬虫"(很多默认模板会拦)
- 站点是否太新/太深——爬虫发现新站靠 sitemap 提交和外链,主动去 Google Search Console / Bing Webmaster / 百度站长提交
- 日志采样窗口是否够长(检索爬虫是突发式的,看一天不够,看一周)
总结
AI 爬虫日志是站点"AI 可见性"最底层、也最容易被忽略的观测面。UA 识别 → robots/WAF 双层放行 → 周报监控,三件事做完,你至少能回答那个最基本的问题:AI 来读过我们吗?读到了什么?
这比任何上层的优化都优先——门没开,屋里装修得再好也没人看得见。
本文基于Winin(Winin.ai)工程实践整理。各 AI 平台爬虫 UA 持续新增和调整,清单以各厂商官方文档为准。笔者长期从事品牌 AI 可见性监测方向工作。欢迎评论区补充你日志里出现过的其他 AI 爬虫 UA。