Сайдкар: якорь Домклика открывает свою выдачу напрямую, без захода через поиск Яндекса (#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:
parent
c871f804cf
commit
6c5f327acd
2 changed files with 44 additions and 11 deletions
|
|
@ -107,10 +107,12 @@ Per-provider модель (#1793):
|
||||||
поиск yandex.ru, а не голым goto (#3251). Ручная сессия
|
поиск yandex.ru, а не голым goto (#3251). Ручная сессия
|
||||||
29.08.2026 показала эталонный человеческий путь:
|
29.08.2026 показала эталонный человеческий путь:
|
||||||
yandex.ru → клик по результату → выдача с Referer
|
yandex.ru → клик по результату → выдача с Referer
|
||||||
yandex.ru. Дефолт "domclick" — авито/циан/яндекс
|
yandex.ru. Дефолт — пусто, выключено везде (#3263):
|
||||||
проверяются отдельно в #3251, не включать здесь.
|
выдача Яндекса капчит конкретные выходные узлы пула,
|
||||||
Пустая строка = выключено везде (полный откат к
|
и путь срабатывал ~2 раза из 9. Якорь поднимается
|
||||||
прежнему поведению). Провайдер без соответствующего
|
прямым goto на выдачу площадки, Referer карточке даёт
|
||||||
|
переход с неё. Включать только явным env и только
|
||||||
|
после замера на узлах пула. Провайдер без соответствующего
|
||||||
BROWSER_ANCHOR_SEARCH_QUERY_{PROVIDER} поиск тоже не
|
BROWSER_ANCHOR_SEARCH_QUERY_{PROVIDER} поиск тоже не
|
||||||
делает — см. ниже.
|
делает — см. ниже.
|
||||||
BROWSER_ANCHOR_SEARCH_QUERY_{PROVIDER} — поисковый запрос на yandex.ru для
|
BROWSER_ANCHOR_SEARCH_QUERY_{PROVIDER} — поисковый запрос на yandex.ru для
|
||||||
|
|
@ -329,12 +331,15 @@ BROWSER_PAGE_INTERVAL_JITTER_S: float = float(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Провайдеры, для которых якорная вкладка (#3251) заходит на origin ЧЕРЕЗ реальный
|
# Провайдеры, для которых якорная вкладка (#3251) заходит на origin ЧЕРЕЗ реальный
|
||||||
# поиск yandex.ru, а не голым goto. Дефолт "domclick" — авито/циан/яндекс проверяются
|
# поиск yandex.ru, а не голым goto. Дефолт — пусто (#3263): капча на выдаче Яндекса —
|
||||||
# отдельно (#3251), не расширять этот список без замера на них. Пустая строка env =
|
# свойство выходного узла (замер владельца 29.08: узлы 1/10/11 — капча, 9 и домашний
|
||||||
# выключено везде — полный откат на поведение до #3251.
|
# IP — выдача), в проде путь срабатывал ~2 из 9, а в логах 15-16.09 все 7 капч
|
||||||
|
# закончились «якорная вкладка не поднялась (Error)» через 0,2 с после отката — якоря
|
||||||
|
# не было вовсе. Без поиска якорь сразу открывает выдачу площадки, карточка идёт с
|
||||||
|
# referer=origin — переход внутри площадки. Включать только явным env после замера.
|
||||||
_ANCHOR_VIA_SEARCH_PROVIDERS: frozenset[str] = frozenset(
|
_ANCHOR_VIA_SEARCH_PROVIDERS: frozenset[str] = frozenset(
|
||||||
p.strip().lower()
|
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()
|
if p.strip()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,12 @@ _HOSTNAME = "ekaterinburg.domclick.ru"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def _reset_state() -> None:
|
def _reset_state(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
server._contexts = {}
|
server._contexts = {}
|
||||||
server._anchor_pages = {}
|
server._anchor_pages = {}
|
||||||
|
# Путь через поиск выключен по умолчанию (#3263) — тесты ниже проверяют его
|
||||||
|
# поведение при ЯВНОМ включении env'ом BROWSER_ANCHOR_VIA_SEARCH=domclick.
|
||||||
|
monkeypatch.setattr(server, "_ANCHOR_VIA_SEARCH_PROVIDERS", frozenset({"domclick"}))
|
||||||
|
|
||||||
|
|
||||||
class _FakeLink:
|
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:
|
def test_anchor_via_search_visits_yandex_and_clicks_result() -> None:
|
||||||
"""domclick включён по умолчанию: заход на yandex.ru → клик по ссылке на хост."""
|
"""domclick включён env'ом: заход на yandex.ru → клик по ссылке на хост."""
|
||||||
page = _FakeAnchorPage(link_host=_HOSTNAME)
|
page = _FakeAnchorPage(link_host=_HOSTNAME)
|
||||||
|
|
||||||
anchored = _run_ensure_anchor("domclick", _ORIGIN, page)
|
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:
|
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"
|
origin = "https://www.avito.ru/ekaterinburg/kvartiry"
|
||||||
page = _FakeAnchorPage(link_host="www.avito.ru")
|
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 origin_calls[0]["referer"] is None
|
||||||
assert page.opened_popup is not None
|
assert page.opened_popup is not None
|
||||||
assert page.opened_popup.closed == 1, "попап не на том хосте должен быть закрыт"
|
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}]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue