Files
portal/bots/yandex-creatives
Дмитрий f2bfe3f1da fix реклама Яндекса: пять поломок, которые вскрыл первый живой запуск связки портал-робот-кабинет
Ни одну нельзя было увидеть без настоящего прогона: часть закрыта песочницей Яндекса,
часть — швами между кусками, которые по отдельности покрыты тестами.

1. Слепок креативов уходил с SelectionCriteria пустым МАССИВОМ. Живой Яндекс отвечает
   отказом 8000 «SelectionCriteria cannot contain an array», портал не может снять слепок,
   задание роботу не выдаётся, клиент видит вечное «готовим картинки». В JSON нужен пустой
   ОБЪЕКТ. Песочница до этой проверки не доходила — отвергала запрос раньше, на входе.

2. Отказы Яндекса ПО ПОЗИЦИИ внутри ответа глотались молча. Запрос успешен, а нужного Id
   в позиции нет — вместо него Errors с человеческим объяснением. Портал падал ошибкой PHP
   «Undefined array key Id», ни клиенту, ни в журнал не попадало ни слова из ответа Яндекса.
   Теперь слова Яндекса выходят наружу — именно это и позволило найти пункт 3.

3. В условии ретаргетинга не передавался MembershipLifeSpan — срок хранения человека
   в сегменте. Живой Яндекс отказывает «Required field: Not specified time for goal or
   segment», и следом «Object not found»: довод негоден целиком, запуск встаёт. Берём
   audience_days кампании, границы Яндекса 1..540.

4. Робот не отдавал набор Яндексу: заливал файлы, нажимал «Создать» и уходил. Оказалось,
   «набор» в кабинете и «креатив» в creatives.get — разные вещи: пока набор не отмечен
   галочкой и не нажато «Добавить выбранные», Яндекс креативы не регистрирует. Замер:
   14 залитых картинок были невидимы для creatives.get, после добавления в ЧЕРНОВИК формы
   счётчик прыгнул 18 -> 32 в ту же секунду. Объявление при этом не сохраняется,
   «Сохранить изменения» робот по-прежнему не трогает никогда.

5. Гонка при заливке. Три живых прогона подряд из 15 картинок доносили 14, и каждый раз
   пропадала ДРУГАЯ: 480x320, потом 300x600, потом 336x280. Замер объяснил: кнопка
   «Создать» разблокируется на 4-й секунде, когда принято 11 файлов из 15, остальные
   дозагружаются к 7-й. Робот жал сразу по разблокировке. Ждём теперь по строкам принятых
   файлов и по исчезновению слова «Загружается».

   Первая попытка этой починки НЕ РАБОТАЛА и выглядела рабочей: сторож считал размеры
   в окне, не заметив постоянного фильтра из тех же 15 размеров вверху. Поймано по тому,
   что прогон занял ровно столько же секунд, сколько до починки. Отсюда тире в признаке
   приёма — фильтр его не содержит.

Каждая починка закрыта тестом, который сначала падал на своей поломке. Прежние тесты
проверяли разбор ОТВЕТОВ и путь ДО «Создать» — форму запросов и то, что после, не смотрел
никто. Робот 84 из 84, реклама портала 42 из 42.

Проверено живьём на боевом: задание роботу отработало со статусом done, опознано
15 креативов из 15.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 07:14:33 +03:00
..

Робот-грузчик креативов в кабинет Яндекс Директа

Зачем он нужен

Портал заводит рекламную кампанию «за показы» в Яндексе целиком через программный интерфейс — кроме одного шага. Картиночный креатив через него создать нельзя: приём creatives.add принимает только видео, а конструктор креативов Яндекс закрыл 01.06.2026. Остался единственный путь — загрузить готовые файлы руками в веб-кабинете.

Этот робот и есть «руки»: он относит готовые файлы клиента в кабинет и говорит порталу «готово». Всё остальное портал делает сам.

Что робот делает

  1. Спрашивает у портала, есть ли работа.
  2. Скачивает файлы баннеров.
  3. Открывает кабинет в своём браузере и проверяет, жив ли вход.
  4. Загружает файлы через «Загрузить креативы».
  5. Отчитывается порталу и чистит за собой скачанные картинки.

Чего робот НЕ делает

  • Не создаёт кампаний и не запускает показы.
  • Не тратит деньги — он вообще не может: таких действий у него нет.
  • Не читает номера созданных креативов — их портал добывает сам, сравнивая список креативов кабинета до и после загрузки.
  • Не нажимает «Сохранить изменения» — единственную кнопку, которая меняет кабинет. На это есть отдельный тест-сторож.

При любом сбое робот останавливается, отчитывается порталу «сбой» и шлёт письмо со снимком экрана. Кампания при этом остаётся черновиком.

Настройка

Скопировать .env.example в .env и заполнить. Отдельного пояснения стоят:

  • YC_CABINET_LOGIN — логин рекламного кабинета.
  • YC_ANTEROOM_CAMPAIGN_ID и YC_ANTEROOM_GROUP_ID«прихожая»: существующие кампания и группа, форму нового объявления которых робот открывает только чтобы добраться до окна загрузки. Ничего в них не сохраняется. Своей кампании у робота в этот момент ещё нет: портал ставит задание до создания кампании в Яндексе, потому что кампания заводится сразу с готовыми номерами креативов. Надёжнее всего назначить прихожей отдельную остановленную кампанию — тогда робот не приближается к работающей рекламе вовсе.

Как завести вход в кабинет

Вход заводится один раз глазами и дальше живёт в папке профиля браузера:

npm run login

На боевом сервере экрана нет, поэтому команда запускается внутри виртуального рабочего стола, к которому подключаются по удалённому рабочему столу через SSH-туннель. Наружу порт не открывается. Владелец вводит пароль и код из СМС — профиль сохраняется на диск.

Как запускать

npm run run:once    # один проход: взять задание, если оно есть
npm run keepalive   # тихо зайти в кабинет, чтобы вход не заснул
npm test            # проверки, браузер не нужен

По расписанию: run:once — часто, keepalive — раз в ~15 минут.

Наложиться друг на друга они не могут: браузерный профиль один, и оба запуска берут общий файл-замок robot.lock в папке робота. Занят замок — процесс молча уходит с кодом 0 и пробует в следующий раз; задание при этом остаётся в очереди. Замок, брошенный убитым процессом (перезагрузка сервера), перехватывается через полчаса.

Снимки экрана в папке screenshots/ робот убирает сам: старше двух недель — удаляет при очередном запуске. Свежие нужны, чтобы разобрать вчерашний сбой; лежать вечно им нельзя — на снимке видна боковая панель кабинета с логином и остатком счёта.

Пришло письмо-алярм — что делать

В письме указан шаг, на котором робот встал, и приложен снимок экрана.

  • «Вход в кабинет слетел» — зайти по удалённому рабочему столу и выполнить npm run login.
  • «Кабинет не принял файлы» — посмотреть снимок: скорее всего, файл не тех размеров или слишком тяжёлый.
  • «Окно загрузки не закрылось» — в письме будет текст, который показал сам кабинет. Задание при этом закрыто как выполненное: правду об успехе знает портал, он сверяет список креативов до и после. Если креативы не появились, портал сам пометит задание сбойным.

🔑 Смотрите на концовку письма — она честно говорит, что происходило в кабинете:

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

Где почитать подробности

  • Разметка экранов кабинета, снятая живьём — docs/cabinet-flow.md.
  • Замысел целиком — docs/superpowers/specs/2026-07-27-yandex-creative-robot-design.md.
  • Почему конструктор закрыт — docs/superpowers/findings/2026-07-27-yandex-konstruktor-zakryt/.