Проект аудита отелей: основные скрипты и документация

- Краулеры: 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:
Фёдор
2025-10-16 10:52:09 +03:00
parent 545e199389
commit 0cf3297290
105 changed files with 28743 additions and 0 deletions

226
CRAWLER_WORKFLOW.md Normal file
View File

@@ -0,0 +1,226 @@
# 🤖 Что делает краулер - пошаговый процесс
## 📋 КРАТКИЙ ОТВЕТ
Краулер делает **ТОЛЬКО парсинг и сохранение в БД**. Никаких эмбеддингов, векторизации или анализа!
---
## 🔄 ПОЛНЫЙ ПРОЦЕСС (шаг за шагом)
### 1⃣ **Получение списка отелей** (`get_unprocessed_hotels`)
```sql
SELECT id, full_name, region_name, website_address
FROM hotel_main
WHERE website_address IS NOT NULL
AND id NOT IN (SELECT hotel_id FROM hotel_website_processed)
ORDER BY id
LIMIT 50 -- пачками по 50
```
**Что делает:**
- Берёт отели с сайтами
- Исключает уже обработанные
- Обрабатывает пачками по 50 штук
---
### 2⃣ **Краулинг сайта** (`crawl_hotel`)
#### 2.1. Запуск браузера Playwright
- Открывает headless браузер
- User-Agent: Mozilla/5.0 (Windows...)
- Параллельно: 5 браузеров (`MAX_CONCURRENT = 5`)
#### 2.2. Загрузка главной страницы
```python
await page.goto(website, wait_until='domcontentloaded', timeout=20000)
```
- Таймаут: 20 секунд
- Ждёт загрузки DOM
#### 2.3. Извлечение контента главной
```python
html = await page.content() # Сырой HTML
cleaned_text = TextCleaner.clean_html(html) # Очищенный текст
```
**`TextCleaner.clean_html()` делает:**
- Удаляет `<script>`, `<style>`, `<meta>`, `<link>`, `<noscript>`
- Извлекает текст через BeautifulSoup
- Убирает лишние пробелы/переносы
- Возвращает чистый текст
#### 2.4. Сбор внутренних ссылок
```python
links = await page.evaluate('''() => {
return Array.from(document.querySelectorAll('a[href]'))
.map(a => a.href)
.filter(href => href && !href.startsWith('mailto:') && !href.startsWith('tel:'))
}''')
```
**Фильтрация:**
- Только внутренние ссылки (тот же домен)
- Исключает `mailto:`, `tel:`
- Убирает дубли
- **Лимит: 19 ссылок** (+ главная = 20 страниц)
#### 2.5. Обход внутренних страниц
```python
for link in internal_links[:19]: # Максимум 19 + главная = 20
page2 = await context.new_page()
await page2.goto(link, timeout=20000)
html2 = await page2.content()
text2 = TextCleaner.clean_html(html2)
# Сохраняем в pages_data
```
**Для каждой страницы:**
- Открывает новую вкладку
- Загружает страницу (20 сек таймаут)
- Извлекает HTML
- Очищает текст
- Добавляет в `pages_data[]`
---
### 3⃣ **Сохранение в БД** (`save_to_db`)
#### 3.1. Метаданные → `hotel_website_meta`
```sql
INSERT INTO hotel_website_meta
(hotel_id, domain, main_url, pages_crawled, crawl_status, crawl_finished_at)
VALUES (...)
ON CONFLICT (hotel_id) DO UPDATE ...
```
**Сохраняет:**
- `hotel_id` - UUID отеля
- `domain` - Домен сайта
- `main_url` - Главный URL
- `pages_crawled` - Количество страниц
- `crawl_status` - 'completed'
- `crawl_finished_at` - Время завершения
#### 3.2. Сырой HTML → `hotel_website_raw`
```sql
INSERT INTO hotel_website_raw
(hotel_id, url, html, status_code, crawled_at)
VALUES (...)
ON CONFLICT (hotel_id, url) DO UPDATE ...
```
**Для КАЖДОЙ страницы сохраняет:**
- `hotel_id` - UUID отеля
- `url` - URL страницы
- `html` - **Полный сырой HTML**
- `status_code` - HTTP код (200, 404, etc)
- `crawled_at` - Время краулинга
#### 3.3. Очищенный текст → `hotel_website_processed`
```sql
INSERT INTO hotel_website_processed
(hotel_id, url, cleaned_text, processed_at)
VALUES (...)
ON CONFLICT (hotel_id, url) DO UPDATE ...
```
**Для КАЖДОЙ страницы сохраняет:**
- `hotel_id` - UUID отеля
- `url` - URL страницы
- `cleaned_text` - **Очищенный текст (без HTML тегов)**
- `processed_at` - Время обработки
---
## ⚡ ПРОИЗВОДИТЕЛЬНОСТЬ
### Настройки:
```python
MAX_PAGES_PER_SITE = 20 # Максимум страниц с одного сайта
PAGE_TIMEOUT = 20000 # 20 секунд на загрузку страницы
MAX_CONCURRENT = 5 # 5 браузеров параллельно
BATCH_SIZE = 50 # Обрабатывать по 50 отелей
```
### Время на 1 отель:
- **Быстрый сайт (1-5 страниц):** ~10-30 секунд
- **Средний сайт (10-15 страниц):** ~1-3 минуты
- **Большой сайт (20 страниц):** ~3-5 минут
- **Недоступный сайт:** ~20 секунд (таймаут)
### Скорость обработки:
- **Текущая:** ~50-100 отелей/день
- **Теоретическая:** ~400-500 отелей/день (если все сайты быстрые)
---
## ❌ ЧТО КРАУЛЕР **НЕ ДЕЛАЕТ**
1.**НЕ создаёт эмбеддинги** (векторы для поиска)
2.**НЕ делает чанки** (разбивку на части)
3.**НЕ анализирует контент** (нет AI/NLP)
4.**НЕ извлекает структурированные данные** (телефоны, email, etc)
5.**НЕ проверяет критерии аудита**
6.**НЕ делает скриншоты**
7.**НЕ проверяет SSL/сертификаты**
---
## 📊 ЧТО В ИТОГЕ В БД
### После краулинга 1 отеля с 15 страницами:
**`hotel_website_meta`:** 1 запись
- Метаданные: домен, количество страниц, статус
**`hotel_website_raw`:** 15 записей
- 15 × полный HTML (может быть 100-500 KB каждый)
- Всего: ~1-7 MB сырых данных
**`hotel_website_processed`:** 15 записей
- 15 × очищенный текст (обычно 1-10 KB каждый)
- Всего: ~15-150 KB текста
---
## 🚀 СЛЕДУЮЩИЕ ЭТАПЫ (отдельно от краулера)
После того как краулер заполнит БД, **ОТДЕЛЬНО** нужно будет:
1. **Создать эмбеддинги** (`process_all_hotels_embeddings.py`)
- Разбить текст на чанки
- Создать векторы через BGE-M3
- Сохранить в `hotel_website_chunks`
2. **Запустить аудит** (`hybrid_audit_chukotka.py`)
- Семантический поиск
- Регулярные выражения
- Natasha NER
- Сохранить в `hotel_audit_results`
3. **Интеграция с n8n**
- AI Agent для анализа
- Автоматизация проверок
---
## 💡 ВЫВОД
**Краулер = простой парсер:**
- Открывает сайты
- Скачивает HTML
- Чистит текст
- Кладёт в БД
**Всё остальное (AI, векторы, аудит) - это отдельные процессы!**
---
**Дата:** 2025-10-14
**Автор:** Фёдор + AI Assistant