diff --git a/tradein-mvp/browser/server.py b/tradein-mvp/browser/server.py index 441df916..fff97c2a 100644 --- a/tradein-mvp/browser/server.py +++ b/tradein-mvp/browser/server.py @@ -61,14 +61,11 @@ Per-provider модель (#1793): НЕ читается — см. _RETIRED_ENV; в проде он всё ещё выставлен во всех трёх контейнерах и ни на что не влияет. BROWSER_BLOCK_IMAGES — булев глобальный дефолт camoufox block_images (#3185). - Camoufox сам предупреждает (LeakWarning), что блокировка - картинок повышает риск детекта на крупных WAF — картинки - часть нормального fingerprint браузера, их отсутствие - выделяет сессию. Авито стоит за QRATOR: с block_images=True - в проде ~32% detail-сборов возвращали заглушку. Дефолт для - avito поэтому False (не блокировать); для cian/yandex/generic - остаётся True — их WAF-чувствительность не замеряна, менять - без замера не будем. + Дефолт для ВСЕХ провайдеров — True (блокируем). Пробовали + выключить для avito по гипотезе «блокировка = сигнал для + QRATOR» — замер её не подтвердил, дефолт откатан; разбор + и цифры в комментарии у _BLOCK_IMAGES_DEFAULT_BY_PROVIDER. + Сама ручка осталась: выключить можно env'ом, без релиза. BROWSER_BLOCK_IMAGES_{PROVIDER} — per-provider override, тот же формат, что у BROWSER_MIN_PAGE_INTERVAL_S_{PROVIDER}: PROVIDER в upper-case (AVITO, CIAN, YANDEX, GENERIC), перебивает и @@ -248,10 +245,20 @@ _MIN_PAGE_INTERVAL_BY_PROVIDER: dict[str, float] = { p: _resolve_min_interval(p) for p in ("avito", "cian", "yandex", "generic") } -# Код-дефолт block_images ПО ПРОВАЙДЕРУ (#3185): avito не измерен пассивно — детект на -# QRATOR стоит дороже, чем экономия трафика/времени рендера. cian/yandex/generic не -# замерены, поведение не трогаем (True, как раньше). -_BLOCK_IMAGES_DEFAULT_BY_PROVIDER: dict[str, bool] = {"avito": False} +# Код-дефолт block_images ПО ПРОВАЙДЕРУ. Сейчас пуст — все провайдеры блокируют +# картинки, как и до #3185 (см. _BLOCK_IMAGES_DEFAULT_FALLBACK). Ручка из #3185 +# остаётся: поменять поведение можно через env, без релиза. +# +# Почему дефолт откатан (#3185). Гипотеза «блокировка картинок = лишний сигнал для +# QRATOR» шла от camoufox'ского LeakWarning, а не от замера. Прямой A/B на сайдкаре её +# не подтвердил: 6/8 успехов с блокировкой против 7/8 без — разница в пределах шума. +# На проде после выкатки avito=False стало хуже: прогон 5200 (картинки блокировались) — +# 43/63 карточки при 32% блоков; прогоны 5206 и 5207 (не блокировались) — 2/22 и 2/13 +# при 91% и 77% блоков. Причинность НЕ доказана: между прогонами через тот же пул +# прокси прошло ~40 диагностических запросов, репутация пула могла просесть от них. +# Но выгоды правка не показала ни разу, поэтому дефолт возвращается к прежнему +# поведению; эффект картинок мерить отдельно и на чистом пуле. +_BLOCK_IMAGES_DEFAULT_BY_PROVIDER: dict[str, bool] = {} _BLOCK_IMAGES_DEFAULT_FALLBACK: bool = True @@ -263,7 +270,7 @@ def _resolve_block_images( Приоритет (выше — сильнее): per-provider env ``BROWSER_BLOCK_IMAGES_{PROVIDER}`` → глобальный env ``BROWSER_BLOCK_IMAGES`` → код-дефолт per-provider - (``_BLOCK_IMAGES_DEFAULT_BY_PROVIDER``, avito=False, остальные=True). Не кидает + (``_BLOCK_IMAGES_DEFAULT_BY_PROVIDER``; сейчас пуст → все True). Не кидает исключений — невалидный/отсутствующий env тихо проваливается на следующий уровень. Args: @@ -434,13 +441,9 @@ async def _launch_browser(provider: str, proxy_override: str | None = None) -> N "locale": "ru-RU", "geoip": True, "humanize": True, - # block_images НЕ бесплатен (#3185): camoufox сам предупреждает LeakWarning'ом, - # что блокировка image-запросов повышает риск детекта на крупных WAF — картинки - # часть штатного fingerprint браузера, их отсутствие выделяет сессию. Авито за - # QRATOR: пока блокировали всем провайдерам одинаково, ~32% detail-сборов - # получали заглушку. Теперь значение per-provider (BROWSER_BLOCK_IMAGES / - # BROWSER_BLOCK_IMAGES_{PROVIDER}, см. docstring модуля) — avito по дефолту НЕ - # блокирует, cian/yandex/generic блокируют как раньше (не измерены, не трогаем). + # Значение per-provider (#3185): env BROWSER_BLOCK_IMAGES / + # BROWSER_BLOCK_IMAGES_{PROVIDER}, см. docstring модуля. Дефолт для всех — True + # (блокируем), почему именно так — у _BLOCK_IMAGES_DEFAULT_BY_PROVIDER. "block_images": _BLOCK_IMAGES_BY_PROVIDER.get(provider, _BLOCK_IMAGES_DEFAULT_FALLBACK), # Анти-leak: WebRTC может слить реальный IP контейнера мимо прокси → деанон. "block_webrtc": True, diff --git a/tradein-mvp/browser/test_server.py b/tradein-mvp/browser/test_server.py index 3ecaae35..cc6d44ac 100644 --- a/tradein-mvp/browser/test_server.py +++ b/tradein-mvp/browser/test_server.py @@ -495,13 +495,13 @@ def test_pace_provider_independent_per_provider(monkeypatch: pytest.MonkeyPatch) # ── #3185: _resolve_block_images (per-provider block_images) ─────────────────────── -def test_resolve_block_images_default_avito_unblocked() -> None: - """Код-дефолт: avito НЕ блокирует картинки (QRATOR-детект, ~32% заглушек).""" - assert server._resolve_block_images("avito", environ={}) is False +def test_resolve_block_images_default_avito_blocked() -> None: + """Код-дефолт: avito блокирует картинки — как и все (откат #3185, см. server.py).""" + assert server._resolve_block_images("avito", environ={}) is True def test_resolve_block_images_default_others_blocked() -> None: - """Код-дефолт: cian/yandex/generic блокируют как раньше (не измерены).""" + """Код-дефолт: cian/yandex/generic блокируют — поведение не менялось никогда.""" assert server._resolve_block_images("cian", environ={}) is True assert server._resolve_block_images("yandex", environ={}) is True assert server._resolve_block_images("generic", environ={}) is True @@ -522,9 +522,15 @@ def test_resolve_block_images_per_provider_env_overrides_global() -> None: def test_resolve_block_images_per_provider_env_overrides_avito_default() -> None: - """BROWSER_BLOCK_IMAGES_AVITO=true может включить блокировку и для avito.""" - env = {"BROWSER_BLOCK_IMAGES_AVITO": "true"} - assert server._resolve_block_images("avito", environ=env) is True + """BROWSER_BLOCK_IMAGES_AVITO=false снимает блокировку для avito, не трогая прочих. + + Проверка направления, которое ОТЛИЧАЕТСЯ от дефолта: после отката #3185 дефолт для + всех True, поэтому тест с env=true проходил бы и у функции, всегда возвращающей + True. Ручка нужна именно чтобы вернуть avito=False без релиза — это и проверяем. + """ + env = {"BROWSER_BLOCK_IMAGES_AVITO": "false"} + assert server._resolve_block_images("avito", environ=env) is False + assert server._resolve_block_images("cian", environ=env) is True def test_resolve_block_images_unrecognized_value_is_falsy() -> None: