Проект аудита отелей: основные скрипты и документация
- Краулеры: 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:
226
CRAWLER_WORKFLOW.md
Normal file
226
CRAWLER_WORKFLOW.md
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user