tradein/domclick: площадка отдаёт одну карточку на экземпляр браузера — перезапускать camoufox после каждой страницы #3205

Closed
opened 2026-08-29 09:58:51 +00:00 by lekss361 · 0 comments
Owner

Что нашли

ДомКлик режет не IP, не сессию и не челлендж. Он отдаёт ровно одну карточку на экземпляр браузера, после чего любая следующая получает страницу отказа (401, ~26 625 байт). Прод годами собирал «примерно одну карточку за прогон» именно поэтому: один браузер на весь прогон — одна карточка.

Замеры (прод-сервер, 2026-08-29)

Три независимых запуска camoufox через прод-прокси, в каждом идём по карточкам до первого отказа:

--- запуск 1: браузер поднялся за 3.5 с ---
    карточка #1  http=200   len=  968674  OK
    карточка #2  http=401   len=   26625  ОТКАЗ
--- запуск 2: браузер поднялся за 0.6 с ---
    карточка #1  http=200   len= 1003055  OK
    карточка #2  http=401   len=   26625  ОТКАЗ
--- запуск 3: браузер поднялся за 0.6 с ---
    карточка #1  http=200   len= 1030764  OK
    карточка #2  http=401   len=   26625  ОТКАЗ

Прямой A/B на восьми карточках в каждом условии:

условие результат
свой браузер на каждую карточку 4 из 4 OK, все 200, ~1 МБ
один браузер на четыре карточки 1 из 4 (первая OK, дальше 401)
прямой выход с сервера, один браузер 1 из 8
через прод-прокси, один браузер 1 из 8

Цена перезапуска — 0.6 с (3.5 с только первый, холодный).

Что этим опровергнуто

Четыре гипотезы, каждая закрыта замером, а не рассуждением:

  • протухший qrator_jsid2 — деплой #3193 (тёплый переиспользуемый контекст) не изменил ничего: 1 OK / 9 блоков, как и до него;
  • camoufox не проходит JS-челлендж_wait_out_pow_challenge вызывается для всех провайдеров, а в сырой странице отказа челленджа нет вовсе;
  • выходим через забракованный узел пула — все четыре узла, включая резидентный, дают тот же 401;
  • виновата сохранённая сессия — 401 одинаково с 16 куками и полностью анонимно, свежий контекст на каждый запрос.

Отдельно: свежего контекста не хватает, нужен именно новый процесс. В контрольном замере каждая карточка бралась через browser.new_page() (новый изолированный контекст) — и всё равно отказ со второй. Признак, по которому нас узнают, живёт на уровне экземпляра браузера: camoufox генерирует новый отпечаток при запуске, а не при создании контекста. Значит reset_context из #3118 эту задачу не решает в принципе.

Что делать

  1. Дать ДомКлику собственный инстанс. Сейчас его нет в PROVIDERS (browser/server.py:168), и он проваливается в generic — то есть делит браузер и счётчик страниц с любым прочим трафиком. Добавить "domclick" в PROVIDERS и domclick.ru → domclick в _provider_for_url.
  2. Сделать порог перезапуска поставщик-зависимым. BROWSER_RECYCLE_PAGES сейчас глобальный, дефолт 15 (browser/server.py:130, сравнения на 1365/1528/1839). Ввести BROWSER_RECYCLE_PAGES_{PROVIDER} по образцу BROWSER_BLOCK_IMAGES_{PROVIDER} (#3185) и BROWSER_MIN_PAGE_INTERVAL_S_{PROVIDER}, код-дефолт для domclick — 1, для остальных прежние 15.

Порог 15 для Авито и Циана не трогаем: у них узор другой, и менять его без своего замера нельзя.

Ожидаемый эффект

domclick_detail_backfill перестаёт упираться в потолок «одна карточка за прогон». За 14 дней у него было 14 прогонов из 14 в banned при нуле обогащений; после правки ограничением станет темп, а не отпечаток браузера.

Смежное

  • #3197 — detail-путь ДомКлика обходит пул прокси (use_pool/proxy_provider остались дефолтами). На эту задачу не влияет: замеры показали, что прокси и прямой выход неразличимы, — но обход всё равно надо закрыть.
  • Диагноз блока теперь честный: #3202 научил сайдкар читать HTTP-статус, #3204 добавил 401 в отказы площадки для ДомКлика.
## Что нашли ДомКлик режет не IP, не сессию и не челлендж. Он отдаёт **ровно одну карточку на экземпляр браузера**, после чего любая следующая получает страницу отказа (401, ~26 625 байт). Прод годами собирал «примерно одну карточку за прогон» именно поэтому: один браузер на весь прогон — одна карточка. ## Замеры (прод-сервер, 2026-08-29) Три независимых запуска camoufox через прод-прокси, в каждом идём по карточкам до первого отказа: ``` --- запуск 1: браузер поднялся за 3.5 с --- карточка #1 http=200 len= 968674 OK карточка #2 http=401 len= 26625 ОТКАЗ --- запуск 2: браузер поднялся за 0.6 с --- карточка #1 http=200 len= 1003055 OK карточка #2 http=401 len= 26625 ОТКАЗ --- запуск 3: браузер поднялся за 0.6 с --- карточка #1 http=200 len= 1030764 OK карточка #2 http=401 len= 26625 ОТКАЗ ``` Прямой A/B на восьми карточках в каждом условии: | условие | результат | |---|---| | свой браузер на каждую карточку | **4 из 4** OK, все 200, ~1 МБ | | один браузер на четыре карточки | 1 из 4 (первая OK, дальше 401) | | прямой выход с сервера, один браузер | 1 из 8 | | через прод-прокси, один браузер | 1 из 8 | **Цена перезапуска — 0.6 с** (3.5 с только первый, холодный). ## Что этим опровергнуто Четыре гипотезы, каждая закрыта замером, а не рассуждением: - **протухший `qrator_jsid2`** — деплой #3193 (тёплый переиспользуемый контекст) не изменил ничего: 1 OK / 9 блоков, как и до него; - **camoufox не проходит JS-челлендж** — `_wait_out_pow_challenge` вызывается для всех провайдеров, а в сырой странице отказа челленджа нет вовсе; - **выходим через забракованный узел пула** — все четыре узла, включая резидентный, дают тот же 401; - **виновата сохранённая сессия** — 401 одинаково с 16 куками и полностью анонимно, свежий контекст на каждый запрос. Отдельно: **свежего контекста не хватает**, нужен именно новый процесс. В контрольном замере каждая карточка бралась через `browser.new_page()` (новый изолированный контекст) — и всё равно отказ со второй. Признак, по которому нас узнают, живёт на уровне экземпляра браузера: camoufox генерирует новый отпечаток при запуске, а не при создании контекста. Значит `reset_context` из #3118 эту задачу не решает в принципе. ## Что делать 1. **Дать ДомКлику собственный инстанс.** Сейчас его нет в `PROVIDERS` (`browser/server.py:168`), и он проваливается в `generic` — то есть делит браузер и счётчик страниц с любым прочим трафиком. Добавить `"domclick"` в `PROVIDERS` и `domclick.ru → domclick` в `_provider_for_url`. 2. **Сделать порог перезапуска поставщик-зависимым.** `BROWSER_RECYCLE_PAGES` сейчас глобальный, дефолт 15 (`browser/server.py:130`, сравнения на 1365/1528/1839). Ввести `BROWSER_RECYCLE_PAGES_{PROVIDER}` по образцу `BROWSER_BLOCK_IMAGES_{PROVIDER}` (#3185) и `BROWSER_MIN_PAGE_INTERVAL_S_{PROVIDER}`, код-дефолт для domclick — **1**, для остальных прежние 15. Порог 15 для Авито и Циана не трогаем: у них узор другой, и менять его без своего замера нельзя. ## Ожидаемый эффект `domclick_detail_backfill` перестаёт упираться в потолок «одна карточка за прогон». За 14 дней у него было 14 прогонов из 14 в `banned` при нуле обогащений; после правки ограничением станет темп, а не отпечаток браузера. ## Смежное - #3197 — detail-путь ДомКлика обходит пул прокси (`use_pool`/`proxy_provider` остались дефолтами). На эту задачу не влияет: замеры показали, что прокси и прямой выход неразличимы, — но обход всё равно надо закрыть. - Диагноз блока теперь честный: #3202 научил сайдкар читать HTTP-статус, #3204 добавил 401 в отказы площадки для ДомКлика.
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#3205
No description provided.