【问题标题】:Handling web-log files as a CSV with Python使用 Python 将 Web 日志文件处理为 CSV
【发布时间】:2026-01-04 17:45:01
【问题描述】:

我正在使用 Python 3 CSV 阅读器将一些网络日志文件读入命名元组。 我无法控制日志文件结构,并且有多种类型。

分隔符是一个空格( ),问题是某些日志文件格式在时间戳中放置了一个空格,如下面的日志文件 2。然后 CSV 阅读器将日期/时间戳读取为两个字段。

日志文件 1

73 58 2993 [22/Jul/2016:06:51:06.299] 2[2] "GET /example HTTP/1.1"
13 58 224 [22/Jul/2016:06:51:06.399] 2[2] "GET /example HTTP/1.1"

日志文件 2

13 58 224 [22/Jul/2016:06:51:06 +0000] 2[2] "GET /test HTTP/1.1"
153 38 224 [22/Jul/2016:06:51:07 +0000] 2[2] "GET /test HTTP/1.1"

日志文件通常在方引号内有时间戳,但我找不到将它们作为“引号”处理的方法。最重要的是,方括号也不总是在日志中用作引号(请参阅日志后面的 [2])。

我已经阅读了Python 3 CSV Reader documentation,包括有关方言的内容,但似乎没有任何东西可以处理封闭的方括号。

如何自动处理这种情况?

【问题讨论】:

    标签: python python-3.x csv


    【解决方案1】:

    这样就可以了,您需要使用正则表达式代替 sep。
    例如,这会将 NGinx 日志文件解析为 pandas.Dataframe:

    import pandas as pd
    
    df = pd.read_csv(log_file,
                  sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])',
                  engine='python',
                  usecols=[0, 3, 4, 5, 6, 7, 8],
                  names=['ip', 'time', 'request', 'status', 'size', 'referer', 'user_agent'],
                  na_values='-',
                  header=None
                    )
    

    编辑:

    line = '172.16.0.3 - - [25/Sep/2002:14:04:19 +0200] "GET / HTTP/1.1" 401 - "" "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827"'
    regex = '([(\d\.)]+) - - \[(.*?)\] "(.*?)" (\d+) - "(.*?)" "(.*?)"'
    
    import re
    print re.match(regex, line).groups()
    

    输出将是一个包含 6 条信息的元组

    ('172.16.0.3', '25/Sep/2002:14:04:19 +0200', 'GET / HTTP/1.1', '401', '', 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.1) Gecko/20020827')
    

    【讨论】:

    • 我猜这需要 Pandas 库。很高兴知道这是可能的,但我希望只使用标准库。
    • 添加了一个只有正则表达式的版本,而不必添加熊猫
    【解决方案2】:

    蛮力!我连接了 2 个时间字段,以便可以在需要时解释时间戳。

       data.csv = 
    13 58 224 [22/Jul/2016:06:51:06.399] 2[2] "GET /example HTTP/1.1" 
    13 58 224 [22/Jul/2016:06:51:06 +0000] 2[2] "GET /test HTTP/1.1"
    
    
    import csv
    
    with open("data.csv") as f:
        c = csv.reader(f, delimiter=" ")
        for row in c:
            if len(row) == 7:
                r = row[:3] + [row[3] + row[4]] + row[5:]
                print(r)
            else:
                print(row)
    
    ['13', '58', '224', '[22/Jul/2016:06:51:06.399]', '2[2]', 'GET /example HTTP/1.1']
    ['13', '58', '224', '[22/Jul/2016:06:51:06+0000]', '2[2]', 'GET /test HTTP/1.1']
    

    【讨论】: