你的服务器正在被 AI 爬虫"白嫖"带宽:2026 用日志把 Googlebot 和 AI 洪流分开算账(附脚本)
目录
- [00 2026 为什么要关心 AI 爬虫](#00 2026 为什么要关心 AI 爬虫)
- [背景一:AI 搜索正在抢传统搜索的流量](#背景一:AI 搜索正在抢传统搜索的流量)
- 背景二:爬虫分两类,待遇天差地别
- 背景三:默认屏蔽是坑
- [01 为什么要看服务器日志(而不是 GA)](#01 为什么要看服务器日志(而不是 GA))
- [02 工具:log_ai_bot_analyzer.py](#02 工具:log_ai_bot_analyzer.py)
- [03 怎么用结论做决策(2026 robots.txt 策略)](#03 怎么用结论做决策(2026 robots.txt 策略))
- [04 发布前 checklist](#04 发布前 checklist)
- 写在最后
先说个 2026 年很多外贸站长还不知道的事:
你网站流量里,AI 爬虫已经占了很大一块------而且你看不见。 打开 Google Analytics,里面只有人类访客和 Googlebot,GPTBot、ClaudeBot、PerplexityBot、Bytespider 这些全都不在 GA 里------因为它们不执行 JavaScript,客户端统计根本抓不到它们。
真相只在服务器访问日志里。
更扎心的是 2026 年的新现实:
- Bytespider(字节跳动)一天能爬你 5,000--50,000 次请求,而且经常不尊重 robots.txt
- GPTBot 和 ChatGPT-User 根本不读 robots.txt ,你写
Disallow它们照爬 - 一堆 SEO 插件在 2024--2025 年偷偷加了"屏蔽所有 AI 爬虫"开关且默认开启------很多站更新插件后,一夜之间从 ChatGPT/Claude/Perplexity 的引用池里消失了
- 有些 AI 训练爬虫(GPTBot、CCBot)抓你的内容是去训练模型,对你零流量回报,纯纯吃带宽
分不清"谁在爬你、花了多少钱、该封还是该放",你要么被带宽账单坑,要么手滑一封把 AI 搜索流量也掐了。
本文给你一个脚本,把访问日志里的 Googlebot / Bingbot / 各类 AI 爬虫一次性分开,算清每家的请求量、带宽、404、IP 数,并直接告诉你"哪些该封"。
00 2026 为什么要关心 AI 爬虫
背景一:AI 搜索正在抢传统搜索的流量
ChatGPT 周活 2 亿+、Perplexity 月活 1500 万+、Google AI Overviews 覆盖 30%+ 查询。你的内容不在 AI 检索爬虫的池子里,AI 搜索就不会引用你------这是一个正在快速增长的新流量渠道。
背景二:爬虫分两类,待遇天差地别
- 训练类 (GPTBot、ClaudeBot、Google-Extended、CCBot、Bytespider):抓内容去训模型,封了不影响你被实时引用,只是退出训练语料
- 检索/用户触发类 (PerplexityBot、ChatGPT-User、Claude-Web、OAI-SearchBot):实时回答用户问题时抓取,封了你就从 AI 答案里消失
关键误区:Google-Extended ≠ Googlebot。 前者是 Gemini 训练爬虫,封它只退出 Gemini 训练语料,完全不影响你的 Google 搜索排名。很多站长分不清,把 Google-Extended 当 Googlebot 一起封,白白丢了 Gemini 可见度。
背景三:默认屏蔽是坑
2024--2025 年多个 WordPress/Shopify SEO 插件加了"block AI bots"开关且默认开。审计你 robots.txt,别让插件替你做了决定。
01 为什么要看服务器日志(而不是 GA)
| 来源 | 能看到 | 看不到 |
|---|---|---|
| Google Analytics | 人类访客、Googlebot(部分) | 所有 AI 爬虫(不执行 JS) |
| 服务器日志 | 一切(含每个 AI 爬虫的 UA/IP/URL/状态码/字节数) | --- |
日志是唯一真相来源。判断"该不该封 Bytespider""GPTBot 是不是在疯狂抓我 404 旧页",只能从日志来。
02 工具:log_ai_bot_analyzer.py
零依赖,读 Nginx/Apache combined 或 common 格式日志,按 UA 把流量分成 Google / Bing / AI 训练 / AI 检索 / 用户触发 / 人类,算清每类并给建议。
bash
# 分析日志,输出爬虫排行 + 带宽 + 404 清单
python log_ai_bot_analyzer.py -i access.log -o bot_report.csv --show-404
核心逻辑(脚本摘要):
python
# UA 分类表(2026 常用)
BOT_RULES = [
("googlebot","Googlebot","Google 搜索/AI Overviews 索引","google"),
("bingbot","Bingbot","Bing/Copilot 索引","bing"),
("gptbot","GPTBot","OpenAI 训练","ai_training"),
("chatgpt-user","ChatGPT-User","ChatGPT 用户触发","ai_user"),
("claudebot","ClaudeBot","Anthropic 训练","ai_training"),
("claude-web","Claude-Web","Claude 实时检索","ai_retrieval"),
("perplexitybot","PerplexityBot","Perplexity 搜索","ai_retrieval"),
("google-extended","Google-Extended","Gemini 训练(非搜索)","ai_training"),
("bytespider","Bytespider","ByteDance/TikTok 训练","ai_training"),
("ccbot","CCBot","Common Crawl(多模型用)","ai_training"),
# ... OAI-SearchBot / Claude-SearchBot / Applebot / Meta-* / Amazonbot 等
]
RECOMMEND_BLOCK = {"Bytespider","CCBot","Meta-ExternalAgent","PetalBot","cohere-ai","Diffbot"}
# 逐行解析:IP / 时间 / method / url / status / bytes / UA
# 按 UA 归到类别,累加 requests / bytes / 去重 IP / 状态码分布
# 输出每爬虫:请求数、占比、带宽MB、占比、独立IP、404数、建议(封/放)
完整脚本:
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""服务器日志 AI 爬虫/SEO 分析(2026)------区分 Googlebot/Bingbot 与 AI 爬虫洪流,量化带宽/404,给封禁建议。零依赖。"""
import argparse, csv, re
from collections import Counter, defaultdict
BOT_RULES = [
("googlebot","Googlebot","Google 搜索/AI Overviews 索引","google"),
("google-inspectiontool","GoogleInspect","Google 索引检查","google"),
("bingbot","Bingbot","Bing/Copilot 索引","bing"),
("msnbot","Bingbot","Bing","bing"),
("yandex","Yandex","Yandex","other"),
("baiduspider","Baiduspider","百度","other"),
("gptbot","GPTBot","OpenAI 训练","ai_training"),
("oai-searchbot","OAI-SearchBot","OpenAI 搜索索引","ai_retrieval"),
("claudebot","ClaudeBot","Anthropic 训练","ai_training"),
("claude-web","Claude-Web","Claude 实时检索","ai_retrieval"),
("claude-searchbot","Claude-SearchBot","Claude 搜索","ai_retrieval"),
("claude-user","Claude-User","Claude 用户触发","ai_user"),
("google-extended","Google-Extended","Gemini 训练(非搜索)","ai_training"),
("googleother","GoogleOther","Google 非搜索","ai_training"),
("ccbot","CCBot","Common Crawl(多模型用)","ai_training"),
("bytespider","Bytespider","ByteDance/TikTok 训练","ai_training"),
("applebot-extended","Applebot-Extended","Apple Intelligence 训练","ai_training"),
("applebot","Applebot","Apple","ai_retrieval"),
("meta-externalagent","Meta-ExternalAgent","Meta AI 训练","ai_training"),
("facebookbot","FacebookBot","Meta AI","ai_training"),
("amazonbot","Amazonbot","Amazon Alexa/Rufus","ai_retrieval"),
("cohere-ai","cohere-ai","Cohere 训练","ai_training"),
("petalbot","PetalBot","华为 Petal","ai_training"),
("youbot","YouBot","You.com 搜索","ai_retrieval"),
("diffbot","Diffbot","结构化数据抓取","ai_training"),
("meta-webindexer","Meta-WebIndexer","Meta 网页索引","ai_retrieval"),
("perplexitybot","PerplexityBot","Perplexity 搜索","ai_retrieval"),
("perplexity-user","Perplexity-User","Perplexity 用户触发","ai_user"),
("chatgpt-user","ChatGPT-User","ChatGPT 用户触发浏览","ai_user"),
("anthropic-ai","anthropic-ai","Anthropic 旧训练","ai_training"),
]
RECOMMEND_BLOCK = {"Bytespider","CCBot","Meta-ExternalAgent","PetalBot","cohere-ai","Diffbot"}
LINE_RE = re.compile(
r'^(?P<ip>\S+)\s+\S+\s+\S+\s+\[(?P<time>[^\]]+)\]\s+'
r'"(?P<method>\S+)\s+(?P<url>\S+)\s*(?P<proto>[^"]*)"\s+'
r'(?P<status>\d{3})\s+(?P<bytes>\d+|-)'
r'(?:\s+"(?P<ref>[^"]*)"\s+"(?P<ua>[^"]*)")?')
def classify(ua):
ua_l = (ua or "").lower()
if not ua_l: return ("unknown","未知","无 UA","other")
for sub, name, desc, cat in BOT_RULES:
if sub in ua_l: return (sub, name, desc, cat)
if re.search(r"bot|crawl|spider|slurp|facebookexternalhit|preview", ua_l):
return ("otherbot","其他爬虫","未分类自动程序","other")
return ("human","人类/真实访客","浏览器","human")
def analyze(log_path):
stats = defaultdict(lambda: {"requests":0,"bytes":0,"ips":set(),"status":Counter(),"urls":Counter()})
total_req = total_bytes = 0
not_found = []
with open(log_path, encoding="utf-8", errors="ignore") as f:
for line in f:
m = LINE_RE.match(line.strip())
if not m: continue
ua = m.group("ua") or ""
_, name, _, _ = classify(ua)
try: b = int(m.group("bytes")) if m.group("bytes") != "-" else 0
except ValueError: b = 0
status, url, ip = m.group("status"), m.group("url"), m.group("ip")
s = stats[name]; s["requests"] += 1; s["bytes"] += b
s["ips"].add(ip); s["status"][status] += 1; s["urls"][url] += 1
total_req += 1; total_bytes += b
if status == "404" and len(not_found) < 5000:
not_found.append((name, url, ip))
return stats, total_req, total_bytes, not_found
def main():
ap = argparse.ArgumentParser(description="服务器日志 AI 爬虫/SEO 分析(2026)")
ap.add_argument("-i","--input",required=True); ap.add_argument("-o","--output",default="bot_report.csv")
ap.add_argument("--show-404",action="store_true"); ap.add_argument("--top404",default="bot_404_report.csv")
args = ap.parse_args()
stats, total_req, total_bytes, not_found = analyze(args.input)
if total_req == 0:
print("[错误] 未解析到任何日志行"); return
rows, human_req = [], 0
for name, s in stats.items():
cat = desc = "other"
for k,v,d,c in BOT_RULES:
if v == name: cat, desc = c, d; break
if cat == "human":
human_req += s["requests"]; continue
rows.append({"Bot":name,"Category":cat,"Purpose":desc,
"Requests":s["requests"],"PctRequests":round(100*s["requests"]/total_req,2),
"BandwidthMB":round(s["bytes"]/1048576,2),"PctBandwidth":round(100*s["bytes"]/total_bytes,2) if total_bytes else 0,
"DistinctIPs":len(s["ips"]),"Status404":s["status"].get("404",0),
"TopStatus":s["status"].most_common(1)[0][0] if s["status"] else "",
"Recommend":("建议封/限" if name in RECOMMEND_BLOCK and cat=="ai_training"
else "保持放行" if cat in ("google","bing","ai_retrieval","ai_user") else "按业务判断")})
rows.sort(key=lambda x:-x["Requests"])
with open(args.output,"w",newline="",encoding="utf-8-sig") as f:
w = csv.DictWriter(f, fieldnames=["Bot","Category","Purpose","Requests","PctRequests","BandwidthMB","PctBandwidth","DistinctIPs","Status404","TopStatus","Recommend"])
w.writeheader(); w.writerows(rows)
print(f"写出 {args.output};总请求 {total_req:,},总流量 {total_bytes/1048576:.1f} MB")
for r in rows:
flag = "[BLOCK]" if r["Recommend"].startswith("建议封") else "[OK]"
print(f" {flag} {r['Bot'][:18]:18} 请求{r['Requests']:>7,} ({r['PctRequests']:>5}%) 带宽{r['BandwidthMB']:>8.1f}MB ({r['PctBandwidth']:>5}%) 404={r['Status404']:>4} [{r['Category']}]")
print(f"\n人类/真实访客请求:{human_req:,}({round(100*human_req/total_req,1)}%)------ AI/机器人占比 {round(100*(total_req-human_req)/total_req,1)}%")
ai_train = [r for r in rows if r["Category"]=="ai_training"]
ai_train_bw = sum(r["BandwidthMB"] for r in ai_train)
print(f"\nAI 训练类爬虫总带宽 {ai_train_bw:.1f} MB")
blockable = [r for r in ai_train if r["Bot"] in RECOMMEND_BLOCK]
if blockable:
print(f"建议评估封禁:{', '.join(r['Bot'] for r in blockable)}(封训练类不影响 Google/Bing 搜索与实时 AI 引用)")
if [r for r in rows if r["Bot"]=="Google-Extended"]:
print("注意:Google-Extended ≠ Googlebot,封它只退出 Gemini 训练语料,不影响搜索排名")
if args.show_404 and not_found:
with open(args.top404,"w",newline="",encoding="utf-8-sig") as f:
w = csv.writer(f); w.writerow(["Bot","URL","IP"])
for b,u,ip in not_found: w.writerow([b,u,ip])
print(f"\n写出 404 清单 {args.top404}({len(not_found)} 条)")
if __name__=="__main__": main()
输出示例(合成日志跑出的效果)
[BLOCK] Bytespider 请求 65 (37.14%) 带宽 0.3MB (35.26%) 404=5 [ai_training]
[OK] Googlebot 请求 40 (22.86%) 带宽 0.2MB (20.75%) 404=0 [google]
[OK] 人类/真实访客 请求 30 (17.14%) 带宽 0.1MB (15.56%) 404=0 [human]
[OK] PerplexityBot 请求 18 (10.29%) 带宽 0.1MB (15.22%) 404=0 [ai_retrieval]
[OK] GPTBot 请求 12 ( 6.86%) 带宽 0.1MB (10.14%) 404=0 [ai_training]
[OK] Bingbot 请求 10 ( 5.71%) 带宽 0.0MB ( 3.07%) 404=0 [bing]
人类/真实访客请求:30(17.1%)------ AI/机器人占比 82.9%
AI 训练类爬虫总带宽 0.4 MB
建议评估封禁:Bytespider(封训练类不影响 Google/Bing 搜索与实时 AI 引用)
03 怎么用结论做决策(2026 robots.txt 策略)
根据脚本输出,对应三类处理:
| 类别 | 代表 | 处理 |
|---|---|---|
| 搜索引擎(绝不能封) | Googlebot / Bingbot | 保持放行,封了直接从搜索消失 |
| 实时检索/用户触发(建议放) | PerplexityBot / ChatGPT-User / Claude-Web / OAI-SearchBot | 保持放行,否则退出 AI 答案 |
| 训练类高带宽低价值(评估封) | Bytespider / CCBot / Meta-ExternalAgent | 可封,不影响搜索与实时引用 |
robots.txt 模板(平衡保护 vs AI 可见度):
# 搜索引擎必须放
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
# 实时 AI 检索------保持放行(要吃 AI 搜索流量)
User-agent: PerplexityBot
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: Claude-Web
Allow: /
# 训练类凶猛/低价值------评估封
User-agent: Bytespider
Disallow: /
User-agent: CCBot
Disallow: /
两个硬提醒:
- Bytespider 不尊重 robots.txt ,光写
Disallow没用,要在 WAF/防火墙层返回 403 才拦得住 - GPTBot / ChatGPT-User 不读 robots.txt,限制要走 server 层;robots.txt 对它们只是建议
04 发布前 checklist
- 从主机后台导出原始访问日志(不是 GA)
- 跑
log_ai_bot_analyzer.py看 AI 爬虫占比 - 确认 Googlebot / Bingbot 在"保持放行"列,没被误封
- 确认 PerplexityBot / ChatGPT-User / Claude-Web 没被插件默认屏蔽
- Bytespider 占比过高 → WAF 层 403 拦截(robots.txt 拦不住它)
- 每季度复查 robots.txt,AI 爬虫 UA 每年都变
- 看 404 清单:AI 爬虫猛抓的旧 URL 要么 301 重定向,要么返回正确内容
写在最后
2026 年,"谁在爬我的网站"已经不是小事。AI 爬虫吃的是真金白银的带宽,部分还零回报;但手滑一封,你可能同时把 ChatGPT/Claude/Perplexity 的引用流量也掐了------那可是增长最快的新搜索渠道。
分不清的时候,记住一句话:搜索引擎和实时 AI 检索必须放,训练类凶猛爬虫可以封,Google-Extended 不是 Googlebot。
脚本跑一遍日志,账就清楚了。
免责声明:本文 AI 爬虫列表与带宽基准基于 2026 年公开资料(presenc.ai / tencentcloud / buttonblock / wislr 等日志研究)整理,非官方。UA 字符串每半年变一次,落地前请以各平台官方 bot 文档为准,并用反向 DNS 校验 IP 再下封禁决策。脚本为启发式分类,不替代 WAF/CDN 层真实防护。
系列第 10 篇(前 9 篇:删文涨流量 / 搜索意图 / AI Overview / GPSR 合规 / 关税海外仓红利词 / 内容农场自查 / 商品结构化数据审计 / GBP 本地 SEO 差距 / hreflang 国际 SEO),选题互不重复,均为纯 SEO + 外贸时事 + 工具化。