All checks were successful
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 3m10s
Deploy Trade-In / build-backend (push) Successful in 1m34s
Deploy Trade-In / deploy (push) Successful in 2m4s
34 lines
2.5 KiB
Python
34 lines
2.5 KiB
Python
"""Cian-specific exceptions для anti-bot detection."""
|
||
|
||
from scraper_kit.proxy_errors import ProxyBanError
|
||
|
||
|
||
class CianBlockedError(ProxyBanError):
|
||
"""HTTP 403 от Циана — узел, с которого мы пришли, отбит WAF'ом площадки.
|
||
|
||
Живая различающая проба 2026-08-10 (#2700), один и тот же detail-URL, один и тот
|
||
же код, менялся ТОЛЬКО прокси-узел:
|
||
|
||
узел 1 (asocks-residential, 46.8.110.92) → HTTP 403, 21 564 байт,
|
||
маркер `cian_waf_block`
|
||
узел 9 (asocks-mobile-1, 5.227.16.0) → HTTP 200, 617 352 байт, state ok
|
||
узел 10 (asocks-mobile-2, 95.104.183.29) → HTTP 200, 617 355 байт, state ok
|
||
узел 11 (asocks-mobile-3, 95.55.49.98) → HTTP 200, 617 407 байт, state ok
|
||
|
||
То есть 403 — свойство ПАРЫ «узел × Циан», а не площадки вообще и не нашего
|
||
запроса: detail-страница Циана авторизации не требует и отдаётся без единой куки
|
||
(проба выше шла без них). Поэтому исключение наследует `ProxyBanError` — тот же
|
||
приём, что у `AvitoBlockedError`/`DomClickBlockedError`: generic curl-слой
|
||
(`providers/_proxy.py::curl_proxy_url`) увидит `isinstance(exc, ProxyBanError)` и
|
||
снимет узел с выдачи ИМЕННО Циану (per-source бан, #2600 п.2), не трогая остальные
|
||
источники.
|
||
|
||
Почему это заводится отдельным исключением, а не остаётся `return None`: пока 403
|
||
гасился внутри `fetch_detail`, наружу не выходило НИЧЕГО — пул получал
|
||
`mark_health(ok=True)` на отбитый узел и продолжал выдавать его Циану, а прогон
|
||
писал `detail_failed=50` при `errors_count=0` и статусе `done` (#2700: 15 суток
|
||
подряд, 50 из 50 отказов ежедневно).
|
||
|
||
404 сюда НЕ относится: удалённое объявление — не бан, узел за него наказывать
|
||
нельзя. Остальные не-200 остаются прежним мягким отказом (`None` + WARNING).
|
||
"""
|