tradein/avito: detail-страницы отдают HTTP 439 firewall независимо от IP и клиента #2827

Open
opened 2026-08-11 04:53:40 +00:00 by lekss361 · 1 comment
Owner

Что происходит

avito_city_sweep стабильно падает в failed на фазе detail: три блока подряд → abort.

city-sweep run_id=3647: detail BLOCKED #1/20 (consecutive=1): Avito detail firewall/soft-block (browser-mode)
city-sweep run_id=3647: detail BLOCKED #2/20 (consecutive=2): ...
city-sweep run_id=3647: detail BLOCKED #3/20 (consecutive=3): ...
city-sweep run_id=3647: detail ABORT — 3 consecutive blocks (IP rate-limited)

При этом SERP работает: run_id=3645 дал inserted=69 updated=6 из 75 лотов.

Это не про прокси — проверено

Причиной казался забаненный egress (SCRAPER_PROXY_URL указывал на asocks-residential-1, забаненный для avito до 13.08). После переключения на мобильный asocks-mobile-1 выдача починилась, а детали — нет.

Разделяющий тест на одной и той же карточке https://www.avito.ru/ekaterinburg/kvartiry/3-k._kvartira_579_m_1225_et._8282057970, клиент curl_cffi impersonate=chrome120:

Путь Результат
без прокси (datacenter IP) HTTP 439, len=7851, маркер firewall
через мобильный прокси HTTP 439, len=7851, маркер firewall
browser-mode (camoufox) soft-block, тот же класс

Ответ побайтово одинаковой длины во всех случаях. Вывод: блокировка не зависит ни от выходного IP, ни от типа клиента — это защита Авито на detail-страницах. Ротация прокси и смена fingerprint'а в текущем виде её не обходят.

Влияние

Обогащение деталями не работает → у объявлений Авито нет полей, которые берутся с карточки. SERP-intake при этом идёт, объявления в базу попадают. Статус прогона при этом failed, хотя сбор частично успешен (phase-honest-status, #2700) — мониторинг показывает красное на фоне работающего сбора.

Что стоит рассмотреть

  • Прогрев сессии перед detail-фазой (последовательный переход с SERP на карточку в одном контексте, а не прямой запрос по URL).
  • Пейсинг: сейчас три запроса подряд → abort. Возможно, лимит по частоте, а не по факту доступа.
  • Проверить, не изменился ли требуемый набор заголовков/кук для detail в сравнении с SERP.
  • Решить продуктово: если обход дорогой — согласиться на SERP-only и убрать failed со статуса прогона, чтобы не шуметь в мониторинге.

Как воспроизвести

ssh -o ClearAllForwardings=yes gendesign
docker exec -i tradein-backend python -c "
from app.core.config import settings
from curl_cffi import requests as r
px = settings.scraper_proxy_url
U = 'https://www.avito.ru/ekaterinburg/kvartiry/3-k._kvartira_579_m_1225_et._8282057970'
for label, kw in (('direct', {}), ('proxy', {'proxies': {'http': px, 'https': px}})):
    resp = r.get(U, impersonate='chrome120', timeout=30, **kw)
    print(label, resp.status_code, len(resp.text), 'firewall' in resp.text.lower())
"

Обнаружено при разборе инцидента с первым платящим заказчиком 2026-08-10/11.

## Что происходит `avito_city_sweep` стабильно падает в `failed` на фазе `detail`: три блока подряд → abort. ``` city-sweep run_id=3647: detail BLOCKED #1/20 (consecutive=1): Avito detail firewall/soft-block (browser-mode) city-sweep run_id=3647: detail BLOCKED #2/20 (consecutive=2): ... city-sweep run_id=3647: detail BLOCKED #3/20 (consecutive=3): ... city-sweep run_id=3647: detail ABORT — 3 consecutive blocks (IP rate-limited) ``` При этом **SERP работает**: `run_id=3645` дал `inserted=69 updated=6` из 75 лотов. ## Это не про прокси — проверено Причиной казался забаненный egress (`SCRAPER_PROXY_URL` указывал на `asocks-residential-1`, забаненный для avito до 13.08). После переключения на мобильный `asocks-mobile-1` **выдача починилась**, а детали — нет. Разделяющий тест на одной и той же карточке `https://www.avito.ru/ekaterinburg/kvartiry/3-k._kvartira_579_m_1225_et._8282057970`, клиент curl_cffi `impersonate=chrome120`: | Путь | Результат | |---|---| | без прокси (datacenter IP) | **HTTP 439**, len=7851, маркер `firewall` | | через мобильный прокси | **HTTP 439**, len=7851, маркер `firewall` | | browser-mode (camoufox) | soft-block, тот же класс | Ответ побайтово одинаковой длины во всех случаях. Вывод: блокировка **не зависит ни от выходного IP, ни от типа клиента** — это защита Авито на detail-страницах. Ротация прокси и смена fingerprint'а в текущем виде её не обходят. ## Влияние Обогащение деталями не работает → у объявлений Авито нет полей, которые берутся с карточки. SERP-intake при этом идёт, объявления в базу попадают. Статус прогона при этом `failed`, хотя сбор частично успешен (`phase-honest-status`, #2700) — мониторинг показывает красное на фоне работающего сбора. ## Что стоит рассмотреть - Прогрев сессии перед detail-фазой (последовательный переход с SERP на карточку в одном контексте, а не прямой запрос по URL). - Пейсинг: сейчас три запроса подряд → abort. Возможно, лимит по частоте, а не по факту доступа. - Проверить, не изменился ли требуемый набор заголовков/кук для detail в сравнении с SERP. - Решить продуктово: если обход дорогой — согласиться на SERP-only и убрать `failed` со статуса прогона, чтобы не шуметь в мониторинге. ## Как воспроизвести ```bash ssh -o ClearAllForwardings=yes gendesign docker exec -i tradein-backend python -c " from app.core.config import settings from curl_cffi import requests as r px = settings.scraper_proxy_url U = 'https://www.avito.ru/ekaterinburg/kvartiry/3-k._kvartira_579_m_1225_et._8282057970' for label, kw in (('direct', {}), ('proxy', {'proxies': {'http': px, 'https': px}})): resp = r.get(U, impersonate='chrome120', timeout=30, **kw) print(label, resp.status_code, len(resp.text), 'firewall' in resp.text.lower()) " ``` Обнаружено при разборе инцидента с первым платящим заказчиком 2026-08-10/11.
lekss361 added the
bug
priority/p1
scrapers
tradein
labels 2026-08-16 10:25:21 +00:00
Collaborator

Замер 28.08.2026: авторизованная сессия проходит там, где анонимная получает 439/403.

Проверено вживую, одна и та же карточка 8273772563, один и тот же адрес, разница только в сессии:

аноним залогиненный сеанс
ответ 403 / 439 200
размер заглушка 6 756 б 1 064 467 б
цена в разметке 8 650 000 ₽
параметров 19
антибот-куки нет __zzatw-avito, cfidsw-avito, sx, f

Затем пять карточек подряд из той же сессии, пауза 1,5 с:

200  779 802 б  481 мс
200  759 535 б  316 мс
200  789 714 б  352 мс
200  806 944 б  482 мс
200  740 594 б  482 мс

Пять из пяти, ноль блоков. Для сравнения, прод в тот же день: прогон 5190 — пять попыток за 72 секунды, то есть с бОльшими паузами, и пять блоков подряд, enriched=0.

Отсюда прямой вывод: дело не в темпе и не в адресе. Анонимный запрос к карточке отбивается независимо от IP — я получил 439 и со своей домашней машины, и после прогрева сессии на выдаче. Владелец получил «проблема с IP» на своём адресе, при том что выдача у него открывалась.

Что делает сессию проходной

  • антибот-куки __zzatw-avito / cfidsw-avito — ровно те, отсутствие которых код репортит как AvitoWarmupCookiesMissingError;
  • cookie авторизации — HttpOnly, в document.cookie не видна (там только buyer_location_id, buyer_from_page). Переносить сессию в скраппер нужно на уровне CDP (Network.getAllCookies), а не через JS;
  • ?context= из выдачи — карточки открывались с ним (ср. #3035, где бэкфилл его отрезает).

Что это значит для планов

Мой предварительный вывод был «аккаунты не помогут, рубит по IP до проверки авторизации». Замер его опроверг — привожу как есть.

Отдельно объяснилась деградация: 22.08 коммит b61123d7 перевёл прод на браузерный режим, а прогрев сессии (яндексовый referer → поиск Авито → антибот-куки) реализован только для curl-путиwarm_up_session принимает AsyncSession. Браузерный путь ходит на карточки холодным, и обогащение затухало четыре дня: 161 → 161 → 116 → 23 → 1 → 2.

**Замер 28.08.2026: авторизованная сессия проходит там, где анонимная получает 439/403.** Проверено вживую, одна и та же карточка `8273772563`, один и тот же адрес, разница только в сессии: | | аноним | залогиненный сеанс | |---|---|---| | ответ | 403 / 439 | **200** | | размер | заглушка 6 756 б | **1 064 467 б** | | цена в разметке | — | 8 650 000 ₽ | | параметров | — | 19 | | антибот-куки | нет | **`__zzatw-avito`, `cfidsw-avito`, `sx`, `f`** | Затем пять карточек подряд из той же сессии, пауза 1,5 с: ``` 200 779 802 б 481 мс 200 759 535 б 316 мс 200 789 714 б 352 мс 200 806 944 б 482 мс 200 740 594 б 482 мс ``` **Пять из пяти, ноль блоков.** Для сравнения, прод в тот же день: прогон 5190 — пять попыток за 72 секунды, то есть с бОльшими паузами, и **пять блоков подряд, `enriched=0`**. Отсюда прямой вывод: **дело не в темпе и не в адресе**. Анонимный запрос к карточке отбивается независимо от IP — я получил 439 и со своей домашней машины, и после прогрева сессии на выдаче. Владелец получил «проблема с IP» на своём адресе, при том что выдача у него открывалась. ## Что делает сессию проходной - антибот-куки `__zzatw-avito` / `cfidsw-avito` — ровно те, отсутствие которых код репортит как `AvitoWarmupCookiesMissingError`; - cookie авторизации — **`HttpOnly`**, в `document.cookie` не видна (там только `buyer_location_id`, `buyer_from_page`). Переносить сессию в скраппер нужно на уровне CDP (`Network.getAllCookies`), а не через JS; - `?context=` из выдачи — карточки открывались с ним (ср. #3035, где бэкфилл его отрезает). ## Что это значит для планов Мой предварительный вывод был «аккаунты не помогут, рубит по IP до проверки авторизации». **Замер его опроверг** — привожу как есть. Отдельно объяснилась деградация: 22.08 коммит `b61123d7` перевёл прод на браузерный режим, а прогрев сессии (яндексовый referer → поиск Авито → антибот-куки) реализован **только для curl-пути** — `warm_up_session` принимает `AsyncSession`. Браузерный путь ходит на карточки холодным, и обогащение затухало четыре дня: 161 → 161 → 116 → 23 → 1 → 2.
Sign in to join this conversation.
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#2827
No description provided.