Files
hotels/update_website_status.py
Фёдор 0cf3297290 Проект аудита отелей: основные скрипты и документация
- Краулеры: smart_crawler.py, regional_crawler.py
- Аудит: audit_orel_to_excel.py, audit_chukotka_to_excel.py
- РКН проверка: check_rkn_registry.py, recheck_unclear_rkn.py
- Отчёты: create_orel_horizontal_report.py
- Обработка: process_all_hotels_embeddings.py
- Документация: README.md, DB_SCHEMA_REFERENCE.md
2025-10-16 10:52:09 +03:00

202 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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('Камчатский край')