Проект аудита отелей: основные скрипты и документация
- Краулеры: 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
This commit is contained in:
201
update_website_status.py
Normal file
201
update_website_status.py
Normal file
@@ -0,0 +1,201 @@
|
||||
#!/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('Камчатский край')
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user