You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写正则捕获组解析自定义日志并导出为CSV文件?

如何用Python正则解析自定义日志并导出为CSV?

我完全懂你现在的困扰——单独写的正则片段能匹配单个字段,但组合起来就抓不到内容了对吧?这其实是因为没有考虑日志的完整结构,忽略了中间的主机名、服务名这些过渡部分,而且还要兼容像logrotate这种不带PID的日志条目。下面我给你一步步解决这个问题:

第一步:编写兼容所有日志的正则表达式

先看你的日志结构,统一格式是:

日期 时间 主机名 服务标识[PID]: 消息内容
(其中服务标识可能是sshd(pam_unix)或者logrotate,后者没有PID)

所以我们需要写一个能覆盖两种情况的正则,把四个字段都用捕获组对应上:

import re

log_pattern = r'^(\w{3} \d{2}) (\d{2}:\d{2}:\d{2}) \w+ (?:\w+\(\w+\)\[(\d+)\]|\w+): (.*)$'

我来拆解一下这个正则:

  • ^(\w{3} \d{2}):匹配开头的日期(比如Jun 15),作为第一个捕获组对应Date
  • (\d{2}:\d{2}:\d{2}):匹配时间,第二个捕获组对应Time
  • \w+:匹配主机名(比如combo),这里不需要捕获,所以直接跳过
  • (?:\w+\(\w+\)\[(\d+)\]|\w+):这是一个非捕获组,用来处理两种服务情况:
    • \w+\(\w+\)\[(\d+)\]:匹配带PID的服务(比如sshd(pam_unix)[20897]),里面的(\d+)是第三个捕获组对应PID
    • \w+:匹配不带PID的服务(比如logrotate),这种情况第三个捕获组会是None
  • : (.*)$:匹配冒号后的所有内容作为消息,第四个捕获组对应Message

第二步:编写完整的Python解析代码

下面是把日志解析成字典,再导出为CSV的完整代码:

import re
import csv

# 定义正则模式
log_pattern = r'^(\w{3} \d{2}) (\d{2}:\d{2}:\d{2}) \w+ (?:\w+\(\w+\)\[(\d+)\]|\w+): (.*)$'
regex = re.compile(log_pattern)

# 日志样本(你可以替换成读取文件的代码,比如用open()逐行读取)
logs = [
    "Jun 15 02:04:59 combo sshd(pam_unix)[20897]: authentication failure; logname= uid=0 euid=0 tty=NODEVssh ruser= rhost=220-135-151-1.hinet-ip.hinet.net user=root",
    "Jun 15 02:04:59 combo sshd(pam_unix)[20898]: authentication failure; logname= uid=0 euid=0 tty=NODEVssh ruser= rhost=220-135-151-1.hinet-ip.hinet.net user=root",
    "Jun 15 04:06:18 combo su(pam_unix)[21416]: session opened for user cyrus by (uid=0)",
    "Jun 15 04:06:19 combo su(pam_unix)[21416]: session closed for user cyrus",
    "Jun 15 04:06:20 combo logrotate: ALERT exited abnormally with [1]",
    "Jun 15 04:12:42 combo su(pam_unix)[22644]: session opened for user news by (uid=0)",
    "Jun 15 04:12:43 combo su(pam_unix)[22644]: session closed for user news"
]

# 解析每条日志
parsed_logs = []
for log in logs:
    match = regex.match(log)
    if match:
        date, time, pid, message = match.groups()
        parsed_logs.append({
            "Date": date,
            "Time": time,
            "PID": pid if pid else "",  # 无PID时设为空字符串,避免CSV出现None
            "Message": message.strip()
        })

# 导出为CSV文件
with open('parsed_logs.csv', 'w', newline='', encoding='utf-8') as csvfile:
    fieldnames = ['Date', 'Time', 'PID', 'Message']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    
    writer.writeheader()
    for entry in parsed_logs:
        writer.writerow(entry)

为什么之前的组合正则失效?

你之前单独写的字段正则没问题,但组合时忽略了日志中间的主机名、服务名这些“无关但必须匹配”的部分,而且没考虑logrotate这种不带PID的特殊情况,导致正则无法匹配整条日志。上面的正则通过非捕获组处理了两种服务格式,同时跳过不需要的主机名,就能完美匹配所有日志条目了。

测试一下代码,导出的CSV会包含所有你需要的四个字段,无PID的条目也会正确处理为空。

内容的提问来源于stack exchange,提问作者Aaron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 16:27:27