Загрузка данных
# Константа для черного списка IP-адресов
BLACKLIST_IPS = {"85.234.12.1"}
def parse_log_line(line: str) -> dict | None:
"""
Парсит строку лога и возвращает словарь с данными.
Возвращает None, если строка повреждена.
"""
parts = line.split()
# Проверяем, что строка содержит достаточно элементов
if len(parts) < 7:
return None
try:
# Извлекаем IP (0-й элемент)
ip = parts[0]
# Извлекаем пользователя (2-й элемент)
user = parts[2] if parts[2] != "-" else None
# Извлекаем метод (4-й элемент, очищаем от кавычек)
method = parts[4].strip('"')
# Извлекаем путь (5-й элемент)
path = parts[5]
# Извлекаем код ответа (последний элемент)
status_code = int(parts[-1])
return {
"ip": ip,
"user": user,
"method": method,
"path": path,
"status_code": status_code
}
except (ValueError, IndexError):
# Если возникла ошибка (например, код ответа не число)
return None
def is_suspicious(log_dict: dict, blacklist: set) -> bool:
"""
Проверяет, является ли запись подозрительной.
"""
if not log_dict:
return False
# Проверка IP в черном списке
if log_dict["ip"] in blacklist:
return True
# Проверка кода ответа
if log_dict["status_code"] in (401, 403):
return True
# Проверка пути
if log_dict["path"].startswith("/admin"):
return True
return False
def count_failed_logins(logs_list: list) -> dict:
"""
Подсчитывает количество неудачных попыток входа (401) по IP.
"""
failed_logins = {}
for log in logs_list:
if log and log["status_code"] == 401:
ip = log["ip"]
failed_logins[ip] = failed_logins.get(ip, 0) + 1
return failed_logins
def get_most_frequent_path(logs_list: list) -> str:
"""
Определяет самый часто запрашиваемый путь.
"""
path_counter = {}
for log in logs_list:
if log:
path = log["path"]
path_counter[path] = path_counter.get(path, 0) + 1
if not path_counter:
return ""
# Находим путь с максимальным количеством запросов
most_frequent = max(path_counter, key=path_counter.get)
return most_frequent
# Основной блок программы
if __name__ == "__main__":
# Список для всех распарсенных записей
all_logs = []
# Чтение файла лога
try:
with open("network_log.txt", "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if line: # Пропускаем пустые строки
parsed = parse_log_line(line)
if parsed: # Если парсинг успешен
all_logs.append(parsed)
# Если parsed == None, строка пропускается
except FileNotFoundError:
print("Ошибка: Файл network_log.txt не найден!")
exit()
# Запись отчета о подозрительных действиях
try:
with open("suspicious_report.txt", "w", encoding="utf-8") as report:
for log in all_logs:
if is_suspicious(log, BLACKLIST_IPS):
report.write(
f"[ВНИМАНИЕ] IP: {log['ip']} | "
f"Путь: {log['path']} | "
f"Код: {log['status_code']}\n"
)
except IOError:
print("Ошибка при записи в файл suspicious_report.txt")
# Вывод статистики неудачных входов
failed_stats = count_failed_logins(all_logs)
for ip, count in failed_stats.items():
print(f"IP {ip}: {count} неудачных попыток входа")
# Вывод самого частого пути
most_frequent = get_most_frequent_path(all_logs)
if most_frequent:
print(f"Самый частый путь: {most_frequent}")