439 — нестандартный код, которым QRATOR отвечает на странице-челлендже
Avito. Его нет ни в одном RFC, поэтому он не попал ни в один список
«это блок» — и обе точки входа трактовали его как штатный исход:
SERP проваливался в `if sc != 200: return None` — пагинация мирно
останавливалась, будто страницы кончились. Ни ротации IP, ни
_report_ban, ни пометки прогона banned.
detail доходил до `if sc != 200: raise ValueError` — то есть считался
ошибкой разбора страницы, без реконнекта на свежий exit-IP и
без ban-сигнала.
То есть обе ветки молчали ровно там, где нас блокировали. Отсюда
прогоны с диагнозом «причина НЕ установлена» (#2700) при том, что у
отказа был вполне чёткий HTTP-код: за 14 дней 43 из 82 прогонов
avito-семейства (52%) завершились failed/banned, и часть из них —
именно этот класс тихого отказа.
439 подключён к УЖЕ СУЩЕСТВУЮЩЕЙ 403-ветке, а не новым механизмом:
тот же смысл (текущий exit-IP признан подозрительным), то же лечение
(смена IP, а не повтор на той же сессии). В serp.py — в условие
блока и в backconnect-reconnect; в detail.py — в блок-ветку.
Заодно текст AvitoBlockedError в detail.py перестал жёстко печатать
"403": на 439 он врал бы в логах ровно там, где по логу и ставят
диагноз.
Тест test_3044 параметризован по [403, 439] намеренно — не ради
полноты, а чтобы стеречь ПАРИТЕТ: 403 заведомо рабочая ветка, и если
кто-то перепишет блок-логику и уронит только 439, упадёт половина
кейсов и сразу покажет, что ветки разъехались.
Проверено:
- фальсификация на коде до правки: 403-кейсы проходят, 439-кейсы
падают (SERP «DID NOT RAISE», detail «ValueError: HTTP 439»)
- регрессия: 421 passed, 2 skipped (-k "avito or ban_kind or
proxy_pool or browser_routing")
#3035 (обрезка ?context= в avito_detail_backfill) в этот коммит НЕ
входит — см. комментарий в issue: замер показал, что query несут все
55 140 avito-URL, а та же обрезка стоит ещё в двух местах kit'а, и
знак эффекта от её снятия неизвестен.
Refs #3044, #2700