gendesign/tradein-mvp/backend/app/services/scrapers
lekss361 375f785100 feat(tradein): avito_imv.py — Avito IMV evaluation API client (2 requests)
Stage 2d of AvitoScraper_v2.

- evaluate_via_imv(address, rooms, area, floor, ...) — async 2-request flow:
  1) GET /web/1/coords/by_address → geoHash + geo IDs
  2) POST /web/1/realty-imv/get-data → price + placementHistory + suggestions
- IMVEvaluation dataclass: cache_key (sha256), geo, price (recommended/lower/higher/market_count),
  placement_history with removed_date, suggestions
- compute_imv_cache_key(...) — deterministic hash for 24h cache lookup
- save_imv_evaluation(db, e) — UPSERT в avito_imv_evaluations ON CONFLICT(cache_key)
- save_imv_placement_history(db, items) — INSERT с source='avito_imv' и removed_date NOT NULL
  (отличие от Stage 2c widget save flow)
- IMVAddressNotFoundError / IMVCityMismatchError exceptions
- pytest offline smoke (cache_key determinism + unix→date + dataclass construct)

Note: suggestions saving в listings skipped — Stage 3 решит when integrating.
Note: house_placement_history использует scraped_at (не fetched_at) — по DDL 017.
      avito_imv_evaluations сохраняет geo_hash в отдельную колонку — по DDL 018.
2026-05-23 15:10:32 +03:00
..
__init__.py feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00
avito.py refactor(tradein): avito search — remove jitter (C-5) + mobile API dead code + parse houseLinks (#441) 2026-05-23 11:55:18 +00:00
avito_imv.py feat(tradein): avito_imv.py — Avito IMV evaluation API client (2 requests) 2026-05-23 15:10:32 +03:00
base.py refactor(tradein): avito search — remove jitter (C-5) + mobile API dead code + parse houseLinks (#441) 2026-05-23 11:55:18 +00:00
cian.py feat(tradein): пагинация Циан/N1 3→8 страниц — плотность данных 2026-05-21 14:34:29 +03:00
n1.py feat(tradein): пагинация Циан/N1 3→8 страниц — плотность данных 2026-05-21 14:34:29 +03:00
yandex_realty.py feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in) 2026-05-21 00:25:39 +03:00