GMBSPYLAB собирает рекламу из FB Ad Library и раскладывает её по веткам в Telegram
Сборщик на Playwright и асинхронном Python забирает рекламу из FB Ad Library — открытой библиотеки объявлений Facebook. Самое интересное начинается после сбора: объявления приводятся к единому виду, повторы отсеиваются, дальше идут очереди и доставка. За день набирается 30–75 тыс. карточек по 30+ странам, и у каждой страны своя ветка в Telegram.
Зачем собирать рекламу самому
Платные сервисы, которые собирают рекламные библиотеки, стоят $300–800 в месяц. Мне нужны были свежие данные по 30+ странам, включая небольшие рынки Европы, Латинской Америки и Азии.
Официальный доступ к API Meta через приложение разработчика требует пройти проверку App Review. Для небольшой команды это недели ожидания ради данных, которые и так открыты всем. При этом страница facebook.com/ads/library собирается прямо в браузере, поэтому простой запрос HTML возвращает пустую страницу.
Цель — самостоятельно собирать свежий поток рекламы из 30+ стран в свою базу: с фильтром по формату (картинка, видео, веб-приложение PWA) и по сроку показа, с единой системой меток и публикацией в Telegram.
Система состоит из четырёх частей
Браузер открывает страницу один раз, дальше сбор идёт по данным
Страница библиотеки собирается прямо в браузере. Поэтому Chromium без окна открывает её один раз, а дальше сбор идёт по тем же данным, которые получает сам браузер, и не тратит время на разбор вёрстки. Разбирать HTML каждой карточки заметно дольше.
Запросы идут в обычном пользовательском темпе. За каждым рынком закреплены свои сессии, запрос уходит не чаще одного раза в 2,5 с, и у каждой сессии есть жёсткий потолок. Задача — чтобы поток был предсказуемым и его хватало на суточный объём.
Сбор переживает изменения на стороне источника
Источник живой: разметка и параметры выдачи часто меняются, и простой сборщик после такого изменения молча отдаёт нули. Здесь формат ответа проверяется на каждом шаге. При расхождении сессия запускается заново, и поток не прерывается. Если источник отвечает ошибкой или медленно, сессия уходит в паузу, которая растёт с каждой попыткой (экспоненциальная задержка), и потом возвращается сама. За сутки такое случается десятки раз, и обычно моё участие не требуется.
База на Postgres 16, очередь arq и хранилище для картинок и видео
База работает через SQLAlchemy 2 async и asyncpg, схема меняется миграциями alembic, индексы построены по рекламодателю, стране и дате первого появления. arq через Redis выполняет фоновые задачи: загрузку файлов и отсев повторов. Картинки и видео уходят в MinIO / R2 через aioboto3. Повторы отсеиваются по перцептивному хешу изображения — отпечатку, который совпадает у визуально одинаковых картинок: из 30–75 тыс. собранных за день остаётся 5–12 тыс. уникальных.
Два формата ленты в Telegram, бот на aiogram 3
Первый вариант — группа с темами: для каждой из 30+ стран создаётся своя тема
(createForumTopic), и ленту удобно смотреть по рынку. Это 27 стран ЕС, Великобритания, Бразилия, Танзания, Мексика, Индия, Канада, ЮАР, Сербия и другие.
Второй вариант — канал с хештегами: общий поток и метки
#GEO #PWA #VIDEO #1DAY #FBPAGE.
Задача по расписанию каждый день обновляет метку #NDAY,
и видно, сколько дней объявление уже показывается.
На чём это работает
- Playwright (Chromium без окна)
- Пул сессий, закреплённых за рынками
- Ограничение частоты запросов и растущие паузы при ошибках
- Проверка формата ответа на каждом шаге
- Python 3.12 + uv (менеджер пакетов)
- SQLAlchemy 2 async + asyncpg
- PostgreSQL 16 и миграции alembic
- Pydantic v2 для всех схем данных
- arq + Redis 7 (фоновые задачи)
- APScheduler (запуск по расписанию)
- MinIO / Cloudflare R2 (aioboto3)
- SQLite (кэш и локальное состояние)
- aiogram 3 (Bot API)
- Группа с темами: ветка на каждую страну
- Канал с хештегами и ежедневное обновление счётчика дней
- Проверка состояния и оповещения в Discord и Telegram
- Playwright и FB Ad Library (основной источник)
- ScrapeCreators (платный запасной источник вне ЕС)
- Meta Graph API (для подтверждённых идентификаторов)
- Реестр EU DSA (данные, которые раскрываются по регламенту ЕС)
- structlog (структурированные журналы)
- 16 из 16 тестов проходят (pytest)
- Проверка состояния и аварийная остановка
- Вебхуки Discord для статусов
Что в итоге
после отсева повторов остаётся 5–12 тыс. уникальных
27 стран ЕС, Великобритания, Бразилия, Мексика, Индия и другие рынки
в месяц на сервер и хранилище
Где это пригодится клиентам: та же схема (сбор → единый вид → отсев повторов → доставка) переносится на другие источники, к которым у клиента есть законный доступ: свой кабинет на Avito, в WB Seller или Ozon Seller, официальные выгрузки, открытые рекламные библиотеки. На созвоне разберём конкретный источник и то, что разрешают правила площадки.
Похожие кейсы
Сквозная атрибуция для двух магазинов на Shopify: от клика до заказа
Свой сервис на стандартной библиотеке Python принимает уведомления Shopify о заказах и проверяет их подпись…
Заказы из Shopify сами встают в рабочие таблицы склада
Номера заказов, трек-номера, статусы и отмены проставляются каждые 30 минут. Приёмник на Apps Script…
Обмен файлами с партнёром по отгрузке: стоимость и трек-номера сами встают в таблицу
Дневной файл собирается сам и выглядит так же, как рабочая таблица, вместе с раскраской строк. Ответ партнёра…
Начните с аудита за 5 000 ₽: письменный отчёт и расчёт окупаемости
Расскажу, что автоматизировать в первую очередь, когда это окупится и нужен ли вашей задаче ИИ вообще. Иногда он не нужен.
Или просто задайте вопрос. В рабочее время отвечаю в течение 2 часов