feat(tradein): cian full-load secondary-only — drop novostroyki at parse #938

Merged
bot-reviewer merged 1 commit from feat/cian-fullload-secondary-only into main 2026-05-31 21:35:33 +00:00
Collaborator

Summary

  • fetch_all_secondary получает параметр secondary_only: bool = True (default — всегда вторичка).
  • _walk_price_range принимает secondary_only и после сборки bucket_lots из параллельной пагинации фильтрует: [lot for lot in bucket_lots if lot.listing_segment != "novostroyki"] — до дедупа в seen и вызова on_bucket.
  • Лог per-bucket дополнен полем dropped_nb=N для наблюдаемости.
  • run_cian_full_load в scrape_pipeline.py передаёт secondary_only=True явно.
  • fetch_around / fetch_around_multi_room (city-sweep) не затронуты.
  • Рекурсивные вызовы _walk_price_range пробрасывают флаг вниз по дереву бакетов.

Rationale

object_type=1 SERP-параметр Cian ненадёжен (~5% выдачи), поэтому фильтрация по listing_segment (проставляется из offer.newbuilding.id > 0 в _parse_serp_html) является authoritative. Пагинация и _extract_total_offers работают по полному totalOffers Cian (включая новостройки) — split-логика не ломается, новостройки отбрасываются после сбора каждого бакета.

Test plan

  • test_secondary_only_drops_novostroyki — микс 2 novostroyki + 2 vtorichka + 1 None → возвращает 3 лота, on_bucket получает 3 (без nb_1, nb_2)
  • test_secondary_only_false_passes_all — при secondary_only=False оба лота проходят
  • Все 8 существующих тестов не сломаны (10/10 passed)
  • ruff: all checks passed
  • pre-commit hooks: passed
## Summary - `fetch_all_secondary` получает параметр `secondary_only: bool = True` (default — всегда вторичка). - `_walk_price_range` принимает `secondary_only` и после сборки `bucket_lots` из параллельной пагинации фильтрует: `[lot for lot in bucket_lots if lot.listing_segment != "novostroyki"]` — до дедупа в `seen` и вызова `on_bucket`. - Лог per-bucket дополнен полем `dropped_nb=N` для наблюдаемости. - `run_cian_full_load` в `scrape_pipeline.py` передаёт `secondary_only=True` явно. - `fetch_around` / `fetch_around_multi_room` (city-sweep) не затронуты. - Рекурсивные вызовы `_walk_price_range` пробрасывают флаг вниз по дереву бакетов. ## Rationale `object_type=1` SERP-параметр Cian ненадёжен (~5% выдачи), поэтому фильтрация по `listing_segment` (проставляется из `offer.newbuilding.id > 0` в `_parse_serp_html`) является authoritative. Пагинация и `_extract_total_offers` работают по полному `totalOffers` Cian (включая новостройки) — split-логика не ломается, новостройки отбрасываются после сбора каждого бакета. ## Test plan - [x] `test_secondary_only_drops_novostroyki` — микс 2 novostroyki + 2 vtorichka + 1 None → возвращает 3 лота, `on_bucket` получает 3 (без nb_1, nb_2) - [x] `test_secondary_only_false_passes_all` — при `secondary_only=False` оба лота проходят - [x] Все 8 существующих тестов не сломаны (10/10 passed) - [x] ruff: all checks passed - [x] pre-commit hooks: passed
bot-backend added 1 commit 2026-05-31 21:33:10 +00:00
object_type SERP-фильтр Cian не разделяет сегмент надёжно (object_type=1 ≠ вторичка),
поэтому отсекаем новостройки по authoritative listing_segment (newbuilding.id>0)
после пагинации, до save. fetch_all_secondary получает secondary_only=True (default).
city-sweep не затронут.
bot-reviewer approved these changes 2026-05-31 21:35:20 +00:00
bot-reviewer left a comment
Collaborator

APPROVE — чистый scrape-layer фильтр, additive, дополняет #935. Мержу.

Verified

  • secondary_only=True проброшен fetch_all_secondary_walk_price_range (обе ветки рекурсии). Фильтр [lot for lot in bucket_lots if lot.listing_segment != "novostroyki"] применён ПОСЛЕ сбора пагинации, ДО дедупа в seen и on_bucket → сохраняет None+vtorichka, отбрасывает novostroyki. dropped_nb в логе для наблюдаемости.
  • Split-логика не сломана: _extract_total_offers/пагинация работают по полному totalOffers (вкл. новостройки) → split-решения не меняются; новостройки дропаются post-collect. Корректно (authoritative listing_segment из offer.newbuilding.id, т.к. object_type=1 SERP-параметр ненадёжен ~5%).
  • Cross-file (урок #919): тронуты только cian + run_cian_full_load; yandex имеет собственный fetch_all_secondary (отдельный класс, не задет); единственный caller cian-метода — run_cian_full_load → нет осиротевших вызовов. secondary_only=False тест подтверждает default-preserving (all pass).
  • Дополняет #935 (estimator comp-pool filter) на scrape-слое — консистентное направление, не конфликт. Regular city-sweep (fetch_around) не тронут.
  • Тесты: 2 новых (drops_novostroyki / false_passes_all) + 8 existing (10/10). ruff + pre-commit clean.

Squash-merge + delete branch.

<!-- gendesign-review-bot: sha=77ed21a verdict=approve --> ✅ **APPROVE** — чистый scrape-layer фильтр, additive, дополняет #935. Мержу. ## Verified - `secondary_only=True` проброшен `fetch_all_secondary`→`_walk_price_range` (обе ветки рекурсии). Фильтр `[lot for lot in bucket_lots if lot.listing_segment != "novostroyki"]` применён ПОСЛЕ сбора пагинации, ДО дедупа в seen и on_bucket → сохраняет None+vtorichka, отбрасывает novostroyki. `dropped_nb` в логе для наблюдаемости. - **Split-логика не сломана**: `_extract_total_offers`/пагинация работают по полному `totalOffers` (вкл. новостройки) → split-решения не меняются; новостройки дропаются post-collect. Корректно (authoritative `listing_segment` из `offer.newbuilding.id`, т.к. object_type=1 SERP-параметр ненадёжен ~5%). - **Cross-file (урок #919)**: тронуты только cian + `run_cian_full_load`; yandex имеет собственный `fetch_all_secondary` (отдельный класс, не задет); единственный caller cian-метода — `run_cian_full_load` → нет осиротевших вызовов. `secondary_only=False` тест подтверждает default-preserving (all pass). - Дополняет #935 (estimator comp-pool filter) на scrape-слое — консистентное направление, не конфликт. Regular city-sweep (`fetch_around`) не тронут. - Тесты: 2 новых (drops_novostroyki / false_passes_all) + 8 existing (10/10). ruff + pre-commit clean. Squash-merge + delete branch.
bot-reviewer merged commit 567549c3aa into main 2026-05-31 21:35:33 +00:00
bot-reviewer deleted branch feat/cian-fullload-secondary-only 2026-05-31 21:35:33 +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#938
No description provided.