#!/usr/bin/env python3 """ Обновление статусов доступности сайтов на основе результатов краулинга """ import psycopg2 from urllib.parse import unquote import re # Конфигурация БД DB_CONFIG = { 'host': "147.45.189.234", 'port': 5432, 'database': "default_db", 'user': "gen_user", 'password': unquote("2~~9_%5EkVsU%3F2%5CS") } def update_website_statuses(log_file_path): """Обновление статусов на основе лог-файла краулера""" conn = psycopg2.connect(**DB_CONFIG) cur = conn.cursor() # Паттерны для определения типов ошибок error_patterns = { 'timeout': r'Timeout \d+ms exceeded', 'connection_refused': r'ERR_CONNECTION_REFUSED', 'dns_error': r'ERR_NAME_NOT_RESOLVED', 'ssl_error': r'ERR_SSL_PROTOCOL_ERROR|ERR_CERT_DATE_INVALID', 'http_error': r'Ошибка загрузки: (403|404|500)', 'invalid_url': r'Cannot navigate to invalid URL' } # Читаем лог-файл with open(log_file_path, 'r', encoding='utf-8') as f: log_content = f.read() # Находим все отели и их ошибки hotel_pattern = r'🏨 «(.+?)»\n.*?🌐 (.+?)\n' hotels = re.findall(hotel_pattern, log_content, re.DOTALL) stats = { 'accessible': 0, 'timeout': 0, 'connection_refused': 0, 'dns_error': 0, 'ssl_error': 0, 'http_error': 0, 'invalid_url': 0, 'not_checked': 0 } for hotel_name, website in hotels: # Нормализуем URL website = website.strip() if not website.startswith(('http://', 'https://')): website = 'https://' + website # Ищем секцию этого отеля в логе hotel_section_pattern = f'🏨 «{re.escape(hotel_name)}».*?(?=🏨 «|======================================================================\\n📊 ИТОГИ:)' hotel_section_match = re.search(hotel_section_pattern, log_content, re.DOTALL) if not hotel_section_match: continue hotel_section = hotel_section_match.group(0) # Определяем статус status = 'not_checked' # Проверяем на успешность if '✓ Спарсено' in hotel_section and '✓ Сохранено' in hotel_section: status = 'accessible' stats['accessible'] += 1 else: # Проверяем типы ошибок for error_type, pattern in error_patterns.items(): if re.search(pattern, hotel_section): status = error_type stats[error_type] += 1 break if status == 'not_checked': stats['not_checked'] += 1 # Обновляем статус в БД try: cur.execute(''' UPDATE hotel_main SET website_status = %s WHERE website_address LIKE %s OR website_address LIKE %s OR website_address LIKE %s ''', (status, f'%{website.replace("https://", "").replace("http://", "").split("/")[0]}%', f'%{website}%', website.replace("https://", "").replace("http://", "").split("/")[0])) except Exception as e: print(f"Ошибка обновления для {hotel_name}: {e}") conn.commit() cur.close() conn.close() return stats def generate_report(region_name='Камчатский край'): """Генерация отчета по доступности сайтов""" conn = psycopg2.connect(**DB_CONFIG) cur = conn.cursor() # Получаем статистику cur.execute(''' SELECT website_status, COUNT(*) as count, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 2) as percentage FROM hotel_main WHERE region_name ILIKE %s GROUP BY website_status ORDER BY count DESC ''', (f'%{region_name}%',)) stats = cur.fetchall() print(f"\n{'='*80}") print(f"📊 ОТЧЕТ О ДОСТУПНОСТИ САЙТОВ: {region_name}") print(f"{'='*80}\n") status_labels = { 'accessible': '✅ Сайт доступен', 'no_website': '❌ Сайт отсутствует', 'timeout': '⏱️ Таймаут (сайт медленный)', 'connection_refused': '🚫 Соединение отклонено', 'dns_error': '🔍 DNS ошибка (домен не найден)', 'ssl_error': '🔒 SSL ошибка (проблема с сертификатом)', 'http_error': '⚠️ HTTP ошибка (403/404/500)', 'invalid_url': '❓ Неверный URL', 'not_checked': '⏳ Не проверено' } for status, count, percentage in stats: label = status_labels.get(status, status) print(f"{label:45} {count:5} ({percentage:5.2f}%)") # Получаем список недоступных отелей print(f"\n{'='*80}") print("🔴 ОТЕЛИ С НЕДОСТУПНЫМИ САЙТАМИ:") print(f"{'='*80}\n") cur.execute(''' SELECT full_name, website_address, website_status FROM hotel_main WHERE region_name ILIKE %s AND website_status NOT IN ('accessible', 'no_website', 'not_checked') ORDER BY website_status, full_name LIMIT 20 ''', (f'%{region_name}%',)) problematic = cur.fetchall() for name, website, status in problematic: status_icon = { 'timeout': '⏱️', 'connection_refused': '🚫', 'dns_error': '🔍', 'ssl_error': '🔒', 'http_error': '⚠️', 'invalid_url': '❓' }.get(status, '❓') print(f"{status_icon} {name}") print(f" 🌐 {website}") print(f" 📋 Статус: {status}") print() cur.close() conn.close() if __name__ == "__main__": import sys if len(sys.argv) > 1: log_file = sys.argv[1] print(f"📖 Обработка лог-файла: {log_file}") stats = update_website_statuses(log_file) print("\n📊 СТАТИСТИКА ОБНОВЛЕНИЯ:") for status, count in stats.items(): print(f" {status}: {count}") # Генерируем отчет generate_report('Камчатский край')