使用正则表达式解析损坏的 Apache 日志

Parsing corrupt Apache logs using regex

我正在编写一个 Python 3.7.2 程序来解析 Apache 日志以查找所有成功的响应代码。我现在已经编写了正则表达式,它将所有正确的 Apache 日志条目解析为 [origin] [date/time] [HTML method/file/protocol] [response code] 和 [file size] 的单个元组] 然后我只是检查响应代码是否为 3xx。问题是有几个条目已损坏,有些损坏到无法读取,所以我在程序的不同部分将它们删除。 method/protocol 项上的几个只是缺少结束 "(引号),导致每次我解析该行时它都会抛出错误。我想我需要对 " OR 空格使用 RegEx Or 表达式,但是似乎将引号分成不同的元组项而不是寻找说,"GET 613.html HTTP/1.0" OR "GET 613.html HTTP/1.0 我是正则表达式的新手并且完全被难住了,任何人都可以解释什么我做错了吗?

我应该注意到日志中的一些信息已经被清除,它只显示 'local' 或 'remote' 而不是原始 IP,并且 OS/browser 信息被完全删除。

这是适用于有效条目的相关元组项的正则表达式:“(.*)?”我也试过:

"(.*)?("|\s) - 创建另一个元组项并仍然抛出错误

这是日志条目的片段,包括最后一个缺少的条目,它正在关闭“

本地 - - [27/Oct/1994:18:47:03 -0600] "GET index.html HTTP/1.0" 200 3185
本地 - - [27/Oct/1994:18:48:53 -0600] "GET index.html HTTP/1.0" 404 -
本地 - - [27/Oct/1994:18:49:55 -0600] "GET index.html HTTP/1.0" 303 3185
本地 - - [27/Oct/1994:18:50:25 -0600] "GET 612.html HTTP/1.0" 404 -
本地 - - [27/Oct/1994:18:50:41 -0600] "GET index.html HTTP/1.0" 200 388
local - - [27/Oct/1994:18:50:52 -0600] "GET 613.html HTTP/1.0 303 728

regex = '([(\w+)]+) - - \[(.*?)\] "(.*)?" (\d+) (\S+)'
import re

with open("validlogs.txt") as validlogs:                
    i = 0
    array = []
    successcodes = 0
    for line in validlogs:                               
        array.append(line)
        loglength = len(array)                               

    while (i < loglength):                               
        line = re.match(regex, array[i]).groups()
        if(line[3].startswith("3")):
            successcodes+=1
        i+=1
    print("Number of successcodes: ", successcodes)

解析上面的日志响应应该给出 Number of success codes: 2 相反,我得到:追溯(最近一次通话): 文件 "test.py",第 24 行,位于 line = re.match(regex, array[i]).groups() AttributeError: 'NoneType' 对象没有属性 'groups'

因为(我相信)正则表达式正在明确寻找 " 并且无法处理缺少它的行条目。

所以我最初使用 re.match 和 ([(\w+)]+) - - \[(.*?)\] "(.*?)" (\d+) (\d+) 以及 Try: / Except: continue 代码来解析所有实际匹配模式的日志。由于 ~750,000 行中的 ~100,000 行不符合正确的 Apache 日志模式,我最终将我的代码更改为 re.search 并使用更小的段。

例如:

with open("./http_access_log.txt") as logs:             
    for line in logs:
        if re.search('\s*(30\d)\s\S+', line):         #Checking for 30x redirect codes
            redirectCounter += 1  

我读到 re.match 比 re.search 快,但我觉得能够准确捕获最可能的日志条目(这处理了大约 2000 行以外的所有行,其中大部分有没有可用信息)更重要。