把 access.log 转成 CSV:awk 之外的第二条路

来源:互联网 时间:2026-09-09

前几篇的 awk 报表很顺手,但它有两个天花板:一是结果只能打印在终端上,要给不懂命令行的同事看、要丢进 Excel 做透视表,就得有个通用格式;二是复杂逻辑(多条件组合、正则提取、跨行关联)用 awk 写起来越写越拧巴。这时候就该 Python 上场了——把日志解析成 CSV,一条命令跑完,后面随便怎么加工。

解析 Nginx combined 格式用一条正则就够了:IP、时间、请求行、状态码、字节数、来源页、UA,七个字段一次抓齐。写成 Python 脚本,逐行匹配、逐行写入,几百 MB 的日志也是流式处理,内存占用恒定。

import re, csv

LINE = re.compile(
r'(\S+) \S+ \S+ \[([^]]+)\] "(\S+) (\S+) (\S+)" '
r'(\d{3}) (\d+) "([^"]*)" "([^"]*)"'
)

with open("/var/log/nginx/access.log", encoding="utf-8",
errors="replace") as fin, \
open("access.csv", "w", newline="", encoding="utf-8-sig") as fout:
w = csv.writer(fout)
w.writerow(["ip", "time", "method", "url", "proto",
"status", "bytes", "referer", "ua"])
for line in fin:
m = LINE.match(line)
if m:
w.writerow(m.groups())

几个细节决定这脚本好不好用:编码用 utf-8-sig 写出,Excel 双击打开中文不乱码;errors="replace" 容忍日志里偶发的脏字节,不至于跑一半崩掉;正则里 \S+ 抓请求行,畸形行匹配不上就跳过,最后核对行数就能知道丢了多少脏数据。归档的 .gz 压缩日志也不用先解压,把 open 换成 gzip.open 即可,脚本其余部分一行不用改。

# 验证:CSV 行数 vs 日志行数(差值就是畸形行数)
wc -l /var/log/nginx/access.log
wc -l access.csv

# 只导蜘蛛记录:写入前加一行过滤
for line in fin:
m = LINE.match(line)
if m and ("spider" in m.group(9).lower()
or "bot" in m.group(9).lower()):
w.writerow(m.groups())

CSV 到手,Excel 透视表直接开做:行放 url、列放 status、值放计数,蜘蛛抓了什么一目了然;再加个筛选器按 UA 分百度谷歌,比任何命令行都直观。装了 pandas 的话连 Excel 都省了,两行代码出蜘蛛抓取 TOP 榜,比透视表还快。

import pandas as pd

df = pd.read_csv("access.csv", encoding="utf-8-sig")
bot = df[df["ua"].str.contains("spider|bot", case=False,
na=False)]
print(bot["url"].value_counts().head(10))
print(bot["status"].value_counts())

要自动化的话,把脚本挂进 logrotate 的钩子或者 crontab,每天切完日志自动出前一天的 CSV,攒一个月就是完整的原始数据库。

# crontab:每天 0 点 10 分处理切割后的日志
10 0 * * * /usr/bin/python3 /opt/seo/log2csv.py \
/var/log/nginx/access.log.1 /opt/seo/csv/$(date +\%F).csv

收尾摆一下定位:awk 适合即席查询,敲完就走;CSV 适合沉淀数据和协作分发。两条路不冲突,日常诊断用 awk,周报月报用 Python 出 CSV。真正不该做的是死磕其中一条——工具为结论服务,哪个快用哪个。

相关阅读:CSV 是后面所有报表的原料。《SEO 自动化总清单:日、周、月、季各该跑什么》里日报、月报都从这份文件取数,本篇是日志组的数据地基,总纲建议收藏。

相关文章

A5创业网 版权所有

返回顶部