AI-самопочинка селекторов: почему при обновлении интерфейса WB наш сервис не ложится

WB перерисовал кнопку «В корзину» — и пол-рынка сервисов автоматизации легло до ближайшего релиза.

Так бывает каждый раз, когда Wildberries меняет вёрстку: переехала кнопка, переименовали класс — и робот больше не находит, куда жать.

У нас иначе. Self-healing селекторов — это когда сервис сам ловит сломанный селектор и переписывает его без инженера и без релиза: фоновый watchdog раз в 30 минут гоняет сценарий на тестовом профиле, ловит поломку (селектор — правило, по которому код находит элемент на странице), отдаёт фрагмент HTML в LLM и записывает рабочий XPath в базу. Сервис чинит себя сам. Это и есть та самая надёжность самовыкупов, ради которой всё затевалось.

Дальше — как это устроено внутри. И почему «у конкурентов лежит, а у нас нет» — это не лозунг, а архитектура.

Что вообще ломается, когда WB меняет интерфейс?

Автоматизация выкупа — это робот, который проходит путь живого человека: логин, поиск товара по запросу, добавление в корзину, оформление. Каждый шаг привязан к конкретным элементам страницы через селекторы (XPath или CSS — адрес элемента в дереве HTML).

WB не присылает писем «мы тут поменяли вёрстку, готовьтесь». Выкатили новый A/B, переименовали класс, переехала кнопка — и селектор //button[@data-link='basket'] ловит пустоту. Код кидает SelectorNotFoundError, сценарий обрывается на полпути.

У классической реализации сценарий один:

  • утром выкатили новый UI на WB;
  • сервис начал валить задачи пачками;
  • кто-то из пользователей пишет в поддержку «не работает»;
  • инженер чинит селектор руками, гоняет тесты, катит релиз;
  • от обнаружения до фикса — от пары часов до суток.

Всё это время выкупы стоят. А для серой механики простой — это не только потерянные часы. Это сбитый ритм: антифрод WB смотрит на ~200+ параметров поведения, и рваный график ему не нравится.

Как работает self-healing селекторов в Toptaker?

Коротко: selector-watchdog.ts каждые 30 минут проверяет здоровье сценариев на отдельном профиле, и при поломке зовёт LLM сгенерить новый селектор. Подробно — по шагам.

1. Standalone-функции на Base Test профиле. Watchdog не трогает боевые задачи живых пользователей. Он гоняет три изолированные функции — verifyAuth, searchProduct, addToCart — на выделенном профиле Base Test. Это синтетический прогон ключевого пути: авторизация, поиск, корзина. Если эти три шага живы — жив весь конвейер.

2. Ловим SelectorNotFoundError. Любой шаг не нашёл элемент — кидается типизированная ошибка с тем самым проблемным селектором и куском DOM вокруг него. Не «что-то упало», а «вот этот селектор на этой странице больше не существует».

3. Зовём DeepSeek с фрагментом HTML. Watchdog вырезает релевантный кусок текущего HTML (не всю страницу — только окрестность, где раньше жил элемент) и отдаёт его в DeepSeek (LLM) с задачей: вот разметка, вот что мы искали, верни XPath-кандидаты на этот элемент в новой вёрстке.

4. Сохраняем override в БД. LLM возвращает кандидатов, watchdog их прогоняет на той же странице, рабочий — пишет в базу как override (переопределение базового селектора). Дальше боевые сценарии берут селектор из базы, а не из захардкоженного кода.

Итог: цикл «сломалось → починилось» проходит внутри получаса и без участия человека. Релиз не нужен — фикс живёт в данных, а не в коде.

Почему LLM, а не просто запасные селекторы?

Список фолбэков (button.basket, потом [data-link=basket], потом ещё пять вариантов) работает, пока WB меняет вёрстку предсказуемо. Но когда кнопку реально переименовали и переложили, перебор заранее заготовленных вариантов так же мёртв, как и основной — все они написаны под старую разметку.

LLM смотрит на актуальный HTML, которого никто заранее не видел, и строит селектор прямо под него.

Разница как между связкой запасных ключей от старого замка и слесарём, который смотрит на новый замок. Замок поменяли — ключи в мусорку, а слесарь просто работает.

При этом мы не отдаём в LLM ничего лишнего: только фрагмент публичной разметки страницы. Логику обхода антифрода, ключи, профили — это в промпт не уходит.

Чем это отличается от конкурентов на уровне кода?

Отстройка здесь не в лозунге «надёжно», а в конкретных инженерных решениях. Тот же подход у нас по всему стеку.

  • Сетевой слой. У многих сервисов запросы летят через Node fetch — TLS-fingerprint (отпечаток рукопожатия TLS, по которому сервер вычисляет нестандартного клиента) выдаёт «не браузер» сразу. Мы держим TLS-пресет под реальный мобильный клиент, чтобы рукопожатие выглядело как настоящее приложение. Подробно про это — в имитации мобильного приложения WB.
  • Подпись запросов. WB подписывает часть запросов челленджем X-Pow (proof-of-work заголовок — клиент должен посчитать задачку, прежде чем сервер примет запрос). Самопал на голом fetch его не считает и отлетает.
  • Реакция на смену UI. У них «обновили WB UI → сервис лежит до прод-релиза». У нас watchdog ловит поломку за ≤30 минут и чинит без релиза.

Это три разных уровня, но логика одна: не делать вид, что мы браузер и человек, а технически быть неотличимым — и не падать, когда площадка дёргается. Полная карта отличий — в чём Toptaker отличается.

Это даёт «100% безопасность»?

Нет. И врать про это не буду.

Самовыкупы — серая зона. Антифрод WB ловит накрутку по ~200+ параметрам с точностью около 98%, а за палево снимают СПП (скидку постоянного покупателя) на 30 дней по всему ассортименту. Это бьёт по обороту жёстко.

Self-healing убирает один конкретный класс рисков — технический простой и рваный ритм из-за сломанной вёрстки. Поведенческую естественность держат другие слои. Честная планка по живучести профиля — до 95%, а не «гарантия».

Кто продаёт гарантию на серой механике — либо не понимает, как работает антифрод, либо просто врёт тебе в лицо.

FAQ

Что такое self-healing селекторов? Механизм, при котором сервис сам находит новый селектор сломавшегося элемента: фоновый процесс ловит SelectorNotFoundError, отдаёт фрагмент HTML в LLM (DeepSeek), получает рабочий XPath и сохраняет его в базе. Без правки кода и релиза.

Как часто проверяются сценарии? Каждые 30 минут. selector-watchdog.ts прогоняет verifyAuth, searchProduct и addToCart на отдельном профиле Base Test, не трогая боевые задачи пользователей.

Сколько времени сервис простаивает после обновления интерфейса WB? В типовом случае — до 30 минут, до ближайшего прогона watchdog, который и поднимет фикс. У сервисов с ручной починкой простой тянется до прод-релиза: часы или сутки.

Зачем LLM, если можно прописать запасные селекторы? Запасные селекторы написаны под старую разметку и умирают вместе с основным при серьёзной смене вёрстки. LLM строит селектор под актуальный HTML, которого заранее никто не видел.

Повышает ли это безопасность самовыкупа? Снимает технический риск простоя и рваного ритма, но не делает механику «безопасной». Самовыкупы — серая зона, антифрод WB работает на ~98% по 200+ параметрам. Реалистичная планка по живучести — до 95%.


Хочешь увидеть, как это держит ритм на твоих товарах без простоя на каждом чихе WB — заведи тестовый выкуп в Toptaker и понаблюдай сам.

Конкуренты ночью чинят селекторы руками. Мы в это время спим — код чинится без нас.

Хотите так же — но без ручной возни?

Toptaker делает выкупы и отзывы автоматически: SRID, чеки и скриншоты по каждому действию. 5 выкупов бесплатно при регистрации.