feat(tradein-imv): route IMV backfill через BrowserFetcher.fetch_json за dormant-флагом (#915 Stage 3) #1916

Merged
bot-backend merged 2 commits from feat/915-stage3-imv-browser into main 2026-06-26 09:54:29 +00:00
Collaborator

Summary

Transport-swap для avito IMV backfill: 4 IMV-запроса (warm-up → coords → position → get-data) ходят через камуфокс in-page fetch (/fetch-json sidecar, #915 Stage 2) вместо curl_cffi. Same-origin avito.ru + sidecar-прокси + warmed-cookies + реальный fingerprint обходят datacenter-403 (#562/#853) без отдельного IMV-прокси. Это чистый transport-swap — geoFieldsHash отдаёт сам avito, реверса нет.

За dormant-флагом avito_imv_use_browser_fetcher (default False, ENV AVITO_IMV_USE_BROWSER_FETCHER) → деплой не меняет prod IMV-поведение. Backfill-only: estimator и sweep-путь (process_houses_imv_batch) не тронуты.

🎯 Prod-валидация гипотезы (на задеплоенном Stage 2, до мержа этого PR)

POST tradein-browser:3000/fetch-json на https://www.avito.ru/web/1/coords/by_address?address=Екатеринбург, Малышева 84 (origin=/evaluation/realty, source=avito) →
inner HTTP 200 + реальный JSON (normalizedAddress, point{lat 56.835471, lon 60.617579}). НЕ 403. Подтверждает: avito IMV XHR из тёплого браузера обходит datacenter-403 → этот PR реально разблокирует #562.

Что внутри

  • _BrowserResponse + _BrowserSessionAdapter в avito_imv.py — мимикрия под curl_cffi (.get/.post/.close, .status_code/.text/.json/.raise_for_status); IMV-флоу не меняется. evaluate_via_imv получил browser_fetcher kwarg.
  • backfill_house_imv при флаге открывает один BrowserFetcher(source="avito") на батч, прокидывает в _process_one_houseevaluate_via_imv. Флаг OFF → browser_fetcher=None → curl-путь как раньше (byte-equivalent).
  • Deep-review #1915 follow-ups: _post_fetch_json защищён от ответа без status/body keys; добавлен тест crash-retry ветки _do_fetch_json.

Test plan

  • adapter/response units; evaluate_via_imv(browser_fetcher=...) happy-path + 403→IMVAuthError; backfill flag on/off проводка.
  • backend 107 passed (scoped imv/browser/backfill/fetch_json), sidecar 9 passed. ruff clean.
  • flag-OFF путь byte-equivalent текущему поведению (подтверждено диффом).

Refs #915, #562

## Summary Transport-swap для avito IMV backfill: 4 IMV-запроса (warm-up → coords → position → get-data) ходят через камуфокс in-page fetch (`/fetch-json` sidecar, #915 Stage 2) вместо curl_cffi. Same-origin avito.ru + sidecar-прокси + warmed-cookies + реальный fingerprint обходят **datacenter-403** (#562/#853) без отдельного IMV-прокси. Это чистый transport-swap — `geoFieldsHash` отдаёт сам avito, реверса нет. За **dormant**-флагом `avito_imv_use_browser_fetcher` (default `False`, ENV `AVITO_IMV_USE_BROWSER_FETCHER`) → деплой не меняет prod IMV-поведение. **Backfill-only**: estimator и sweep-путь (`process_houses_imv_batch`) не тронуты. ## 🎯 Prod-валидация гипотезы (на задеплоенном Stage 2, до мержа этого PR) `POST tradein-browser:3000/fetch-json` на `https://www.avito.ru/web/1/coords/by_address?address=Екатеринбург, Малышева 84` (origin=`/evaluation/realty`, source=avito) → **inner HTTP 200** + реальный JSON (`normalizedAddress`, `point{lat 56.835471, lon 60.617579}`). НЕ 403. Подтверждает: avito IMV XHR из тёплого браузера обходит datacenter-403 → этот PR реально разблокирует #562. ## Что внутри - `_BrowserResponse` + `_BrowserSessionAdapter` в `avito_imv.py` — мимикрия под curl_cffi (`.get/.post/.close`, `.status_code/.text/.json/.raise_for_status`); IMV-флоу не меняется. `evaluate_via_imv` получил `browser_fetcher` kwarg. - `backfill_house_imv` при флаге открывает один `BrowserFetcher(source="avito")` на батч, прокидывает в `_process_one_house` → `evaluate_via_imv`. Флаг OFF → `browser_fetcher=None` → curl-путь как раньше (**byte-equivalent**). - Deep-review #1915 follow-ups: `_post_fetch_json` защищён от ответа без `status`/`body` keys; добавлен тест crash-retry ветки `_do_fetch_json`. ## Test plan - [x] adapter/response units; `evaluate_via_imv(browser_fetcher=...)` happy-path + 403→`IMVAuthError`; backfill flag on/off проводка. - [x] backend `107 passed` (scoped imv/browser/backfill/fetch_json), sidecar `9 passed`. ruff clean. - [x] flag-OFF путь byte-equivalent текущему поведению (подтверждено диффом). Refs #915, #562
bot-backend added 1 commit 2026-06-26 09:46:39 +00:00
feat(tradein-imv): route IMV backfill через BrowserFetcher.fetch_json за dormant-флагом (#915 Stage 3)
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
0d010a707c
Транспорт-своп для avito IMV backfill: вместо curl_cffi 4 IMV-запроса
(warm-up → coords → position → get-data) ходят через камуфокс in-page fetch
(/fetch-json sidecar). Same-origin avito.ru + прокси + warmed-cookies +
реальный fingerprint обходят datacenter-403 (#562/#853) без отдельного
IMV-прокси. За dormant-флагом avito_imv_use_browser_fetcher (default False) —
деплой не меняет prod IMV-поведение.

- avito_imv.py: _BrowserResponse + _BrowserSessionAdapter (мимикрия под
  curl_cffi session/response: .get/.post/.close, .status_code/.text/.json/
  .raise_for_status). evaluate_via_imv получает browser_fetcher kwarg; при
  его наличии адаптер вместо curl-сессии (browser-путь не требует curl_cffi).
- config.py: avito_imv_use_browser_fetcher (ENV AVITO_IMV_USE_BROWSER_FETCHER).
- house_imv_backfill.py: backfill_house_imv при флаге открывает ОДИН
  BrowserFetcher(source="avito") на батч и прокидывает в _process_one_house →
  evaluate_via_imv. Флаг OFF → browser_fetcher=None → curl-путь как раньше.
  Backfill-only: estimator и sweep-путь (process_houses_imv_batch) не тронуты.
- browser_fetcher.py: _post_fetch_json защищён от ответа без status/body keys.
- test_server_fetch_json.py: тест crash-retry ветки _do_fetch_json (relaunch
  + второй _fetch_json_once после browser-crash).
- tests: _BrowserResponse/_BrowserSessionAdapter юниты, evaluate_via_imv
  browser happy-path + 403→IMVAuthError, backfill flag on/off проводка.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Light1YT added 1 commit 2026-06-26 09:54:01 +00:00
docs(tradein): document SCRAPER_FETCH_MODE + AVITO_IMV_USE_BROWSER_FETCHER in .env.example (#915)
All checks were successful
CI / openapi-codegen-check (pull_request) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
e347303465
bot-backend merged commit e03c810306 into main 2026-06-26 09:54:29 +00:00
bot-backend deleted branch feat/915-stage3-imv-browser 2026-06-26 09:54:29 +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#1916
No description provided.