Загрузка данных


import collections

# Константы
BLACKLIST_IPS = {"85.234.12.1"}


def parse_log_line(line: str) -> dict:
    """Извлекает данные из строки лога и возвращает словарь."""
    parts = line.split()
    if len(parts) < 8:
        return None

    try:
        # Извлекаем и очищаем данные
        ip = parts[0]
        user = parts[2] if parts[2] != "-" else None
        
        # Метод: берем 4-й элемент, убираем лишние кавычки
        method = parts[4].replace('"', '')
        
        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 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_counts = {}
    for log in logs_list:
        if log["status_code"] == 401:
            ip = log["ip"]
            failed_counts[ip] = failed_counts.get(ip, 0) + 1
    return failed_counts


def get_most_frequent_path(logs_list: list) -> str:
    """Находит самый популярный URL-путь."""
    paths = [log["path"] for log in logs_list]
    if not paths:
        return None
    # Используем Counter для удобного подсчета
    return collections.Counter(paths).most_common(1)[0][0]


def main():
    all_logs = []
    
    # 1. Чтение и парсинг файла
    with open("network_log.txt", "r", encoding="utf-8") as f:
        for line in f:
            line = line.strip()
            if not line:
                continue
            
            parsed_data = parse_log_line(line)
            if parsed_data:
                all_logs.append(parsed_data)
            else:
                continue

    # Тестирование парсинга первой строки (из этапа 1 задания)
    if all_logs:
        print("--- Тест парсинга первой строки ---")
        print(all_logs[0])
        print("-" * 35)

    # 2. Формирование отчета о подозрительной активности
    with open("suspicious_report.txt", "w", encoding="utf-8") as report:
        for log in all_logs:
            if is_suspicious(log, BLACKLIST_IPS):
                report_line = f"[ВНИМАНИЕ] IP: {log['ip']} | Путь: {log['path']} | Код: {log['status_code']}\n"
                report.write(report_line)

    # 3. Вывод статистики в консоль
    failed_logins = count_failed_logins(all_logs)
    for ip, count in failed_logins.items():
        print(f"IP {ip}: {count} неудачных попыток входа")
    
    most_popular = get_most_frequent_path(all_logs)
    print(f"\nСамый популярный путь: {most_popular}")


if __name__ == "__main__":
    main()