Сайдкар безусловно блокирует картинки — camoufox предупреждает, что это детектируется WAF (44 раза за 3 часа) #3185

Closed
opened 2026-08-28 17:42:15 +00:00 by bot-backend · 2 comments
Collaborator

Найдено при проверке гипотезы «а точно ли скраппер ходит браузером» (28.08).

Сначала — сомнение снято

Скраппер действительно ходит через браузер. В окне прогона 5200 (16:47-17:01) сайдкар принимал непрерывный поток POST /fetch от python-httpx/0.28.1. Режим сбора — не проблема.

Доля блоков, посчитанная по размерам ответов самого сайдкара в этом окне: 29 заглушек против 63 живых карточек, ~32%.

Что нашлось в логе сайдкара

За три часа — 44 предупреждения от самого camoufox, всегда одно и то же:

LeakWarning: Blocking image requests has been reported to cause
detection issues on major WAFs.
If this is intentional, pass `i_know_what_im_doing=True`.

То есть используемая нами библиотека прямым текстом сообщает, что текущая конфигурация детектируется крупными WAF. Авито стоит за QRATOR.

Почему это нельзя выключить

browser/server.py:379, в _launch_browser:

# Скорость: не грузим картинки — нам нужен HTML/JSON, рендер быстрее
# (трафик безлимитный, выигрыш именно по времени загрузки).
"block_images": True,

Захардкожено. Ручки нет.

Хуже: BROWSER_BLOCK_RESOURCES=true задан в проде и не читается кодом — он в списке _RETIRED_ENV (server.py:573-583). В самом коде про эту ловушку написано ровно то, что и произошло:

оператор ставит BROWSER_BLOCK_RESOURCES=false, чтобы посмотреть страницу с ресурсами, ничего не меняется, и он делает вывод не о переменной, а о блокировке

BROWSER_BLOCK_RESOURCE_TYPES в проде не задан вовсе. Так что картинки блокируются безусловно, всегда, ради выигрыша по времени рендера.

Оговорка

Это предупреждение библиотеки, а не наш замер. Блокировка картинок точно не единственная причина: мой прямой прогон 16 карточек через тот же сайдкар с той же настройкой дал 15/16. Но из всех названных причин эта — единственная конкретная, документированная и лежащая в нашем собственном конфиге.

Что сделать

  1. Вывести block_images в настройку (per-provider или per-request), дефолт для Авито — не блокировать.
  2. Замерить A/B на одинаковых карточках: картинки блокируются против не блокируются, доля заглушек. Выборка не меньше 40 на группу — блоки стохастичны (см. #3184), на малых выборках разницы не увидеть.
  3. Если разницы нет — вернуть блокировку ради скорости и закрыть вопрос измерением, а не догадкой.
  4. Убрать BROWSER_BLOCK_RESOURCES из compose: мёртвая ручка, которая уже один раз сработает как ловушка.

Приёмка

  • block_images управляем, для Авито выключен
  • A/B проведён, числа в тикете
  • Мёртвый BROWSER_BLOCK_RESOURCES убран из compose
  • LeakWarning в логе сайдкара больше не появляется (либо появляется осознанно, с i_know_what_im_doing)

Оценка S. Refs #3177, #3184

Найдено при проверке гипотезы «а точно ли скраппер ходит браузером» (28.08). ## Сначала — сомнение снято Скраппер **действительно ходит через браузер**. В окне прогона 5200 (16:47-17:01) сайдкар принимал непрерывный поток `POST /fetch` от `python-httpx/0.28.1`. Режим сбора — не проблема. Доля блоков, посчитанная по размерам ответов самого сайдкара в этом окне: **29 заглушек против 63 живых карточек, ~32%**. ## Что нашлось в логе сайдкара За три часа — **44 предупреждения от самого camoufox**, всегда одно и то же: ``` LeakWarning: Blocking image requests has been reported to cause detection issues on major WAFs. If this is intentional, pass `i_know_what_im_doing=True`. ``` То есть используемая нами библиотека прямым текстом сообщает, что текущая конфигурация детектируется крупными WAF. Авито стоит за QRATOR. ## Почему это нельзя выключить `browser/server.py:379`, в `_launch_browser`: ```python # Скорость: не грузим картинки — нам нужен HTML/JSON, рендер быстрее # (трафик безлимитный, выигрыш именно по времени загрузки). "block_images": True, ``` Захардкожено. Ручки нет. Хуже: `BROWSER_BLOCK_RESOURCES=true` **задан в проде и не читается кодом** — он в списке `_RETIRED_ENV` (`server.py:573-583`). В самом коде про эту ловушку написано ровно то, что и произошло: > оператор ставит `BROWSER_BLOCK_RESOURCES=false`, чтобы посмотреть страницу с ресурсами, ничего не меняется, и он делает вывод не о переменной, а о блокировке `BROWSER_BLOCK_RESOURCE_TYPES` в проде не задан вовсе. Так что картинки блокируются **безусловно, всегда**, ради выигрыша по времени рендера. ## Оговорка Это предупреждение библиотеки, а не наш замер. Блокировка картинок **точно не единственная** причина: мой прямой прогон 16 карточек через тот же сайдкар с той же настройкой дал 15/16. Но из всех названных причин эта — единственная конкретная, документированная и лежащая в нашем собственном конфиге. ## Что сделать 1. Вывести `block_images` в настройку (per-provider или per-request), дефолт для Авито — **не блокировать**. 2. Замерить A/B на одинаковых карточках: картинки блокируются против не блокируются, доля заглушек. Выборка не меньше 40 на группу — блоки стохастичны (см. #3184), на малых выборках разницы не увидеть. 3. Если разницы нет — вернуть блокировку ради скорости и закрыть вопрос измерением, а не догадкой. 4. Убрать `BROWSER_BLOCK_RESOURCES` из compose: мёртвая ручка, которая уже один раз сработает как ловушка. ## Приёмка - [ ] `block_images` управляем, для Авито выключен - [ ] A/B проведён, числа в тикете - [ ] Мёртвый `BROWSER_BLOCK_RESOURCES` убран из compose - [ ] `LeakWarning` в логе сайдкара больше не появляется (либо появляется осознанно, с `i_know_what_im_doing`) Оценка S. Refs #3177, #3184
bot-backend added the
bug
priority/p1
scope/devops
scrapers
tradein
labels 2026-08-28 17:42:15 +00:00
Author
Collaborator

Поправка к пункту 4 постановки. Я написал «убрать BROWSER_BLOCK_RESOURCES из compose». В compose её нет — проверено по всем трём tradein-mvp/docker-compose*.yml, grep пустой.

Переменная задаётся на сервере в .env.runtime, вне репозитория. То есть в git убирать нечего, это операция на хосте — и её надо делать отдельно, руками, а не PR'ом. Пока не сделана, ловушка остаётся: оператор увидит BROWSER_BLOCK_RESOURCES=true в окружении контейнера и решит, что ручка живая.

Переношу пункт в ops-хвост задачи, из приёмки кода убираю.

Что реально сделано в коде

  • _resolve_block_images(provider) по образцу соседней _resolve_min_interval: per-provider env → global env → код-дефолт.
  • Код-дефолт {"avito": False}, фолбэк Trueповедение cian/yandex/generic не меняется, их мы не измеряли.
  • Новые env: BROWSER_BLOCK_IMAGES (глобально) и BROWSER_BLOCK_IMAGES_{PROVIDER}.
  • Комментарий у опции переписан: раньше упоминал только выигрыш по скорости, теперь и цену — LeakWarning про детект на WAF, ~32% заглушек на Авито.
  • _on_startup логирует итоговую карту, симметрично page-intervals — чтобы значение было видно в логе, а не только в коде.
  • 6 тестов, весь файл сайдкара 35/35.

Оставшийся ops-хвост

  • Убрать мёртвую BROWSER_BLOCK_RESOURCES из .env.runtime на сервере
  • После деплоя убедиться, что LeakWarning для avito пропал из лога сайдкара
  • A/B на выборке ≥40 на группу (блоки идут пачками, см. #3184 — на малых выборках разницы не видно)
**Поправка к пункту 4 постановки.** Я написал «убрать `BROWSER_BLOCK_RESOURCES` из compose». В compose её нет — проверено по всем трём `tradein-mvp/docker-compose*.yml`, grep пустой. Переменная задаётся на сервере в `.env.runtime`, вне репозитория. То есть в git убирать нечего, это операция на хосте — и её надо делать отдельно, руками, а не PR'ом. Пока не сделана, ловушка остаётся: оператор увидит `BROWSER_BLOCK_RESOURCES=true` в окружении контейнера и решит, что ручка живая. Переношу пункт в ops-хвост задачи, из приёмки кода убираю. ## Что реально сделано в коде - `_resolve_block_images(provider)` по образцу соседней `_resolve_min_interval`: per-provider env → global env → код-дефолт. - Код-дефолт `{"avito": False}`, фолбэк `True` — **поведение cian/yandex/generic не меняется**, их мы не измеряли. - Новые env: `BROWSER_BLOCK_IMAGES` (глобально) и `BROWSER_BLOCK_IMAGES_{PROVIDER}`. - Комментарий у опции переписан: раньше упоминал только выигрыш по скорости, теперь и цену — `LeakWarning` про детект на WAF, ~32% заглушек на Авито. - `_on_startup` логирует итоговую карту, симметрично `page-intervals` — чтобы значение было видно в логе, а не только в коде. - 6 тестов, весь файл сайдкара 35/35. ## Оставшийся ops-хвост - [ ] Убрать мёртвую `BROWSER_BLOCK_RESOURCES` из `.env.runtime` на сервере - [ ] После деплоя убедиться, что `LeakWarning` для avito пропал из лога сайдкара - [ ] A/B на выборке ≥40 на группу (блоки идут пачками, см. #3184 — на малых выборках разницы не видно)
Author
Collaborator

Уточнение к формулировке в #3199: базы для сравнения не было

Смержил revert со словами «после правки прод стал заметно хуже». Посмотрел историю прогонов целиком — так говорить нельзя, и вот почему.

run время попыток обогащено блоков доля
5111 27.08 16:45 6 0 5 83%
5120 27.08 19:46 5 0 5 100%
5129 27.08 22:46 5 0 5 100%
5140 28.08 01:46 5 0 5 100%
5152 28.08 04:46 5 0 5 100%
5169 28.08 07:46 11 2 8 73%
5182 28.08 10:47 5 0 5 100%
5190 28.08 13:47 5 0 5 100%
5200 28.08 16:47 63 43 20 32%
5206 28.08 19:11 22 2 20 91%
5207 28.08 19:20 13 2 10 77%
5209 28.08 19:48 20 0 20 100%
5210 28.08 19:54 20 6 14 70%

Что здесь видно:

  1. Все прогоны до 5200 обрывались на пятом блоке — это старый критерий max_consecutive_blocks=5. Их «доля блоков» не характеристика площадки, а характеристика правила обрыва: прогон резали ровно там, где доля по построению близка к 100%. Сравнивать с ними нельзя.
  2. 5200 — первый прогон, доживший до 63 попыток (после мержа ratio-критерия #3188). Его 32% я и взял за базу. Это одно наблюдение, и по остальным данным оно скорее удачное, чем типичное: 5169 (11 попыток, дожил дальше пятёрки) дал 73%.
  3. 5209 испорчен деплоем: он стартовал в 19:48, а контейнер сайдкара пересоздавался в 19:51 — прямо посреди прогона. 20/20 там про рестарт, не про площадку.
  4. 5210 после отката — 70%, то есть между 5207 (77%) и ничем. Откат не вернул 32%.

Что из этого следует

Формулировка «прод стал хуже после #3185» не подтверждена: базы, относительно которой «хуже», у меня не было — до 5200 все прогоны были обрезаны на пятом блоке.

Само решение откатить при этом остаётся верным, но по другому основанию, и оно в PR названо честно: прямой A/B на сайдкаре разницы не показал (6/8 против 7/8), выгоды правка не показала ни разу, поэтому дефолт возвращается к прежнему поведению. Это довод «нет доказанной пользы», а не «доказан вред».

Что теперь непонятно и требует замера

Реальная доля блоков у avito detail неизвестна. Единственное длинное измерение — 5200. Чтобы получить базу, нужен ряд прогонов подряд при неизменных настройках; ratio-критерий это наконец позволяет (раньше все прогоны резались на пятом блоке и мерить было нечего).

До появления такого ряда любые выводы вида «стало лучше/хуже» на 1-2 прогонах — то же самое, что я уже дважды сделал неправильно в этой задаче.

## Уточнение к формулировке в #3199: базы для сравнения не было Смержил revert со словами «после правки прод стал заметно хуже». Посмотрел историю прогонов целиком — так говорить нельзя, и вот почему. | run | время | попыток | обогащено | блоков | доля | |---|---|---|---|---|---| | 5111 | 27.08 16:45 | 6 | 0 | 5 | 83% | | 5120 | 27.08 19:46 | 5 | 0 | 5 | 100% | | 5129 | 27.08 22:46 | 5 | 0 | 5 | 100% | | 5140 | 28.08 01:46 | 5 | 0 | 5 | 100% | | 5152 | 28.08 04:46 | 5 | 0 | 5 | 100% | | 5169 | 28.08 07:46 | 11 | 2 | 8 | 73% | | 5182 | 28.08 10:47 | 5 | 0 | 5 | 100% | | 5190 | 28.08 13:47 | 5 | 0 | 5 | 100% | | **5200** | 28.08 16:47 | **63** | **43** | 20 | **32%** | | 5206 | 28.08 19:11 | 22 | 2 | 20 | 91% | | 5207 | 28.08 19:20 | 13 | 2 | 10 | 77% | | 5209 | 28.08 19:48 | 20 | 0 | 20 | 100% | | 5210 | 28.08 19:54 | 20 | 6 | 14 | 70% | Что здесь видно: 1. **Все прогоны до 5200 обрывались на пятом блоке** — это старый критерий `max_consecutive_blocks=5`. Их «доля блоков» не характеристика площадки, а характеристика правила обрыва: прогон резали ровно там, где доля по построению близка к 100%. Сравнивать с ними нельзя. 2. **5200 — первый прогон, доживший до 63 попыток** (после мержа ratio-критерия #3188). Его 32% я и взял за базу. Это одно наблюдение, и по остальным данным оно скорее удачное, чем типичное: 5169 (11 попыток, дожил дальше пятёрки) дал 73%. 3. **5209 испорчен деплоем**: он стартовал в 19:48, а контейнер сайдкара пересоздавался в 19:51 — прямо посреди прогона. 20/20 там про рестарт, не про площадку. 4. **5210 после отката — 70%**, то есть между 5207 (77%) и ничем. Откат не вернул 32%. ## Что из этого следует Формулировка «прод стал хуже после #3185» **не подтверждена**: базы, относительно которой «хуже», у меня не было — до 5200 все прогоны были обрезаны на пятом блоке. Само решение откатить при этом остаётся верным, но по другому основанию, и оно в PR названо честно: прямой A/B на сайдкаре разницы не показал (6/8 против 7/8), выгоды правка не показала ни разу, поэтому дефолт возвращается к прежнему поведению. Это довод «нет доказанной пользы», а не «доказан вред». ## Что теперь непонятно и требует замера Реальная доля блоков у avito detail неизвестна. Единственное длинное измерение — 5200. Чтобы получить базу, нужен ряд прогонов подряд при неизменных настройках; ratio-критерий это наконец позволяет (раньше все прогоны резались на пятом блоке и мерить было нечего). До появления такого ряда любые выводы вида «стало лучше/хуже» на 1-2 прогонах — то же самое, что я уже дважды сделал неправильно в этой задаче.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3185
No description provided.