fix(tradein/avito-detail): живой прогрев сессии + батч-на-сессию — снимает 403 на curl-backfill (#1551) #2089

Merged
lekss361 merged 4 commits from fix/tradein-avito-detail-warmup-batch into main 2026-06-28 22:34:39 +00:00
Owner

Проблема

avito_detail_backfill в curl-режиме (AVITO_DETAIL_BACKFILL_USE_CURL=true) строил холодную curl_cffi-сессию на каждую карточку и бил прямо в detail-URL → Avito-файрвол резал HTTP 403 (прод run 472: 6/8 blocked, abort на 2 enriched). Холодная сессия не имеет антибот-куки.

Решение — живой прогрев + батч-на-сессию

Эмпирически отресёрчено на проде (резидентный sticky-прокси МГТС):

  • Прогрев: GET Yandex SERP (органический referer) → GET Avito EKB search-страница (Referer=yandex) сеет антибот-куки → прогретая сессия держит батч detail-GET'ов. Detail-GET шлёт Referer = URL search-страницы.
  • Доказано пробами: одна warmed-сессия = 66/66 карточек, 0 блоков (холодная ловила 439 на 2-м запросе).
  • Sticky-IP: МГТС даёт один фиксированный exit-IP (6/6 свежих сессий = тот же IP; per-connection ротации нет). Поэтому rebuild сессии ≠ новый IP. on-block = cooldown + in-session перепоиск (не дискард рабочей сессии — escape через IP софтом невозможен).

Параметры (всё в default_params jsonb — тюнятся в БД без редеплоя)

Param Дефолт Что делает
research_every 50 лёгкий in-session перепоиск (re-GET search, тот же IP, освежить куки) — «≈ карточек на SERP-странице»
warm_batch 500 периодический полный re-warm (свежий TLS+куки, тот же sticky IP — session-hygiene, НЕ ротация) — «≈ 10 страниц»
block_cooldown_sec 30 пауза на блоке (дать rate-limit окну остыть)
warm_timeout_s 90 hard-timeout на warm/research await'ы (#1950)
request_delay_sec (БД 5) задержка между detail + джиттер ±30%

Файлы

  • avito_detail.py: warm_up_session / research_in_session / build_warmed_session; fetch_detail(referer, reconnect_on_block) (kw-only, дефолты сохраняют browser/own-session/scrape_pipeline пути).
  • avito_detail_backfill.py: use_curl-ветка строит warmed shared-сессию; warm_batch/research_every в loop; on-block cooldown+research; джиттер.

Безопасность / харднинг

  • Backward-compat: новые параметры kw-only с дефолтами — legacy-вызовы fetch_detail не меняются (проверено: admin.py, scrape_pipeline.py).
  • #1950 (zombie-hang): все новые in-loop сетевые await'ы (build_warmed_session, research_in_session) обёрнуты в asyncio.wait_for(warm_timeout_s); warm_batch re-warm строит новую сессию ДО close старой (graceful degrade на timeout).

Тесты

ruff line-100 clean; 324 passed, 1 skipped (tests/scrapers/ + tests/tasks/), без регрессий. Новые: warm_up_session/research_in_session, on-block cooldown+research-no-rebuild, abort-reorder.

Pre-push code-review: ⚠️ MINOR → все замечания (включая #1950-обёртки) устранены.

## Проблема `avito_detail_backfill` в curl-режиме (`AVITO_DETAIL_BACKFILL_USE_CURL=true`) строил **холодную** curl_cffi-сессию на каждую карточку и бил прямо в detail-URL → Avito-файрвол резал **HTTP 403** (прод run 472: 6/8 blocked, abort на 2 enriched). Холодная сессия не имеет антибот-куки. ## Решение — живой прогрев + батч-на-сессию Эмпирически отресёрчено на проде (резидентный sticky-прокси МГТС): - **Прогрев:** GET Yandex SERP (органический referer) → GET Avito EKB search-страница (`Referer=yandex`) сеет антибот-куки → прогретая сессия **держит батч detail-GET'ов**. Detail-GET шлёт `Referer` = URL search-страницы. - **Доказано пробами:** одна warmed-сессия = **66/66 карточек, 0 блоков** (холодная ловила 439 на 2-м запросе). - **Sticky-IP:** МГТС даёт **один фиксированный exit-IP** (6/6 свежих сессий = тот же IP; per-connection ротации нет). Поэтому rebuild сессии ≠ новый IP. on-block = **cooldown + in-session перепоиск** (не дискард рабочей сессии — escape через IP софтом невозможен). ## Параметры (всё в `default_params` jsonb — тюнятся в БД без редеплоя) | Param | Дефолт | Что делает | |---|---|---| | `research_every` | 50 | лёгкий in-session перепоиск (re-GET search, тот же IP, освежить куки) — «≈ карточек на SERP-странице» | | `warm_batch` | 500 | периодический полный re-warm (свежий TLS+куки, тот же sticky IP — **session-hygiene, НЕ ротация**) — «≈ 10 страниц» | | `block_cooldown_sec` | 30 | пауза на блоке (дать rate-limit окну остыть) | | `warm_timeout_s` | 90 | hard-timeout на warm/research await'ы (#1950) | | `request_delay_sec` | (БД 5) | задержка между detail + джиттер ±30% | ## Файлы - `avito_detail.py`: `warm_up_session` / `research_in_session` / `build_warmed_session`; `fetch_detail(referer, reconnect_on_block)` (kw-only, дефолты сохраняют browser/own-session/scrape_pipeline пути). - `avito_detail_backfill.py`: use_curl-ветка строит warmed shared-сессию; warm_batch/research_every в loop; on-block cooldown+research; джиттер. ## Безопасность / харднинг - Backward-compat: новые параметры kw-only с дефолтами — legacy-вызовы `fetch_detail` не меняются (проверено: admin.py, scrape_pipeline.py). - **#1950 (zombie-hang):** все новые in-loop сетевые await'ы (`build_warmed_session`, `research_in_session`) обёрнуты в `asyncio.wait_for(warm_timeout_s)`; warm_batch re-warm строит новую сессию ДО close старой (graceful degrade на timeout). ## Тесты ruff line-100 clean; **324 passed, 1 skipped** (tests/scrapers/ + tests/tasks/), без регрессий. Новые: warm_up_session/research_in_session, on-block cooldown+research-no-rebuild, abort-reorder. Pre-push code-review: ⚠️ MINOR → все замечания (включая #1950-обёртки) устранены.
lekss361 added 4 commits 2026-06-28 22:33:20 +00:00
lekss361 merged commit 69845ddcee into main 2026-06-28 22:34:39 +00:00
lekss361 deleted branch fix/tradein-avito-detail-warmup-batch 2026-06-28 22:34:39 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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#2089
No description provided.