Анализ Python GET | POST путь из журналов доступа - PullRequest
1 голос
/ 03 апреля 2019

Предположим, у нас есть несколько журналов доступа, подобных этой

83.198.250.175 - - [22 / Mar / 2009: 07: 40: 06 +0100] "GET / images / ht1.gif HTTP / 1.1" 200 61 "http://www.facades.fr/" "Mozilla / 4.0 (совместимо; MSIE 7.0; Windows NT 5.1; Wanadoo 6.7; Orange 8.0)" "-"

65.33.94.190 - - [05 / Apr / 2003: 17: 26: 27 -0500] "POST / samples / dem / tt.php ? X = e2323 HTTP / 1.0" 404 276

151.227.152.48 - - [02 / Jul / 2014: 14: 35: 55 +0100] "GET / css / main.css HTTP / 1.1" 200 4658 "http://stanmore.menczykowski.co.uk/" "Mozilla / 5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit / 537.36 (KHTML, как Gecko) Chrome / 35.0.1916.153 Safari / 537.36"

10.143.2.119 64.103.161.112 - [06 / Jan / 1970: 00: 48: 01 +0000] "GET / right_arrow.jpg HTTP / 1.1" 304 0 "http://64.103.161.112/index_eth_diag.html" «Mozilla / 5.0 (Windows NT 6.1; WOW64) AppleWebKit / 537.36 (KHTML, как Gecko) Chrome / 28.0.1500.95 Safari / 537.36»

Мне нужно получить выделенные части текста после POST и GET (путь к файлам).
формат журнала может отличаться, но тип запроса и путь всегда будут существовать.

Я пытался со следующим, но это не всегда работало, потому что формат журнала не тот

parts = [
    r'(?P<host>\S+)',                   # host %h
    r'\S+',                             # indent %l (unused)
    r'(?P<user>\S+)',                   # user %u
    r'\[(?P<time>.+)\]',                # time %t
    r'"(?P<request>.*)"',               # request "%r"
    r'(?P<status>[0-9]+)',              # status %>s
    r'(?P<size>\S+)',                   # size %b (careful, can be '-')
    r'"(?P<referrer>.*)"',              # referrer "%{Referer}i"
    r'"(?P<agent>.*)"',                 # user agent "%{User-agent}i"
]

def get_structured_access_logs_list(access_logs):
    pattern = re.compile(r'\s+'.join(parts) + r'\s*\Z')

    # Initialize required variables
    log_data = []

    # Get components from each line of the log file into a structured dict
    for line in access_logs:
        try:
            log_data.append(pattern.match(line).groupdict())
        except:
            pass
    return log_data

def parse_path(request_string) :
    rx = re.compile(r'^(?:GET|POST)\s+([^?\s]+).*$', re.M)
    return rx.findall(request_string)


def get_file_paths(access_logs_list):
    file_path_set = set()
    for dict in access_logs_list:
        if 'request' in dict.keys():
            file_name = parse_path(dict['request'])[0] # passing a single line, the list will contain only 1 element
            if file_name is not None:
                file_path_set.add(full_path)
    return accessed_file_set

UPDATE: после корректировки кода функция get_file_paths вернет набор, содержащий полный путь к файлам, доступ к которым осуществляется в журналах доступа

def parse_path(request_string) :
    rx = re.compile(r'"(?:GET|POST)\s+([^\s?]*)', re.M)
    return rx.findall(request_string)


def get_file_paths(access_logs):
    file_set = set()
    for line in access_logs:
            matches = parse_accessed_file_name_list(line) # passing a single line, the list will contain only 1 element
            if matches is None or len(matches) <= 0:
                continue
            full_path = root_path + matches[0]
            if os.path.isfile(full_path):
                file_set.add(full_path)
    return file_set

Ответы [ 3 ]

2 голосов
/ 03 апреля 2019

Вы можете использовать

(?x)^
    (?P<host>\S+)                         \s+         # host %h
    \S+                                   \s+         # indent %l (unused)
    (?P<user>\S+)                         \s+         # user %u
    \[(?P<time>.*?)\]                     \s+         # time %t
    "\S+\s+(?P<request>[^"?\s]*)[^"]*"    \s+         # request "%r"
    (?P<status>[0-9]+)                    \s+         # status %>s
    (?P<size>\S+)                      (?:\s+         # size %b (careful, can be '-')
    "(?P<referrer>[^"?\s]*[^"]*)"         \s+         # referrer "%{Referer}i"
    "(?P<agent>[^"]*)"                 (?:\s+         # user agent "%{User-agent}i"
    "[^"]*"                            )? )?          # unused
$

См. Демоверсию regex .

Внесено много незначительных улучшений (см. [^"]* вместо .*), основными из которых являются необязательные группы без захвата для соответствия полей реферера и агента, которые могут отсутствовать и шаблон request, который выглядит как (?P<request>[^"?\s]*) и захватывает только 0 или более символов, кроме пробелов, ? и " char, тогда как последующие [^"]*" соответствуют остальной части поля.

Также имеет смысл скомпилировать шаблон один раз , а не так, как вы это делаете при обработке каждой строки.

Модификатор (?x) включает режим свободного пробела, позволяющий форматировать шаблон в несколько строк и добавлять комментарии.

Демо Python :

import re
pattern = re.compile(r"""(?x)^
    (?P<host>\S+)                         \s+         # host %h
    \S+                                   \s+         # indent %l (unused)
    (?P<user>\S+)                         \s+         # user %u
    \[(?P<time>.*?)\]                     \s+         # time %t
    "\S+\s+(?P<request>[^"?\s]*)[^"]*"    \s+         # request "%r"
    (?P<status>[0-9]+)                    \s+         # status %>s
    (?P<size>\S+)                      (?:\s+          # size %b (careful, can be '-')
    "(?P<referrer>[^"?\s]*[^"]*)"         \s+         # referrer "%{Referer}i"
    "(?P<agent>[^"]*)"                 (?:\s+         # user agent "%{User-agent}i"
    "[^"]*"                           )?)?            # optional argument (unused)
$""")

def get_structured_access_logs_list(access_logs):
    # Initialize required variables
    log_data = []
    # Get components from each line of the log file into a structured dict
    for line in access_logs:
        try:
            log_data.append(pattern.match(line).groupdict())
        except:
            pass
    return log_data

lines = ['83.198.250.175 - - [22/Mar/2009:07:40:06 +0100] "GET /images/ht1.gif HTTP/1.1" 200 61 "http://www.facades.fr/" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Wanadoo 6.7; Orange 8.0)" "-"',
'65.33.94.190 - - [05/Apr/2003:17:26:27 -0500] "POST /samples/dem/tt.php?x=e2323 HTTP/1.0" 404 276',
'151.227.152.48 - - [02/Jul/2014:14:35:55 +0100] "GET /css/main.css HTTP/1.1" 200 4658 "http://stanmore.menczykowski.co.uk/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36"',
'10.143.2.119 64.103.161.112 - [06/Jan/1970:00:48:01 +0000] "GET /right_arrow.jpg HTTP/1.1" 304 0 "http://64.103.161.112/index_eth_diag.html" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36"']
for res in get_structured_access_logs_list(lines):
    print(res)
1 голос
/ 03 апреля 2019

Поскольку ваше регулярное выражение очень универсально (вы используете \S и ., которые очень широкие), почему бы вам не использовать напрямую:

"(?:GET|POST)\s+([^\s?]*)

[^\s?] соответствует всем символам, которыене пробелы и не вопросительные знаки.

См. здесь демо.

1 голос
/ 03 апреля 2019

Вы можете использовать это регулярное выражение и получить путь от group1,

^.*?"(?:GET|POST) ([^\s?]+)

Демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...