Как я с командой строил внутреннюю платформу конкурентной аналитики

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Привет, Хабр! На связи Владимир Михайлов, Marketing Analyst в Garage Eight. Сегодня хочу поговорить с вами о сервисах конкурентной аналитики. Почти каждая маркетинговая команда пользуется Sensor Tower, AppMagic, Similarweb и не только. Я не исключение. На одном из проектов я как раз работал с таким сервисом и спустя несколько месяцев понял простую вещь: использование аналитической платформы вовсе не означает наличие удобной аналитики.

В статье хочу обсудить, почему так происходит, и поделиться историей о том, как родился проект, в котором я превратил Sensor Tower из инструмента аналитики в источник данных.

Как обычно строились исследования

В команде, где я тогда работал, аналитику всегда собирали примерно одинаково:

Открыть Sensor Tower → Найти приложение → Выбрать страну → Выбрать период → Посмотреть креативы → Переключиться на следующего конкурента → Повторить то же самое еще 15 раз

Одно дело, когда нужно таким образом разово собрать топ креативов конкурентов по показателю Impression Share. Но анализировать рынок нужно регулярно, поэтому одна задача превращается в десятки похожих — работа становится рутиной и в итоге съедает много времени.

Кроме этого, я столкнулся еще с несколькими ограничениями:

  • Лицензий всегда меньше, чем сотрудников, и полный доступ есть только у части команды.

  • Sensor Tower хорошо показывает данные: например, может четко ответить на вопрос «Какие новые видео залетели у конкурентов на прошлой неделе?». Но если нужно разобраться в причинно-следственных связях и понять, почему одни видео зашли аудитории, а другие — нет, ответ вы не получите.

  • AI нельзя встроить внутрь Sensor Tower. Чтобы модель могла анализировать рынок, данные сначала нужно подготовить, агрегировать и объединить с другими источниками.

Так я понял: Sensor Tower должен стать источником данных, а не инструментом, который закрывает базовые аналитические задачи.

Как решили выстроить работу

На том проекте была гипотеза: мы считали, что часть регулярного анализа конкурентов можно автоматизировать — убрать ручной поиск и фильтрацию в Sensor Tower и отдавать маркетологу уже готовую аналитику прямо в Slack. Решили сделать MVP на одном конкретном кейсе (мониторинге рекламных креативов) и проверить, насколько такой формат будет полезен. 

Мы сознательно не пытались сразу построить полноценную аналитическую платформу. Цель была гораздо скромнее: каждое утро автоматически получать данные, сохранять их в собственном хранилище, формировать аналитический отчет и публиковать его в Slack.

Получилась такая архитектура:

Sensor Tower API

        │

        ▼

Python ETL

        │

        ▼

Transformation Layer

        │

        ▼

BigQuery

        │

        ▼

Slack Bot

Так как это MVP, AI в этой схеме пока отсутствует. Вместо этого мы решили сконцентрироваться на каждом элементе архитектуры, чтобы заложить фундамент для следующих надстроек.

Почему API, а не интерфейс Sensor Tower

Быстро выяснилось, что даже простые операции постоянно повторяются. Каждый раз приходится выбирать нужный регион, период, искать приложение и экспортировать результаты. И суть даже не в том, что это долго, а в том, что эти действия всегда одинаковые — так почему их просто не автоматизировать?

Хотелось вообще перестать открывать Sensor Tower. Практически всё, что отображается в интерфейсе, доступно через API, а значит, всю эту работу можно переложить на ETL. Так мы вытаскиваем данные из источника, преобразуем их в удобный вид и загружаем в хранилище.

Готово — Sensor Tower превращается в обычный источник данных. Но здесь важно разобрать подробнее несколько наших решений.

Архитектура ETL

Первое решение было архитектурным. Я не хотел писать один большой Python-файл: он очень быстро превратился бы в кашу — в нём смешивались бы запросы к API, обработка данных, загрузка в хранилище и логика отчетов. Читать это через месяц было бы просто невозможно, а менять — страшно. Именно поэтому я сразу разделил проект на несколько независимых компонентов:

  • config/ хранит настройки: какие приложения загружаем, каких стран и за какой период;

  • sensor_tower_client.py отвечает только за общение с API;

  • transformer.py берет этот сырой ответ и превращает его в аккуратную таблицу;

  • bigquery_loader.py берет готовую таблицу и сохраняет ее в BigQuery;

  • main.py — точка входа, которая по очереди запускает все шаги.

Каждый модуль отвечает только за одну задачу. Это важно, потому что, если что-то сломается, сразу понятно, где искать проблему, и, если нужно что-то поменять, можно исправить только один модуль, не трогая остальные.

SensorTowerClient

Сам клиент оказался удивительно небольшим:

class SensorTowerClient:

    BASE_URL = "https://api.sensortower.com/v1"

    def get_creatives(...):

        response = requests.get(...)

        response.raise_for_status()

        return response.json()

То есть он обращается по адресу API, отправляет запрос с нужными параметрами, проверяет, что ответ успешный, и возвращает результат в виде JSON. Всё. Именно так это и должно выглядеть — без DataFrame, без SQL, без BigQuery. Только HTTP.

Клиент не должен знать, что будет с данными дальше. Его задача — просто получить их и отдать. За остальное отвечают другие модули. 

Какие сложности возникли

Оказалось, что вызов API — это примерно 20% всей работы, остальные 80% — инженерия вокруг него.

Лимиты API

При загрузке десятков приложений по нескольким регионам очень быстро начинаешь сталкиваться с ограничениями.

Пришлось добавить:

  • retry, чтобы при неудачном запросе система автоматически отправляла его повторно;

  • exponential backoff, чтобы между попытками были паузы и с каждой новой попыткой они увеличивались — так мы даем серверу время восстановиться;

  • обработку HTTP 429, чтобы считывать специальный код ошибки, который говорит о большом количестве запросов;

  • журналирование ошибок, чтобы потом можно было посмотреть, что именно сломалось и когда.

Без этого ночной ETL иногда завершался ошибкой: данные просто не загружались, и утром отчет приходил пустой или не приходил вовсе. Пришлось потратить время, чтобы сделать систему устойчивой.

Конфигурация

Сначала список приложений выглядел так:

apps = [

    "Company 1",

    "Company 2",

    "Company 3"

]

Через несколько недель компаний стало больше пятнадцати, и было очевидно, что менять Python-код при каждом новом конкуренте — плохая идея.

Появился обычный справочник:

| Company | App ID | Country | Platform | Active |

Теперь подключение нового приложения занимает одну строку, и следующей ночью ETL сам начинает его загружать.

Transformer

Вот он оказался важнее клиента. Самая распространенная ошибка интеграций — брать то, что возвращает API, и сразу помещать в базу. Кажется, что так быстрее, но на практике это приводит к хаосу: поля называются непонятно, даты в странном формате, типы данных не соответствуют схеме базы, а если API завтра изменится, придется всё переписать. 

Мы с командой проекта сделали отдельный слой трансформации:

class SensorTowerTransformer:

    def transform(self, response):

        ...

        return dataframe

Именно здесь происходят:

  • преобразование дат;

  • нормализация типов;

  • переименование полей;

  • вычисление служебных колонок;

  • подготовка данных для BigQuery.

В результате остальная система ничего не знает о внутреннем формате Sensor Tower. И опять же, если API изменится, достаточно поправить один модуль.

Почему BigQuery

После трансформации данные перестают быть данными Sensor Tower — это уже обычные строки и колонки, с которыми можно делать что угодно: например, писать собственные SQL, объединять несколько источников, хранить историю, использовать BI и AI. Так Sensor Tower становится всего лишь одним из поставщиков данных.

В итоге добавление нового конкурента теперь выглядит как добавление записи в справочник:

| Company | App ID | Country | Platform | Active |

При следующем запуске система автоматически обращается к API, получает данные, преобразует их и сохраняет в BigQuery. Без изменений кода и ручного экспорта.

В чём проблема

Когда данные начали храниться в BigQuery, нужно было превратить сырые записи в полезную аналитику. И здесь выяснилось, что построить правильный рейтинг креативов значительно сложнее, чем написать ETL.

Например, один и тот же креатив может показываться одновременно в разных соцсетях. Если просто отсортировать строки, получаются дубликаты; если использовать AVG(impression_share), рейтинг тоже оказывается неверным.

В итоге пришлось считать креатив единой сущностью (creative_id), а долю показов — суммировать по всем рекламным сетям (SUM(impression_share)). Именно такие решения отличают корректный рейтинг от простой сортировки.

Почему Slack

После того как данные и SQL были готовы, возник следующий вопрос: как донести результаты до команды? Можно, конечно, использовать Tableau или сделать внутренний веб-портал, но это не решило бы главную проблему — аналитикам всё равно пришлось бы заходить туда самостоятельно, и не каждый бы помнил об этом. Мы решили обхитрить систему и сделать так, чтобы аналитика сама приходила специалистам в руки.

Так мы перешли к следующему этапу и начали работу над Slack-ботом. Сначала всё выглядело просто. Я добавил несколько slash-команд, которые неплохо работали:

/creatives-week

/creatives-month

/creatives-weekly-leaders

Но пользоваться ими было неудобно: приходилось запоминать команды и четко знать, какая из них за что отвечает. Чтобы упростить себе жизнь, мы с командой проекта создали полноценный интерфейс внутри Slack.

Интерфейс вместо команд

Я сделал меню на базе Slack Block Kit, который позволяет строить внутри мессенджера почти полноценный UI. Пользователь открывает меню и видит три действия:

Источник: https://habr.com/ru/companies/garage8/articles/1096816/


Интересные статьи

Интересные статьи

Дан набор данных, в нем — информация об отделе, эффективности, длительности работы, количестве отгулов, о рабочих часах нескольких сотрудников. Чтобы увидеть проблемы с эффективностью нам ну...
Для каких целей? На момент возникновения идеи было еще не совсем понятно. Но предпосылки развития идеи были
Когда ваша тетрадь с заметками — общедоступная база данных Прим. пер.: Я делаю проект Ontol (Github для знаний/мудрости), на который меня вдохновили, в том числе и, мысли Ванневар...
Если у вас есть интернет-магазин и вы принимаете платежи через Интернет, то с 01 июля 2017 года у вас есть онлайн-касса.
Этот пост будет из серии, об инструментах безопасности, которые доступны в Битриксе сразу «из коробки». Перечислю их все, скажу какой инструмент в какой редакции Битрикса доступен, кратко и не очень р...