fix(avito): считать HTTP 439 блокировкой, а не концом выдачи #3065
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3065
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "fix/avito-439-and-context"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Топ-1 находка аудита скрапперов Avito/Cian (24.08).
Проблема
439 — нестандартный код, которым QRATOR отвечает на странице-челлендже Avito. Его нет ни в одном RFC, поэтому он не попал ни в один список «это блок» — и обе точки входа трактовали его как штатный исход:
serp.py)if sc != 200: return None_report_ban, ни пометки прогонаbanneddetail.py)if sc != 200: raise ValueErrorОбе ветки молчали ровно там, где нас блокировали. Отсюда прогоны с диагнозом «причина НЕ установлена» (#2700) при том, что у отказа был вполне чёткий HTTP-код: за 14 дней 43 из 82 прогонов avito-семейства (52 %) завершились
failed/banned, и часть из них — именно этот класс тихого отказа.Ортогонально уже сделанному #3046 (тот учил браузер дожидаться решения челленджа) — 439 всё ещё прилетает на curl_cffi-путях: SERP-фолбэк
_fetch_serp_htmlи detail, где код-дефолтavito_detail_backfill_use_curl=Trueпереопределён только прод-compose'ом.Решение
439 подключён к уже существующей 403-ветке, а не новым механизмом: тот же смысл (текущий exit-IP признан подозрительным), то же лечение (смена IP, а не повтор на той же сессии).
serp.py— в условие блока (sc in (403, 429, 439)) и в backconnect-reconnect (sc in (403, 439) or is_firewall)detail.py— в блок-ветку (sc in (403, 439) or is_firewall)Заодно текст
AvitoBlockedErrorвdetail.pyперестал жёстко печатать"403"— на 439 он врал бы в логах ровно там, где по логу и ставят диагноз.Test plan
DID NOT RAISE, detailValueError: avito detail HTTP 439. То есть тест ловит именно эту регрессию, а не проходит «сам по себе».421 passed, 2 skipped(-k "avito or ban_kind or proxy_pool or browser_routing").Тест
test_3044параметризован по[403, 439]намеренно — не ради полноты, а чтобы стеречь паритет: 403 заведомо рабочая ветка, и если кто-то перепишет блок-логику и уронит только 439, упадёт половина кейсов и сразу покажет, что ветки разъехались.Чего здесь НЕТ
#3035 (обрезка
?context=вavito_detail_backfill.py:433) сознательно не вошла. Проверка на проде показала, что вопрос не такой простой, как выглядел — подробности комментарием в #3035.Refs #3044, #2700
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