使用正则表达式解析日志时不断出现“NoneType”错误

Keep getting `NoneType` errors when parsing logs with regex

下面是两个日志的示例。我正在尝试获取 ip、date_time、方法、这部分 (/071300/242153 HTTP/1.1")、响应代码(只是 404/200 部分),其余部分在一组:

66.249.69.97 - - [24/Sep/2014:22:25:44 +0000] "GET /071300/242153 HTTP/1.1" 404 514 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

71.19.157.174 - - [24/Sep/2014:22:26:12 +0000] "GET /error HTTP/1.1" 404 505 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.94 Safari/537.36"

我的函数如下所示:

def parse_logs(logs):
  log_list = []
  for log in logs:
    p = re.compile(r'''(?P<ip_addr>\d+(\.\d+){3}) - - \[(?P<date_time>.+?)\] (?P<http_method>\".+?\") (?P<return_code>\d+) \d+ "-" (?P<client>\".+?\")''')

    m = p.search(log)

    log_list.append([m.group('ip_addr'), m.group('date_time'), m.group('http_method'), m.group('return_code'), m.group('client')])

rdd_prepped = parse_logs(rdd.take(5))

当我将这些日志的列表传递给函数并 运行 它时,我不断收到错误消息: AttributeError: 'NoneType' object has no attribute 'collect'.

当我在 m = p.search(log) 下放置 print(m.group('ip')) 行时,出现错误:

AttributeError: 'NoneType' object has no attribute 'group'

为什么我总是收到 NoneTypes?我正在使用 Python2.7 btw.

首次发布时,正则表达式如下所示:

p = re.compile(r'''(?P<ip>\d+(\.\d+){3}) - - \[(?P<date_time>.+?)\] (?P<method>\".+?\") \
    (?P<response_code>\d+) \d+ "-" (?P<client>\".+?\")''')

注意第一行末尾的续行符(“\”)。但该模式也包含在三重引号中。因此该模式包括文本 '\n '(斜线 + 换行符 + 缩进)。结果,模式不匹配。

在一行中重写模式,它应该可以工作:

p = re.compile(r'''(?P<ip>\d+(\.\d+){3}) - - \[(?P<date_time>.+?)\] (?P<method>\".+?\") (?P<response_code>\d+) \d+ "-" (?P<client>\".+?\")''')

对于复杂的正则表达式,我喜欢使用verbose模式:

regex = re.compile("""
    (?P<ip>\d+(?:\.\d+){3})     # four, dot-separated sets of digits
    .*?                         # skip ahead
    \[(?P<date_time>.*?)\]      # date time is everything between '[ ]'
    .*?                         # skip 
    "(?P<method>.*?)"           # method is everything between quotes
    .*?                         # skip 
    (?P<response_code>\d+)      # multiple digits
    .*?                         # skip
    "-"                         # don't care
    .*?                         #
    "(?P<client>.*?)"           # client is everything between quotes
    """, re.VERBOSE)

还有一些事情:

如果您希望正则表达式匹配(几乎)日志中的每一行,那么您应该 print/log 任何不匹配的行。这有助于捕获正则表达式中的错误,或者当有人在不通知您的情况下更改日志格式时。

将 re.compile 步骤移出循环。

MatchObject.group() 可以采用多个参数和 returns 列出的组的元组。

def parse_logs(logs):
  log_list = []

  p = re.compile(...whichever regex style you like...)

  for log in logs:

    m = p.search(log)

    if m:
      log_list.append(m.group('ip_addr', 'date_time', 'http_method, 
                              'return_code', 'client'))
    else:
        print(log)

rdd_prepped = parse_logs(rdd.take(5))