Files
hotels/update_website_status.py

202 lines
6.7 KiB
Python
Raw Normal View History

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