docs(autopodbor): спека «свой канал 2ГИС+Яндекс на виртуалке» (замена xf4)
Дизайн утверждён владельцем в брейншторме: рендер своим браузером с маскировкой + ротация RU-прокси вместо платного xf4, чистый разбор 2ГИС через перехват встроенного JSON (убирает трэш), постоянный браузер, всё на выделенной виртуалке (не на боевом портале), за флагом self_render с откатом на xf4. Планка приёмки — фирма-в-фирму с живым 2ГИС. UI/кнопки/функции не трогаются. Замер: 25 мин xf4 → 9 мин свой рендер. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
# Свой канал 2ГИС+Яндекс на выделенной виртуалке — дизайн
|
||||
|
||||
**Дата:** 2026-07-05 · **Ветка:** `worktree-avtopodbor` (НЕ прод) · **Статус:** дизайн утверждён владельцем, готов к плану.
|
||||
|
||||
## 1. Цель и мотивация
|
||||
|
||||
Сбор конкурентов (шаг 1) и изучение (шаг 2) сейчас тянут данные 2ГИС через платный внешний сервис **xf4.ru**. Замер 05.07.2026 на реальных данных владельца (Красноярск, займы под залог авто):
|
||||
|
||||
| | xf4 (сейчас) | наш рендер (тест) |
|
||||
|---|---|---|
|
||||
| Полный шаг 1 | **25 мин** | **9 мин** |
|
||||
| 2ГИС-листинг | 264с / 127 фирм | 53с / 51 фирма |
|
||||
| Вскрытие карточек 2ГИС | 967с (64% всего времени) | часть 340с |
|
||||
| Деньги за прогон | ~50–75 ₽ (при потоке — тысячи ₽/день) | ~0 (только ИИ) |
|
||||
|
||||
**Тормоз — сам сервис xf4:** лимит ~3–4 запроса/ключ (429 выше), рендер 20–60с/страница. Ключами не уравнять: 2ГИС-листинг (264с, ключами не ускоряется) один больше всей Яндекс-части (194с).
|
||||
|
||||
**Проверено вживую:**
|
||||
- наш локальный Playwright с маскировкой (скрытый `webdriver` + свежий Chrome UA + флаг `AutomationControlled` + проскок заглушки «обновите браузер») **пробивает 2ГИС** — 600–680 КБ реальных данных, живые телефоны;
|
||||
- залп 28 карточек по 5 параллельно с одного IP — **100% данные, IP выдержал** (баг был в тесте, не в IP);
|
||||
- голый Playwright 2ГИС **блокирует** (капча/заглушка) — маскировка обязательна.
|
||||
|
||||
**Цель:** заменить xf4 на свой рендер на выделенной виртуалке — **быстро и качественно**, с ротацией прокси, за флагом, с откатом на xf4.
|
||||
|
||||
## 2. Планка приёмки (definition of done для включения флага)
|
||||
|
||||
На тест-клиенте новый канал обязан:
|
||||
1. Находить фирм **не меньше**, чем xf4 (эталон ~127 для тестового запроса), а не 51.
|
||||
2. **Ноль мусора** — только релевантные фирмы (никаких «Бургер Кинг», парковок, табачных из соседних зданий).
|
||||
3. Телефоны/сайты/названия — **корректные, собственные данные 2ГИС**.
|
||||
4. Ручная сверка **фирма-в-фирму с живым 2ГИС** по нескольким фирмам — совпадает.
|
||||
|
||||
Флаг включаем **только после** этой сверки владельцем.
|
||||
|
||||
## 3. Границы — что НЕ меняется (жёстко)
|
||||
|
||||
**UI, кнопки, функции, экраны автоподбора НЕ трогаются.** Правится только слой добычи сырых данных.
|
||||
|
||||
Остаются как есть: экраны «Конкурентное поле» / «Предложения» / «Источники в работе»; кнопки «Собрать конкурентов», «Дайте источники», «В источники →», «Изменить», «Удалить», «Добавить вручную», окно слияния «останется», «История слияний», «Вернуть карточку», перенос выбранных, поиск дублей; логика списания денег, дедуп, склейка, похожесть-%, метки ✓/🎭, шаги 1/2. Клиент работает через тот же портал Лидерра, разницы в интерфейсе не видит.
|
||||
|
||||
## 4. Архитектура (вариант A — весь автоподбор на виртуалке)
|
||||
|
||||
```
|
||||
Клиент → Портал Лидерра → задача в очередь Redis (autopodbor-find / autopodbor-study)
|
||||
↓
|
||||
ВИРТУАЛКА = второй рабочий автоподбора
|
||||
├─ queue:work --queue=autopodbor-find / autopodbor-study
|
||||
├─ Рисовалка: постоянный браузер + маскировка + прокси-ротация
|
||||
├─ 2ГИС: перехват встроенного JSON → чистые фирмы
|
||||
├─ Яндекс: та же маскировка + прокси (разбор прежний)
|
||||
└─ пишет результат в ту же базу (Managed PG)
|
||||
↓
|
||||
Клиент видит результат в портале
|
||||
```
|
||||
|
||||
- Виртуалка запускает воркеры автоподбора и делает всю browser-работу; браузерный шторм физически не на боевом портале.
|
||||
- Разнесённые очереди `autopodbor-find` / `autopodbor-study` (уже в коде) позволяют при желании развести шаги по разным воркерам/виртуалкам.
|
||||
- Всё за флагом `self_render`; xf4-путь остаётся целым запасным.
|
||||
|
||||
## 5. Компоненты
|
||||
|
||||
### 5.1. Рисовалка (render engine)
|
||||
- **Один браузер держим открытым**; на каждую страницу — отдельный лёгкий **контекст** (свои куки + свой прокси), отрисовали → закрыли контекст, браузер живёт. Убирает трату ~1–2с на запуск браузера × сотни карточек.
|
||||
- **Маскировка** (проверена): скрытый `navigator.webdriver`, свежий Chrome UA, `--disable-blink-features=AutomationControlled`, `ru-RU`, реалистичный viewport; проскок заглушки «обновите браузер» (клик «перейти в 2ГИС»).
|
||||
- **Прокси на каждый контекст** — из пула, round-robin.
|
||||
- **Параллельность** — настройка под память виртуалки (~300–400 МБ на контекст). Слабая машина — 4, мощная — 16–30.
|
||||
- **Ошибки:** тайм-аут/редкий блок → **повтор через другой прокси** (1–2 раза) → не вышло → пропуск карточки (как сейчас, поток не падает). Падение браузера → перезапуск.
|
||||
|
||||
### 5.2. 2ГИС через JSON (чистые данные)
|
||||
- При загрузке страницы 2ГИС сам подтягивает **встроенные пакеты данных (JSON)** — его собственный структурированный список фирм (название, адрес, телефоны, сайт). **Перехватываем эти ответы** (Playwright видит сетевые ответы страницы) и читаем готовые данные, а не рисованный HTML.
|
||||
- Новый разборщик читает JSON → чистый список фирм. Старый HTML-разборщик 2ГИС **остаётся для xf4-пути**, не трогается.
|
||||
- **Первый шаг стройки:** поймать реальный JSON живого 2ГИС (листинг + карточка), зафиксировать формат как тест-фикстуру, на нём написать разборщик по TDD.
|
||||
|
||||
### 5.3. Яндекс
|
||||
- Уже рисуется своим браузером и работает без мусора → **разбор не переделываем**. Добавляем только **прокси-ротацию** и перенос на виртуалку.
|
||||
|
||||
### 5.4. Прокси-слой
|
||||
- Пул адресов в настройке (`.env`/config), round-robin per-context, одинаково для 2ГИС и Яндекса. **Провайдер-агностично** — любой сервис резидентных/мобильных RU-прокси (кандидаты: ProxyGRAM, Proxy.Market, Proxys.io, MangoProxy). Ключи только в `.env`, в гит не идут.
|
||||
|
||||
### 5.5. Флаг и откат
|
||||
- Флаг `autopodbor.self_render` (env, по умолчанию ВЫКЛ). ВКЛ → 2ГИС+Яндекс через свой рендер+прокси. ВЫКЛ → текущий путь через xf4. Мгновенный откат тумблером.
|
||||
|
||||
### 5.6. Выкат на виртуалку
|
||||
- Виртуалка = второй app-узел: копия приложения, доступ к Redis и Managed PG (внутренняя сеть облака), node+Playwright+Chromium, пул прокси в `.env`, воркеры `autopodbor-find`/`autopodbor-study`. Параллельность контекстов — по памяти виртуалки. Выкат через `prod-deploy-validator`.
|
||||
|
||||
## 6. Обработка ошибок
|
||||
|
||||
| Ситуация | Поведение |
|
||||
|---|---|
|
||||
| Тайм-аут/пустая страница | повтор через другой прокси ×1–2 → пропуск карточки |
|
||||
| Заглушка «обновите браузер» | автоклик «перейти в 2ГИС» |
|
||||
| Блок по IP | смена прокси (ротация) |
|
||||
| Падение браузера | перезапуск постоянного браузера |
|
||||
| Прокси недоступен | следующий из пула; пул пуст → лог + деградация (как xfetch без ключа) |
|
||||
| 2ГИС сменил формат JSON | разбор пуст → лог; фикстуры-тесты ловят регресс |
|
||||
|
||||
## 7. Тестирование (TDD)
|
||||
|
||||
- **Разборщик 2ГИС** — юнит-тесты на **реальных сохранённых JSON-фикстурах** (листинг + карточка): фирма-в-фирму, телефоны, отсев мусора. По TDD.
|
||||
- **Рисовалка** — интеграция: отдаёт данные с тест-прокси; маскировка/проскок работают.
|
||||
- **Прокси-ротация** — юнит: раскидывает контексты по пулу по кругу.
|
||||
- **Приёмка** — полный прогон на деве + ручная сверка «фирма-в-фирму» с живым 2ГИС (владелец).
|
||||
- **Регресс:** все **434 текущих теста автоподбора зелёные** (xf4-путь не тронут).
|
||||
|
||||
## 8. Фазы стройки (каждая проверяема)
|
||||
|
||||
1. **Чистый разбор 2ГИС.** Поймать реальный JSON → разборщик по TDD. *Без виртуалки/прокси.*
|
||||
2. **Рисовалка.** Постоянный браузер + маскировка + поддержка прокси. *Локально.*
|
||||
3. **Сборка за флагом + приёмка.** Полный прогон на деве, сверка «фирма-в-фирму». *Ещё на деве, флаг ВЫКЛ по умолчанию.*
|
||||
4. **Выкат на виртуалку.** Провижн виртуалки + пул прокси + `prod-deploy-validator` GO/NO-GO.
|
||||
|
||||
## 9. Требования к железу
|
||||
|
||||
- Ограничитель — **память** (~300–400 МБ на параллельный контекст) + процессор (~0,5–1 ядро/контекст).
|
||||
- **Формула:** параллельных контекстов ≈ свободная память ÷ 350 МБ (и не больше ~1,5× ядер).
|
||||
|
||||
| Свободно памяти | Параллельно | Один прогон шаг 1 |
|
||||
|---|---|---|
|
||||
| 2,5 ГБ (dev сейчас) | 4 | ~9 мин |
|
||||
| 6 ГБ | ~16 | ~3–4 мин |
|
||||
| 12 ГБ | ~30 | ~2 мин |
|
||||
|
||||
- **Рекомендация для боевого:** выделенная виртуалка **8–16 ГБ свободной памяти + 4–8 ядер** под автоподбор → 16–30 контекстов → прогон 2–4 мин или 2–3 клиента разом.
|
||||
- Поток (владелец): 5–6 клиентов/день, шаг 1 редкий (~1,2 прогона/клиент), шаг 2 частый но лёгкий (~70 конкурентов на всех), не одновременно — под это 8 ГБ виртуалки с запасом.
|
||||
|
||||
## 10. Открытые вопросы (решаются на этапе внедрения, не блокируют стройку кода)
|
||||
|
||||
- Конкретный провайдер прокси и бюджет (закупка; система агностична).
|
||||
- Точный размер виртуалки (по факту нагрузки; старт с 8 ГБ).
|
||||
- Провижн виртуалки (образ/деплой) — ops-задача фазы 4.
|
||||
|
||||
## 11. Артефакты, уже готовые в ветке
|
||||
|
||||
- Рабочий рецепт маскировки — `app/scripts/render-2gis-stealth.cjs` (образец, не подключён).
|
||||
- Мульти-ключ xfetch (коммит `bdecd08d`) и раздельные очереди find/study (`43e29823`) — совместимы, остаются как запасной путь и основа для разнесения по виртуалкам.
|
||||
Reference in New Issue
Block a user