KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
05 · 日志诊断:爬虫到底来没来 — keel 龙骨
本章目标:能从访问日志里回答三个问题——谁来了、来了多少次、抓到了什么。 验收标准:跑出各爬虫 UA 的抓取量统计,并能定位 404/5xx/超时都发生在哪些路径。
本章目标:能从访问日志里回答三个问题——谁来了、来了多少次、抓到了什么。
验收标准:跑出各爬虫 UA 的抓取量统计,并能定位 404/5xx/超时都发生在哪些路径。
为什么这一章重要:GSC 只能告诉你 Google 看到了什么,百度平台只告诉你百度的事。服务器日志是唯一的中立数据源——所有爬虫的请求都在那里,不管它属于哪家。当"搜不到"时,日志是最快区分"爬虫没来"和"来了但抓不动"的手段。
一、日志里要有什么
nginx 默认日志格式(combined)包含 $http_user_agent 与 $status,够用了。确认你的配置里有 access_log:
access_log /var/log/nginx/learning.access.log;
若想额外看响应时间与上游耗时(诊断抓取超时很有用),自定义一个格式:
log_format main '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" rt=$request_time urt=$upstream_response_time';
access_log /var/log/nginx/learning.access.log main;
二、统计各爬虫的抓取量
LOG=/var/log/nginx/learning.access.log
# 全量 UA 排行(看谁在访问你的站)
awk -F'"' '{print $6}' $LOG | sort | uniq -c | sort -rn | head -30
# 只看搜索引擎与 AI 爬虫
grep -iE 'googlebot|bingbot|baiduspider|sogou|bytespider|GPTBot|ClaudeBot|PerplexityBot|Applebot' $LOG \
| awk -F'"' '{print $6}' \
| sed -E 's/.*(Googlebot|Bingbot|Baiduspider|Bytespider|GPTBot|ClaudeBot|PerplexityBot|Sogou).*/\1/' \
| sort | uniq -c | sort -rn
这个统计能立刻回答:"爬虫到底来没来"。
- 某家 UA 计数为 0 → 它从没来过。原因通常是:站点从未被提交、或从没有任何外部链接指向你。提交 sitemap 是唯一的主动手段。
- 有抓取量但收录为 0 → 抓取成功了但没被收录,问题在内容质量/重复/canonical,回到第 01–02 章。
三、看爬虫抓了哪些路径、拿到了什么状态码
# Googlebot 的请求:路径 + 状态码 分布
grep -i 'googlebot' $LOG \
| awk '{print $7, $9}' | sort | uniq -c | sort -rn | head -30
(字段位置随 log_format 变化;先用一条样本确认 $7 是 path、$9 是 status。)
重点看三类异常
# 1. 爬虫遇到的 404(sitemap 里混进了死链,或内链指向已删除内容)
grep -iE 'googlebot|bingbot|baiduspider' $LOG | awk '$9==404 {print $7}' | sort | uniq -c | sort -rn | head
# 2. 爬虫遇到的 5xx(真正的收录杀手)
grep -iE 'googlebot|bingbot|baiduspider' $LOG | awk '$9>=500 {print $7, $9}' | sort | uniq -c | sort -rn | head
# 3. 爬虫遇到的 301/302(说明它抓到的是非 canonical 形式)
grep -iE 'googlebot|bingbot' $LOG | awk '$9==301 || $9==302 {print $7}' | sort | uniq -c | sort -rn | head
第 3 项容易被忽视:如果爬虫大量抓到 301,说明你的 sitemap 或内链里还有非 canonical 的 URL 形式,抓取预算被浪费在跳转上。正确做法是让 sitemap 与内链直接指向最终 URL。
四、验证爬虫抓到的内容(关键一步)
爬虫来了 ≠ 抓到了正文。日志能看到它请求了哪些资源:
# 某次 Googlebot 请求后,紧接着有没有请求内容 JSON / 抓取 HTML
grep -i 'googlebot' $LOG | tail -20 | awk '{print $7}'
判据:
| 日志里看到的 | 结论 |
|---|---|
只请求了 /learning/ 的 HTML,之后没有任何 /content/*.json 请求 |
说明正文已内联在 HTML(预渲染生效)✅ |
请求了 HTML 后又请求了若干 /content/*.json,但抓取后仍未收录 |
爬虫需要执行 JS,风险较高 |
| 只有 HTML 请求,且你的正文靠 JS 渲染 | 爬虫抓到的是空壳 ❌ |
这就是第 01 章"关掉 JS 看正文"那条自检的日志侧验证。两条证据互相印证,结论才可靠。
五、识别真假爬虫
日志里的 UA 是可以伪造的。冒牌 Googlebot 常见于扫描器。验证方法:反查 IP。
# 取 Googlebot 的来源 IP 排行
grep -i 'googlebot' $LOG | awk '{print $1}' | sort | uniq -c | sort -rn | head
# 反解域名(Google 的爬虫 IP 反向解析应为 *.googlebot.com 或 *.google.com)
dig -x <IP> +short
# 再用正向解析确认(双向 DNS 校验)
dig <反解得到的域名> +short # 应再解析回同一个 IP
官方推荐的校验方式就是双向 DNS:反解得到 *.googlebot.com / *.google.com(百度是 *.baidu.com / *.baidu.jp),再正解回同一 IP,两条都成立才是真的。
伪造 UA 的扫描器通常反解不到这些域——直接忽略即可,不要为它们调整配置。
六、抓取预算(Crawl Budget)的实用理解
搜索引擎给每个站点的抓取配额是有限的。浪费预算的常见行为:
- 无限空间的 URL:带 session id、排序参数、搜索参数的 URL 都能被抓到 → 用 robots.txt 屏蔽,或用 canonical 归一
- 重定向链:
http → https → www两跳 → 让 sitemap 直接指向最终 URL - 大量 404:及时从 sitemap 移除已删除页面
- 重复内容:同一内容多个 URL → canonical
对几百到几千页的站点,预算通常不是瓶颈;但让每一条 sitemap 都指向 200 的 canonical URL 是无论规模都该做的。
七、建立常态化观测
把统计做成一条命令,每个月跑一次:
# /usr/local/bin/crawler-report.sh
#!/usr/bin/env bash
LOG=/var/log/nginx/learning.access.log
DAYS=${1:-30}
SINCE=$(date -d "-$DAYS days" +'%d/%b/%Y:%H:%M:%S')
echo "== 近 $DAYS 天爬虫抓取量 =="
awk -v since="$SINCE" '{
# 提取 [28/Sep/2026:10:00:00
match($0, /\[[0-9]{2}\/[A-Za-z]{3}\/[0-9]{4}:/);
ts = substr($0, RSTART+1, RLENGTH-2);
} { print }' $LOG > /tmp/recent.log
grep -iE 'Googlebot|Bingbot|Baiduspider|Sogou|Bytespider|GPTBot|ClaudeBot|PerplexityBot|Applebot' /tmp/recent.log \
| awk -F'"' '{print $6}' \
| grep -oiE 'Googlebot|Bingbot|Baiduspider|Sogou|Bytespider|GPTBot|ClaudeBot|PerplexityBot|Applebot' \
| sort | uniq -c | sort -rn
echo
echo "== 爬虫遇到的非 2xx =="
grep -iE 'Googlebot|Bingbot|Baiduspider' /tmp/recent.log \
| awk '{print $9}' | sort | uniq -c | sort -rn | head
⚠️ 上面按日期过滤的 awk 只是近似实现(nginx 时间格式解析比较麻烦)。更稳的做法是让 logrotate 每天切一个文件,然后只对最近 N 个文件做统计:
ls -t /var/log/nginx/learning.access.log* | head -7 | xargs zcat -f \
| grep -icE 'googlebot'
八、本章验收
- 能跑出各爬虫 UA 的抓取量统计
- 能列出爬虫遇到的 404 / 5xx / 301 的路径分布
- 已确认爬虫请求 HTML 后是否还需要 JS 才能拿到正文
- 已用双向 DNS 校验至少一个声称是 Googlebot 的 IP
- 统计脚本已保存,可每月复跑
# 一条命令的总览
grep -iE 'googlebot|bingbot|baiduspider|bytespider|GPTBot|ClaudeBot' /var/log/nginx/learning.access.log \
| grep -oiE 'Googlebot|Bingbot|Baiduspider|Bytespider|GPTBot|ClaudeBot' \
| sort | uniq -c | sort -rn
如果某家计数为 0 → 回到第 03/04 章确认是否已提交。
如果抓取量正常但收录为 0 → 问题在内容与结构,进入第 06 章。