Не используя библиотеки для парсинга, распарсить файл логов web-сервера

Python. Не используя библиотеки для парсинга, распарсить файл логов web-сервера В файле лого содержатся строки:

93.180.71.3 - - [17/May/2015:08:05:32 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)"

93.180.71.3 - - [17/May/2015:08:05:23 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)"

80.91.33.133 - - [17/May/2015:08:05:24 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)"

Необходимо получить список кортежей вида: (<remote_addr>, <request_type>,<requested_resource>)

Как пример:

[
...
('141.138.90.60', 'GET', '/downloads/product_2'),
('141.138.90.60', 'GET', '/downloads/product_2'),
('173.255.199.22', 'GET', '/downloads/product_2'),
...
]

Писал:

import re
def reader(filename):
    regexp = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
    with open(filename) as f:
        log = f.read()
        ips_list = re.findall(regexp, log)
    print(ips_list)
if __name__ == '__main__':
    reader('nginx_logs.txt')

Пробовал через regexp получить данные (в коде выше):

regexp = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' 

Но это получает только IP, а следующив тип запроса и куда обращались не вытягивает. Как можно получить данные в виде кортежей?


Ответы (3 шт):

Автор решения: vlad-tim

Можно даже без регулярных выражений

def parse_log_line(log_line: str):
    ip_address, log_line = log_line.split(' - - ')
    date, log_line = log_line.split('] ')

    # Удаление символа [ из строки даты
    date = date.lstrip('[')

    request, other_info = log_line.rsplit(' "-" ')
    
    # Удаление символа " из строки прочей информации
    other_info = other_info.strip('"')

    # Удаление символа " из строки запроса
    request = request.replace('"', '').split(' ')

    return ip_address, date, *request, other_info


lines = ['93.180.71.3 - - [17/May/2015:08:05:32 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)"',
         '93.180.71.3 - - [17/May/2015:08:05:23 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)"',
         '80.91.33.133 - - [17/May/2015:08:05:24 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)"']
parsed_lines = [parse_log_line(line) for line in lines]
→ Ссылка
Автор решения: CrazyElf

Вообще тут можно одними split обойтись, пользуясь тем фактом, что в указанных в данных полях не может быть пробелов:

data = """
93.180.71.3 - - [17/May/2015:08:05:32 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)"
93.180.71.3 - - [17/May/2015:08:05:23 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.21)"
80.91.33.133 - - [17/May/2015:08:05:24 +0000] "GET /downloads/product_1 HTTP/1.1" 304 0 "-" "Debian APT-HTTP/1.3 (0.8.16~exp12ubuntu10.17)"
"""

result = [(lambda x: (x[0],x[5][1:],x[6]))(line.split()) for line in data.split('\n') if line]
print(result)

Вывод:

[('93.180.71.3', 'GET', '/downloads/product_1'), ('93.180.71.3', 'GET', '/downloads/product_1'), ('80.91.33.133', 'GET', '/downloads/product_1')]
→ Ссылка
Автор решения: ykoavlil

Можно использовать библиотеку Fabric, которая позволяет выполнять обычные Linux команды на удаленной сервере.

Например, получить все логи с сервера. Оставить только первый столбец (то есть IP адрес) и отсортировать их.

from fabric import Connection

server_nginx = Connection(
    '192.168.X.X',
    user='root'
)

list_address: list[str] = server_nginx.run(
    command="cat /var/log/nginx/access.log | awk '{print $1}' | sort -u",
    hide=True
).stdout.split("\n")

print(list_address)
→ Ссылка