feat(tradein): exhaustive Cian EKB secondary load — room×price partitioning #926

Merged
bot-reviewer merged 2 commits from feat/cian-exhaustive-price-room into main 2026-05-31 19:54:20 +00:00
Collaborator

Summary

  • Обходит Cian SERP-cap (~54 стр ≈ 1500 результатов/запрос): адаптивное бинарное партиционирование по ЦЕНЕ внутри каждой КОМНАТНОСТИ
  • _walk_price_range — рекурсия с guard MIN_BRACKET=50_000 (защита от бесконечного деления) и MAX_PRICE=200_000_000
  • Rooms buckets: 1к/2к/3к/4к/5к/6+ (студии — TODO-коммент, код Cian не верифицирован)
  • Дедуп по source_id через dict seen; IP-ротация через avito_proxy_rotate_url на captcha/timeout
  • Region-wide один проход — anchor'ы для Cian избыточны
  • Endpoint POST /admin/scrape/cian-full-load + cancel /{run_id}/cancel
  • 3 unit-теста: splits_on_cap, paginates_when_under_cap, min_bracket_guard

Test plan

  • pytest tests/scrapers/test_cian_exhaustive.py -v — 3 passed (проверено локально)
  • ruff на 3 основных файлах — All checks passed
  • POST /admin/scrape/cian-full-load на проде → run_id, heartbeat counters растут
  • После завершения: listings COUNT source='cian' значительно выше pre-run baseline

Refs #922

## Summary - Обходит Cian SERP-cap (~54 стр ≈ 1500 результатов/запрос): адаптивное бинарное партиционирование по ЦЕНЕ внутри каждой КОМНАТНОСТИ - `_walk_price_range` — рекурсия с guard `MIN_BRACKET=50_000` (защита от бесконечного деления) и `MAX_PRICE=200_000_000` - Rooms buckets: 1к/2к/3к/4к/5к/6+ (студии — TODO-коммент, код Cian не верифицирован) - Дедуп по `source_id` через `dict seen`; IP-ротация через `avito_proxy_rotate_url` на captcha/timeout - Region-wide один проход — anchor'ы для Cian избыточны - Endpoint `POST /admin/scrape/cian-full-load` + cancel `/{run_id}/cancel` - 3 unit-теста: splits_on_cap, paginates_when_under_cap, min_bracket_guard ## Test plan - [ ] `pytest tests/scrapers/test_cian_exhaustive.py -v` — 3 passed (проверено локально) - [ ] ruff на 3 основных файлах — All checks passed - [ ] POST /admin/scrape/cian-full-load на проде → run_id, heartbeat counters растут - [ ] После завершения: listings COUNT source='cian' значительно выше pre-run baseline Refs #922
bot-backend added 1 commit 2026-05-31 19:43:42 +00:00
Обходит Cian SERP-cap (~54 стр): адаптивно бьёт цену на бакеты внутри комнатности
(totalOffers-driven split, minprice/maxprice), пагинирует каждый полностью, дедуп
по source_id. Region-wide один проход (anchor'ы для Cian избыточны) + IP-rotation
(cian_proxy_rotate_url). Endpoint POST /admin/scrape/cian-full-load.
lekss361 added 1 commit 2026-05-31 19:51:58 +00:00
Review #926 fixups:
- _rotate_ip: cian_proxy_rotate_url or avito_proxy_rotate_url (was avito-only →
  rotated wrong proxy IP on Cian ban, ignored CIAN_PROXY_ROTATE_URL).
- pagination log: dir() → locals() for local-var existence check.
bot-reviewer approved these changes 2026-05-31 19:54:09 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — рекурсия терминируется, cross-file сигнатуры проверены, additive. Мержу.

Verified

  • Рекурсия _walk_price_range терминируется: каждый split делит bracket пополам; too_narrow = bracket < _MIN_BRACKET(50k) форсит need_split=False → пагинация. Глубина ~log2(200M/50k)≈12. hi=None нормализуется один раз в _MAX_PRICE. Тест min_bracket_guard (total=5000>cap, узкий bracket) подтверждает отсутствие бесконечной рекурсии (≤10 calls). Дедуп по source_id гасит overlap на границах mid/mid+1.
  • Cross-file (урок #919): cian_detail.save_detail_enrichment(db, listing_id, enrichment) — сигнатура совпадает с вызовом ✓; fetch_detail есть; все scrape_runs helpers (create_run/update_heartbeat/is_cancelled/mark_done/mark_failed/mark_cancelled) на месте.
  • Endpoint POST /scrape/cian-full-load за admin-router (Caddy gate, как siblings), Pydantic Field bounds (ge/le). IP-rotation через cian_proxy_rotate_url (из #923) → avito fallback.
  • Additive: новый endpoint + fetch_all_secondary, существующие sweeps не тронуты. enrich_detail off by default (detail-путь не активен пока явно не включишь).

🟡 Advisory (не блокер)

  • Cancel во время fetch_all_secondary детектится в on_progress, но НЕ прерывает 6-room loop — полностью эффективен только на detail-стадии / после fetch. Для admin-endpoint с конечным циклом приемлемо; если нужен прерываемый fetch — прокинуть cancel-флаг в fetch_all_secondary и break room-loop.
  • Один лишний probe ([0,None][0,_MAX_PRICE]) на комнатность — тривиально.

Squash-merge + delete branch.

<!-- gendesign-review-bot: sha=5875641 verdict=approve --> ✅ **APPROVE** — рекурсия терминируется, cross-file сигнатуры проверены, additive. Мержу. ## Verified - **Рекурсия `_walk_price_range` терминируется**: каждый split делит bracket пополам; `too_narrow = bracket < _MIN_BRACKET(50k)` форсит `need_split=False` → пагинация. Глубина ~log2(200M/50k)≈12. `hi=None` нормализуется один раз в `_MAX_PRICE`. Тест `min_bracket_guard` (total=5000>cap, узкий bracket) подтверждает отсутствие бесконечной рекурсии (≤10 calls). Дедуп по `source_id` гасит overlap на границах mid/mid+1. - **Cross-file (урок #919)**: `cian_detail.save_detail_enrichment(db, listing_id, enrichment)` — сигнатура совпадает с вызовом ✓; `fetch_detail` есть; все `scrape_runs` helpers (create_run/update_heartbeat/is_cancelled/mark_done/mark_failed/mark_cancelled) на месте. - Endpoint `POST /scrape/cian-full-load` за admin-router (Caddy gate, как siblings), Pydantic `Field` bounds (ge/le). IP-rotation через `cian_proxy_rotate_url` (из #923) → avito fallback. - **Additive**: новый endpoint + `fetch_all_secondary`, существующие sweeps не тронуты. `enrich_detail` off by default (detail-путь не активен пока явно не включишь). ## 🟡 Advisory (не блокер) - Cancel во время `fetch_all_secondary` детектится в `on_progress`, но НЕ прерывает 6-room loop — полностью эффективен только на detail-стадии / после fetch. Для admin-endpoint с конечным циклом приемлемо; если нужен прерываемый fetch — прокинуть cancel-флаг в `fetch_all_secondary` и `break` room-loop. - Один лишний probe (`[0,None]`→`[0,_MAX_PRICE]`) на комнатность — тривиально. Squash-merge + delete branch.
bot-reviewer merged commit 0883f6d0f1 into main 2026-05-31 19:54:20 +00:00
bot-reviewer deleted branch feat/cian-exhaustive-price-room 2026-05-31 19:54:20 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#926
No description provided.