【问题标题】:How to extract data from a web server log file, and also parse the request line portion?如何从 Web 服务器日志文件中提取数据,并解析请求行部分?
【发布时间】:2016-02-12 20:41:33
【问题描述】:

下面给出了我试图从中提取信息的行示例。

[02/Jan/2015:08:07:32] "GET /click?article_id=162&user_id=5475 HTTP/1.1" 200 4352
[02/Jan/2015:08:08:43] "GET /click?article_id=139&user_id=19550 HTTP/1.1" 200 3078
[02/Jan/2015:08:09:01] "GET /click?article_id=87&user_id=9408 HTTP/1.1" 200 2005
[02/Jan/2015:08:09:18] "GET /click?article_id=175&user_id=9408 HTTP/1.1" 200 3467

我尝试了几种方法。其中之一是

with open('C:/Users/.../access_log/access.log', 'r') as read:      
   for line in read:
      if "click?" in line:
          article_id = line.split('article_id=')[1]
          user_id = line.split('user_id=')[1]
          article.write(article_id)
          user.write(user_id)

我需要提取datearticle_idauthor_id 和最后两组数字。通过使用上面的代码,我的输出看起来像这样

对于 user_id 文件,输出看起来像

  5475 HTTP/1.1" 200 4352

这里的 5475 是我需要的 id,但该行的其余部分随它一起提供。同样对于article_id 文件,输出类似于

   162&user_id=5475 HTTP/1.1" 200 4352

这里 162 是我需要的值,但我再次得到该值的其余部分。

我尝试的第二种方法是这样的

for line in read:
   article_id = re.match('.*article_id=(\d+)', line)
   user_id = re.match('.*user_id=(\d+)', line)
   if article_id and article_id.lastindex > 0:
       ids.write(article_id.group(1))

然后我得到这样的输出

  1621398717554254614225905016411314518885592112332

我无法在 excel 中执行此操作,因为 excel 需要处理的数据点太多,并且所有文件都无法正确加载。另外我需要确保当我从每一行中提取数据点(datearticle_idauthor_id,....)时,每个数据点对应于同一行的另一个数据点,所以我可以查看是否有缺失值。

本质上是有办法让我把它变成这样的

[02/Jan/2015:08:07:32] "GET /click?article_id=162&user_id=5475 HTTP/1.1" 200 4352
[02/Jan/2015:08:08:43] "GET /click?article_id=139&user_id=19550 HTTP/1.1" 200 3078
[02/Jan/2015:08:09:01] "GET /click?article_id=87&user_id=9408 HTTP/1.1" 200 2005
[02/Jan/2015:08:09:18] "GET /click?article_id=175&user_id=9408 HTTP/1.1" 200 3467

进入这个

      Date                   Article_id    user_id       Response_code  Content size

      02/Jan/2015:08:07:32   162           5475          200            4352                     
      02/Jan/2015:08:08:43   139           19950         200            3078

【问题讨论】:

标签: python text-files


【解决方案1】:

您可以使用这个简单的正则表达式来拆分您的行:

re.split(r' ".*?=|&.*?=| .*?" ', line)

输出:

['[02/Jan/2015:08:07:32]', '162', '5475', '200 4352']

你也可以使用findall:

re.findall(r'\[(.*?)\].*?(\d+).*?(\d+).*?(\d+)\s(\d+)', line)

输出:

[('02/Jan/2015:08:07:32', '162', '5475', '200', '4352')]

您可以将 re.findall 分配给变量并使用对元素的简单访问,例如:

data = re.findall(r'\[(.*?)\].*?(\d+).*?(\d+).*?(\d+)\s(\d+)', line)
print data[0][0]
02/Jan/2015:08:07:32

注意:如果缺少任何值,您会看到它,但我的解决方案不会显示特别缺少哪个值。

【讨论】:

  • OP 想要分别解析 'response_code' 和 'content_size' 并且 'date' 不应包含 '[]'
  • @MaxU 好的,感谢您的投票,我添加了一些 findall 以返回操作所需的内容
  • 我还回了一个人情:)
  • @EthanFurman,如果它解决了操作的问题,你为什么要否决我的答案? OP没有这样的要求来做你刚才说的。
  • 仅使用 findall 无法说出缺少哪一个,我不想将其包装在额外的逻辑中并为 OP 完成所有工作,但是您一直在投票,您是很棒。
【解决方案2】:

试试这个:

from __future__ import print_function
import re

parse_re = r'\[([^\[\]]*)\]\s+.*?article_id=(\d+).*?user_id=(\d+)[^\"]*?\"\s+(\d+)\s+(\d+)'

with open('apache.log', 'r') as f:
    data = f.readlines()

for line in data:
    m = re.match(parse_re, line)
    if m:
        (date, article_id, user_id, response_code, content_size) =m.groups()
        print(date, article_id, user_id, response_code, content_size)

输出:

02/Jan/2015:08:07:32 162 5475 200 4352
02/Jan/2015:08:08:43 139 19550 200 3078
02/Jan/2015:08:09:01 87 9408 200 2005
02/Jan/2015:08:09:18 175 9408 200 3467

【讨论】:

  • 这不处理article_iduser_id 的缺失值。
【解决方案3】:

@Amit :我有下面的代码与 re

import re
a='[02/Jan/2015:08:07:32] "GET /click?article_id=162&user_id=5475 HTTP/1.1" 200 4352 '

for line in a:
    match =  re.search("\[(\d+\/[A-Za-z]+\/\d+\:\d+\:\d+\:\d+)\] \"GET\/click\article_id\=(\d+)\&user_id\=(\d+) HTTP\/1\.1\" (\d+) (\d+)",line)
    if match: 
         print "%s   %s  %s %s %s  " %( match.group(1), match.group(2), match.group(3), match.group(4), match.group(5) )

output 
02/Jan/2015:08:07:32   162  5475 200 4352

【讨论】:

    【解决方案4】:

    为了解析GET 段,并能够判断何时丢失,一个小函数将完成这项工作:

    def extract_get_fields(line):
        # fields should be a list desired field names
        if 'GET' not in line:
            return None
        result = {}
        line = line.split('GET ', 1)[1]
        line = line.rsplit('"', 1)[0]
        line = line.rsplit(None, 1)[0]
        # line is now the segment between GET and the last double quote
        result['page'], crumbs = line.split('?')
        for crumb in crumbs.split('&'):
            name, value = crumb.split('=')
            result[name] = value
        return result
    

    并在使用中:

    # second and third lines are missing pieces
    data = [
        '[02/Jan/2015:08:07:32] "GET /click?article_id=162&user_id=5475 HTTP/1.1" 200 4352',
        '[02/Jan/2015:08:08:43] "GET /click?article_id=139 HTTP/1.1" 200 3078',
        '[02/Jan/2015:08:09:01] "GET /click?user_id=9408 HTTP/1.1" 200 2005',
        '[02/Jan/2015:08:09:18] "GET /click?article_id=175&user_id=9408 HTTP/1.1" 200 3467',
        ]
    
    for line in data:
        result = extract_get_fields(line)
        if result is None:
            # wasn't a GET line, skip it
            continue
        if result['page'] != '/click':
            # wasn't a click page, skip it
            continue
        article_id = result.get('article_id', '')
        user_id = result.get('user_id', '')
        print('article_id: %5s   user_id: %s' % (article_id, user_id))
    

    导致:

    article_id:   162   user_id: 5475
    article_id:   139   user_id: 
    article_id:         user_id: 9408
    article_id:   175   user_id: 9408
    

    注意:您需要增强和/或结合其他答案才能获得date 和其他字段。

    【讨论】:

      猜你喜欢
      • 2012-09-09
      • 2015-05-18
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 2010-12-03
      • 2021-01-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多