Побочный эффект предыдущего коммита: 403 стал исключением, и POST /scrape/cian-detail
уронил бы его наружу необработанным. «Страницу не разобрали» (404) и «нас не пустили
с этого узла» (502) — разные новости для того, кто дёргает ручку руками.
Refs #2700
Различающая проба на проде 10.08: один и тот же detail-URL, один и тот же код,
менялся ТОЛЬКО прокси-узел. Узел 1 — HTTP 403, 21 564 байта, маркер
`cian_waf_block`; узлы 9/10/11 — HTTP 200, ~617 КБ, состояние разбирается. Отбита
пара «узел × Циан», а не площадка: те же 200 пришли без единой куки — detail-
страница авторизации не требует, и к протухшим 30.06 кукам эти 403 отношения не
имели.
Держалось это пятнадцать суток потому, что 403 умирал внутри провайдера в
`return None`: наружу не выходило ничего, пул получал mark_health(ok=True) на
отбитый узел и продолжал выдавать его Циану, а прогон писал detail_failed=50 при
errors_count=0 и статусе done.
- providers/cian/detail.py: 403 → CianBlockedError (наследник ProxyBanError, как
AvitoBlockedError/DomClickBlockedError). Generic curl-слой сам делает
mark_banned на пару «узел × cian», оба вызывающих в pipeline уже считают
исключение в errors_count. 404 (снятое объявление) баном не считается.
- scrape_runs.mark_done (обе копии): прогон, у которого отказала КАЖДАЯ попытка
целой фазы (>=3 попыток), больше не done. Пары <phase>_attempted/<phase>_failed
ищутся в самих counters, а не по зашитому списку фаз. Замер на проде за 90
суток: 52 прогона из 3292 done (1.6%) — 33 cian_city_sweep*, 11 avito_city_sweep*.
Тест красный на старом коде в трёх утверждениях: узел не банился, и оба
финализатора писали 'done' прогону 3258 (detail 50/50 отказ).
Refs #2700