学完这篇,你能只用 awk 一条命令,就从几百万行的 Nginx 原始日志里统计出百度、Google、必应等蜘蛛的抓取总量、抓取时段、热门 URL 和状态码分布,不用装任何额外分析工具。
第一步:确认日志格式,记住字段编号
先看清楚日志长什么样,awk 才能取对字段。执行:
head -n 1 /var/log/nginx/access.log
如果输出是 Nginx 默认 combined 格式,大概长这样:
66.249.66.1 - - [12/Mar/2024:10:23:45 +0800] "GET /article/123 HTTP/1.1" 200 5321 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
awk 默认按空格切分,于是:$1 是客户端 IP,$4 是日期加时间(带左方括号),$7 是请求路径,$9 是状态码,$10 是响应字节数。
注意:UA 字符串里带空格,用空格切分取不到完整 UA。要加 -F'"' 改成按双引号切分,此时 $2 是完整请求行,$6 是完整 UA。
第二步:统计各家蜘蛛的抓取总量
这一步的输出是一张排名表:谁抓得最多。命令如下:
awk -F'"' '{ua=tolower($6)
if (ua ~ /googlebot/) print "Googlebot"
else if (ua ~ /baiduspider/) print "Baiduspider"
else if (ua ~ /bingbot/) print "bingbot"
else if (ua ~ /yandexbot/) print "YandexBot"
else if (ua ~ /sogou/) print "Sogou"
else if (ua ~ /360spider/) print "360Spider"
else if (ua ~ /bytespider/) print "Bytespider"
else if (ua ~ /bot|spider|crawler/) print "其他"
}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
tolower() 把 UA 转成小写,就不用担心大小写不一致。
注意:很多教程用 BEGIN{IGNORECASE=1},那是 gawk 的扩展,macOS 自带的 BSD awk 和部分精简版 awk 不支持,会静默失效。用 tolower() 最稳。
第三步:看某个蜘蛛的状态码分布
想知道百度蜘蛛抓到的页面有没有大量报错,把 baiduspider 换成你要查的名字即可:
awk '$0 ~ /Baiduspider/ {print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
这里用默认空格切分,$9 就是状态码。正常情况下 200 占绝大多数。
第四步:统计蜘蛛每小时的抓取频次
判断抓取是否过于集中、会不会压垮服务器:
awk -F'"' 'tolower($6) ~ /baiduspider/ {
split($1, t, ":")
c[t[2]]++
}
END { for (h in c) printf "%s时 %d次\n", h, c[h] }' /var/log/nginx/access.log | sort
$1 里包含 [12/Mar/2024:10:23:45,按冒号切分后 t[2] 就是小时。
第五步:找出被反复抓取的 URL
这一步能帮你发现蜘蛛是不是在爬一堆无意义的参数页:
awk -F'"' 'tolower($6) ~ /baiduspider/ {split($2, r, " "); print r[2]}' \
/var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
$2 是 GET /article/123 HTTP/1.1,切分后 r[2] 就是路径。
第六步:列出蜘蛛抓到的 404 / 5xx 页面
这些是要修的死链和故障页:
awk -F'"' 'tolower($6) ~ /baiduspider/ {
split($3, s, " ")
if (s[2] ~ /^[45]/) print s[2], $2
}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
$3 是 200 5321 这种形式,s[2] 即状态码。
注意:日志被切割或压缩过时,用 zcat /var/log/nginx/access.log.*.gz | awk ...。日志很大时前面加上 LC_ALL=C 能明显提速。
小结
- combined 格式下取 UA 必须用
-F'"',UA 是 $6;
- 跨 awk 版本兼容用
tolower(),别依赖 IGNORECASE;
- 默认空格切分时状态码是
$9,按双引号切分后要用 split($3,s," ") 取 s[2];
- 统计套路固定为「awk 打印目标 → sort → uniq -c → sort -rn」,再加
head 看 Top N;
- 大日志加
LC_ALL=C,压缩日志用 zcat。