feat(tradein/domclick): local Layer-B runner — home-IP + new-headless chromium, paced
Self-contained script (playwright chromium, NO app imports) для сбора DomClick EKB detail с домашнего residential IP (обходит QRATOR — verified live: 2 карточки ok, repair/areas/priceHistory/egrn/owners собраны). Enumerate via bff (Layer A) + card __SSR_STATE__ parse (Layer B) → JSONL (resume/idempotent). KEY: дифференциатор — РЕЖИМ HEADLESS, не только IP. С того же IP старый headless=True → 403, new-headless → 200 + SSR. Раннер дефолтит на new-headless. Пейсинг: рандом 12-30с между карточками, render-jitter 6-10с, human-break каждые 25-40 (60-180с), 1 retry на 403. ~100-150 карточек/час, full ~6400 ≈ 45-65ч. JSONL ингестится в tradein DB отдельным шагом. НЕ deploy — локальный ops-инструмент.
This commit is contained in:
parent
eef23071c5
commit
480ecc90e5
2 changed files with 1239 additions and 0 deletions
|
|
@ -271,3 +271,48 @@ Caveats (also printed): CURRENT listings vs PAST deals (not point-in-time —
|
||||||
needs `listing_source_snapshots` #570); asking-median + IQR core only; ДКП =
|
needs `listing_source_snapshots` #570); asking-median + IQR core only; ДКП =
|
||||||
registered price. Pure metric/ratio helpers are unit-tested in
|
registered price. Pure metric/ratio helpers are unit-tested in
|
||||||
`tests/test_backtest_estimator.py` (no DB).
|
`tests/test_backtest_estimator.py` (no DB).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## `domclick_local_runner.py` — DomClick EKB вторичка с домашнего IP (offline)
|
||||||
|
|
||||||
|
**SELF-CONTAINED** (без `app.*` импортов, stdlib + `playwright.async_api`).
|
||||||
|
Запускается ОПЕРАТОРОМ на его машине с домашнего/резидентного IP — DomClick
|
||||||
|
фронтит QRATOR, который банит datacenter/mobile-proxy, но пропускает домашний.
|
||||||
|
Пишет JSONL (НЕ в БД); заливка в trade-in БД — отдельным ingest-шагом.
|
||||||
|
|
||||||
|
Собирает Layer A (BFF search: `/api/offers/v1` + `/api/offers/count/v1`,
|
||||||
|
room×price-бакетинг под cap offset<2000) + Layer B (detail-карточка,
|
||||||
|
`window.__SSR_STATE__`: renovation, living/kitchen, priceHistory, egrnData
|
||||||
|
owners/collateral, sale_type, views/calls, wall/floor type, AVM). Логика
|
||||||
|
скопирована инлайн из `app/services/scrapers/domclick.py` + `domclick_detail.py`.
|
||||||
|
|
||||||
|
### Режим окна (verified live 2026-06-27 на домашнем IP)
|
||||||
|
|
||||||
|
QRATOR ловит СТАРЫЙ headless (`launch(headless=True)`) → `403 | Домклик` даже
|
||||||
|
с домашнего IP. NEW-headless (`--headless=new`) И headed → `200` + полный
|
||||||
|
`__SSR_STATE__`. Поэтому дефолт = new-headless (окно скрыто, детект проходит);
|
||||||
|
`--headed` = видимое окно (debug). BFF-enumerate проходит в любом режиме.
|
||||||
|
|
||||||
|
### Темп (явное требование — НЕ спалить домашний IP)
|
||||||
|
|
||||||
|
- пауза между карточками `--min-delay` 12с / `--max-delay` 30с (`random.uniform`);
|
||||||
|
- render-wait после goto `--render-min` 6с / `--render-max` 10с;
|
||||||
|
- «человеческий перерыв» каждые 25-40 карточек → 60-180с;
|
||||||
|
- на 403 — один ретрай через 45-90с, потом `status="blocked"` (не долбит).
|
||||||
|
|
||||||
|
Дефолтный темп ≈ 100-150 карточек/час → полный свод ЕКБ (~6400) ≈ 45-65 ч
|
||||||
|
(несколько ночей). Скрипт РЕЗЮМИРУЕМ: при старте читает JSONL и пропускает
|
||||||
|
id с терминальным статусом (ok/blocked/parse_fail).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd tradein-mvp/backend
|
||||||
|
# боевой прогон (дефолтный медленный темп):
|
||||||
|
python scripts/domclick_local_runner.py --out domclick_ekb.jsonl
|
||||||
|
# быстрый smoke (маленькие задержки ТОЛЬКО для теста):
|
||||||
|
python scripts/domclick_local_runner.py --limit 2 --min-delay 3 --max-delay 5 --out dc_test.jsonl
|
||||||
|
# только перечислить (без detail):
|
||||||
|
python scripts/domclick_local_runner.py --enumerate-only --out enum.jsonl
|
||||||
|
```
|
||||||
|
|
||||||
|
Запускать python'ом, где установлен playwright (`python -c "import playwright"`).
|
||||||
|
|
|
||||||
1194
tradein-mvp/backend/scripts/domclick_local_runner.py
Normal file
1194
tradein-mvp/backend/scripts/domclick_local_runner.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue