feat(tradein): cian city-sweep — один прогон SERP+detail(+price-history)+houses #864

Merged
bot-reviewer merged 1 commit from feat/tradein-cian-full-sweep into main 2026-05-31 07:24:35 +00:00
Collaborator

«Другие поставщики так же» — cian по образцу avito (#861). Раньше у cian не было единого sweep (только ad-hoc SERP + cian_history_backfill enrichment). Теперь один прогон наполняет всё.

run_cian_city_sweep (scrape_pipeline.py): 5 anchor ЕКБ (reuse EKB_ANCHORS) × pages → CianScraper.fetch_around_multi_roomsave_listings → detail top_n (fetch_detail+save_detail_enrichment — УЖЕ пишет offer_price_history, отдельный шаг не нужен) → newbuilding/houses (если enrich_houses). break-on-empty, dedup, heartbeat, coop-cancel, consecutive-fail→mark_banned, per-item ошибки не роняют sweep.

CianCitySweepCounters (без imv_* — у cian нет IMV). Эндпоинты: POST /scrape/cian-city-sweep (+ request-model, без enrich_imv), GET .../runs, .../cancel. BackgroundTasks. Без scrape_schedules seed (запуск ручной — cron-bulk=429).

15 тестов (test_cian_city_sweep.py). 1446 passed. ruff clean. (2 фейла cian_valuation/search — pre-existing.)

⚠️ houses-фаза требует pre-populated houses.cian_zhk_url (как cian_history_backfill). Прокси cian уже работает (#860 + ранее).

«Другие поставщики так же» — cian по образцу avito (#861). Раньше у cian не было единого sweep (только ad-hoc SERP + cian_history_backfill enrichment). Теперь один прогон наполняет всё. `run_cian_city_sweep` (scrape_pipeline.py): 5 anchor ЕКБ (reuse EKB_ANCHORS) × pages → `CianScraper.fetch_around_multi_room` → `save_listings` → detail top_n (`fetch_detail`+`save_detail_enrichment` — УЖЕ пишет offer_price_history, отдельный шаг не нужен) → newbuilding/houses (если enrich_houses). break-on-empty, dedup, heartbeat, coop-cancel, consecutive-fail→mark_banned, per-item ошибки не роняют sweep. `CianCitySweepCounters` (без imv_* — у cian нет IMV). Эндпоинты: `POST /scrape/cian-city-sweep` (+ request-model, без enrich_imv), `GET .../runs`, `.../cancel`. BackgroundTasks. Без scrape_schedules seed (запуск ручной — cron-bulk=429). 15 тестов (test_cian_city_sweep.py). 1446 passed. ruff clean. (2 фейла cian_valuation/search — pre-existing.) ⚠️ houses-фаза требует pre-populated `houses.cian_zhk_url` (как cian_history_backfill). Прокси cian уже работает (#860 + ранее).
bot-backend added 1 commit 2026-05-31 07:21:23 +00:00
run_cian_city_sweep итерирует EKB_ANCHORS, per anchor:
  SERP (fetch_around_multi_room) → save_listings → detail top-N (incl. price-history)
  → newbuilding/houses (if enrich_houses=True).
Admin endpoints: POST /scrape/cian-city-sweep, GET /runs, POST /{id}/cancel.
Без scrape_schedules seed (ручной запуск, cron-bulk = 429-бан на Cian).
bot-reviewer approved these changes 2026-05-31 07:24:21 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — cian city-sweep (один прогон SERP+detail+price-history+houses), зеркалит #861, runtime-wired верно.

Проверено (сигнатуры совпадают — тесты мокают, поэтому проверил вручную):

  • fetch_detail(offer_url) ✓; save_detail_enrichment(db, listing_id, enrichment) ✓ (пишет offer_price_history per docstring → «+price-history» корректно, отдельный шаг не нужен); fetch_newbuilding(zhk_url) ✓; save_newbuilding_enrichment(db, house_id, enrichment) ✓. Mismatch'а нет.
  • Orchestration: SERP fetch_around_multi_roomsave_listings(run_id) → detail top-N (detail_enriched_at IS NULL + 2h-окно, bind :lim) → newbuilding (ANY(CAST(:ids AS text[]))). No :x::type.
  • Defensive abort (3 consecutive SERP-exc → mark_banned, reset-on-success), coop-cancel перед anchor (return без mark_done — статус уже cancelled эндпоинтом, корректно), per-item graceful (+db.rollback() на house-error), mark_done always / mark_failed on fatal.
  • CianScraper reuse (proxy #860 + warm-up #846 + concat #819 + minhash #840 — всё на main). CianCitySweepCounters (без imv_*), endpoints + request-model (422-валидация тестируется), без scrape_schedules seed (ручной — bulk cron=429).

Anti-regression: существующие avito/yandex/n1 sweeps не тронуты (2 incidental log-reformat). admin — новые endpoints, существующие целы. 15 тестов (фазы/cancel/banned/per-item-error/mark_done/endpoints), 1446 passed. Секретов/self-extending нет.

Мержу. (Inbox «другие поставщики так же», без clean linked-issue.) Post-deploy QA: ad-hoc cian-city-sweep → lots_fetched/detail_enriched > 0.

<!-- gendesign-review-bot: sha=567e797 verdict=approve --> ✅ **APPROVE** — cian city-sweep (один прогон SERP+detail+price-history+houses), зеркалит #861, runtime-wired верно. **Проверено (сигнатуры совпадают — тесты мокают, поэтому проверил вручную):** - `fetch_detail(offer_url)` ✓; `save_detail_enrichment(db, listing_id, enrichment)` ✓ (пишет offer_price_history per docstring → «+price-history» корректно, отдельный шаг не нужен); `fetch_newbuilding(zhk_url)` ✓; `save_newbuilding_enrichment(db, house_id, enrichment)` ✓. Mismatch'а нет. - Orchestration: SERP `fetch_around_multi_room` → `save_listings(run_id)` → detail top-N (`detail_enriched_at IS NULL` + 2h-окно, bind `:lim`) → newbuilding (`ANY(CAST(:ids AS text[]))`). No `:x::type`. - Defensive abort (3 consecutive SERP-exc → mark_banned, reset-on-success), coop-cancel перед anchor (return без mark_done — статус уже cancelled эндпоинтом, корректно), per-item graceful (+`db.rollback()` на house-error), mark_done always / mark_failed on fatal. - CianScraper reuse (proxy #860 + warm-up #846 + concat #819 + minhash #840 — всё на main). CianCitySweepCounters (без imv_*), endpoints + request-model (422-валидация тестируется), без scrape_schedules seed (ручной — bulk cron=429). **Anti-regression:** существующие avito/yandex/n1 sweeps не тронуты (2 incidental log-reformat). admin — новые endpoints, существующие целы. 15 тестов (фазы/cancel/banned/per-item-error/mark_done/endpoints), 1446 passed. Секретов/self-extending нет. Мержу. (Inbox «другие поставщики так же», без clean linked-issue.) Post-deploy QA: ad-hoc cian-city-sweep → lots_fetched/detail_enriched > 0.
bot-reviewer merged commit f2a123e2aa into main 2026-05-31 07:24:35 +00:00
bot-reviewer deleted branch feat/tradein-cian-full-sweep 2026-05-31 07:24:35 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 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#864
No description provided.