Files
portal/bots/yandex-creatives
Дмитрий af12b1ceb4 fix реклама за показы: предел веса картинки проверен по-настоящему, обход модерации не срывается целиком, робот не несёт токен на чужой адрес
Мелочи приёмочного листа v12 §8. Каждая правка с тестом; где защита уже стояла
в коде — тест проверен вырезанием этой защиты.

Предел веса картинки. Две прежние проверки были пустышками: сравнивали константу
саму с собой и с тем же числом в ответе сервера. Вырезание правила max: оставляло
обе зелёными. Настоящий тест грузит перевес и ждёт отказа — это четвёртая найденная
пустышка за ветку.

Обход модерации. Объявление без статуса и причина отказа длиннее колонки роняли
запись в базу ВНЕ защиты, и обход обрывался на середине: остальные клиенты не узнавали,
приняли их рекламу или отклонили, а деньги за отклонённый набор не возвращались.
Запись ответа теперь под той же защитой, что и сеть; пустой статус не пишем вовсе,
причину храним обрезанной.

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

Ещё: порядок посредников служебного канала — токен раньше служебного соединения;
BannerGenerator больше не отдаёт молча файл тяжелее предела и берёт предел из общей
константы; нулевой номер креатива ловится намеренно, а не случайно нестрогим сравнением.

Портал 300/300, робот 60/60. Мест снятия заморозки денег по-прежнему четыре.

Не тронуто намеренно: цена за 1000 показов и бюджет приходят от клиента — но это
видимое поле мастера и принятое продуктовое решение, а не недосмотр. Решает владелец.
2026-07-28 07:21:02 +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/.