Сайдкар: якорь Домклика открывает свою выдачу напрямую, без захода через поиск Яндекса (#3263)

Выдача Яндекса капчит конкретные выходные узлы пула (замер владельца 29.08:
узлы 1/10/11 — капча, 9 и домашний IP — выдача), поэтому путь через поиск
срабатывал ~2 раза из 9 и стоил ~15 с на подъём якоря. В логах tradein-browser
15-16.09 все 7 попыток — капча, и все 7 через 0,2 с заканчивались «якорная
вкладка не поднялась (Error)». Referer карточке и так даёт переход с выдачи
площадки (detail.py: referer=origin).

Дефолт BROWSER_ANCHOR_VIA_SEARCH теперь пустой: путь через поиск остаётся,
но только по явному env. Тесты яндекс-пути включают его явно; новый тест
грузит модуль без env и проверяет, что якорь идёт прямым goto(origin).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
bot-backend 2026-09-17 12:53:04 +05:00
parent c871f804cf
commit 6c5f327acd
2 changed files with 44 additions and 11 deletions

View file

@ -107,10 +107,12 @@ Per-provider модель (#1793):
поиск yandex.ru, а не голым goto (#3251). Ручная сессия
29.08.2026 показала эталонный человеческий путь:
yandex.ru клик по результату выдача с Referer
yandex.ru. Дефолт "domclick" авито/циан/яндекс
проверяются отдельно в #3251, не включать здесь.
Пустая строка = выключено везде (полный откат к
прежнему поведению). Провайдер без соответствующего
yandex.ru. Дефолт пусто, выключено везде (#3263):
выдача Яндекса капчит конкретные выходные узлы пула,
и путь срабатывал ~2 раза из 9. Якорь поднимается
прямым goto на выдачу площадки, Referer карточке даёт
переход с неё. Включать только явным env и только
после замера на узлах пула. Провайдер без соответствующего
BROWSER_ANCHOR_SEARCH_QUERY_{PROVIDER} поиск тоже не
делает см. ниже.
BROWSER_ANCHOR_SEARCH_QUERY_{PROVIDER} поисковый запрос на yandex.ru для
@ -329,12 +331,15 @@ BROWSER_PAGE_INTERVAL_JITTER_S: float = float(
)
# Провайдеры, для которых якорная вкладка (#3251) заходит на origin ЧЕРЕЗ реальный
# поиск yandex.ru, а не голым goto. Дефолт "domclick" — авито/циан/яндекс проверяются
# отдельно (#3251), не расширять этот список без замера на них. Пустая строка env =
# выключено везде — полный откат на поведение до #3251.
# поиск yandex.ru, а не голым goto. Дефолт — пусто (#3263): капча на выдаче Яндекса —
# свойство выходного узла (замер владельца 29.08: узлы 1/10/11 — капча, 9 и домашний
# IP — выдача), в проде путь срабатывал ~2 из 9, а в логах 15-16.09 все 7 капч
# закончились «якорная вкладка не поднялась (Error)» через 0,2 с после отката — якоря
# не было вовсе. Без поиска якорь сразу открывает выдачу площадки, карточка идёт с
# referer=origin — переход внутри площадки. Включать только явным env после замера.
_ANCHOR_VIA_SEARCH_PROVIDERS: frozenset[str] = frozenset(
p.strip().lower()
for p in os.environ.get("BROWSER_ANCHOR_VIA_SEARCH", "domclick").split(",")
for p in os.environ.get("BROWSER_ANCHOR_VIA_SEARCH", "").split(",")
if p.strip()
)

View file

@ -34,9 +34,12 @@ _HOSTNAME = "ekaterinburg.domclick.ru"
@pytest.fixture(autouse=True)
def _reset_state() -> None:
def _reset_state(monkeypatch: pytest.MonkeyPatch) -> None:
server._contexts = {}
server._anchor_pages = {}
# Путь через поиск выключен по умолчанию (#3263) — тесты ниже проверяют его
# поведение при ЯВНОМ включении env'ом BROWSER_ANCHOR_VIA_SEARCH=domclick.
monkeypatch.setattr(server, "_ANCHOR_VIA_SEARCH_PROVIDERS", frozenset({"domclick"}))
class _FakeLink:
@ -158,7 +161,7 @@ def _run_ensure_anchor(provider: str, origin: str, page: _FakeAnchorPage) -> boo
def test_anchor_via_search_visits_yandex_and_clicks_result() -> None:
"""domclick включён по умолчанию: заход на yandex.ru → клик по ссылке на хост."""
"""domclick включён env'ом: заход на yandex.ru → клик по ссылке на хост."""
page = _FakeAnchorPage(link_host=_HOSTNAME)
anchored = _run_ensure_anchor("domclick", _ORIGIN, page)
@ -202,7 +205,7 @@ def test_no_link_in_serp_falls_back_without_referer() -> None:
def test_provider_not_in_allowlist_skips_search_entirely() -> None:
"""avito не в BROWSER_ANCHOR_VIA_SEARCH (дефолт только domclick) — поведение прежнее."""
"""avito не в BROWSER_ANCHOR_VIA_SEARCH (включён только domclick) — поведение прежнее."""
origin = "https://www.avito.ru/ekaterinburg/kvartiry"
page = _FakeAnchorPage(link_host="www.avito.ru")
@ -255,3 +258,28 @@ def test_new_tab_wrong_host_falls_back_without_referer() -> None:
assert origin_calls[0]["referer"] is None
assert page.opened_popup is not None
assert page.opened_popup.closed == 1, "попап не на том хосте должен быть закрыт"
def test_default_env_domclick_anchor_goes_straight_to_origin(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""#3263: без env якорь Домклика открывает свою выдачу прямым goto, yandex.ru не трогает.
Модуль грузится заново с удалённым env проверяется именно код-дефолт, а не
значение, подставленное фикстурой. Капча на выдаче Яндекса включена в подделке:
если путь через поиск снова станет дефолтом, goto на yandex.ru попадёт в
goto_calls и тест покраснеет.
"""
monkeypatch.delenv("BROWSER_ANCHOR_VIA_SEARCH", raising=False)
spec = importlib.util.spec_from_file_location("tradein_browser_server_anchor_default", _SERVER_PATH)
assert spec is not None and spec.loader is not None
fresh = importlib.util.module_from_spec(spec)
spec.loader.exec_module(fresh)
page = _FakeAnchorPage(link_host=_HOSTNAME, captcha=True)
fresh._contexts["domclick"] = _FakeAnchorContext(page)
anchored = asyncio.run(fresh._ensure_anchor_page("domclick", _ORIGIN))
assert anchored is True
assert fresh._anchor_pages["domclick"] is page
assert page.goto_calls == [{"url": _ORIGIN, "referer": None}]