Портфолио

Airflow + Яндекс.Директ: выгружаем статистику рекламных кампаний из API

Проблема

Маркетинговая команда ежедневно тратит часы на ручную выгрузку статистики по рекламным кампаниям из Яндекс.Директа. API работает асинхронно, требует обработки rate limits, а данных много — несколько аккаунтов, десятки кампаний, сотни строк.

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

Что сделали

РазработалаиETL-пайплайн на Apache Airflow, который:
  • Запрашивает отчёты через API Яндекс.Директа (v5)
  • Работает с асинхронными отчётами (статус 201 → ожидание → 200)
  • Обрабатывает rate limits (коды 52, 53) с автоматическими повторами
  • Поддерживает несколько аккаунтов
  • Использует автоматическую атрибуцию (AUTO модель)
  • Загружает данные в PostgreSQL с идемпотентностью (ON CONFLICT)

Архитектура

Всё поднято в Docker: одна команда — и среда готова.

Ключевые фрагменты кода

Асинхронный запрос отчёта:
response = make_request(account, "reports", body)

if response.status_code == 201:
    report_id = response.headers.get("ReportId")
    
    for attempt in range(max_retries):
        time.sleep(wait_time)
        ready_response = make_request(account, f"reports/{report_id}")
        
        if ready_response.status_code == 200:
            response = ready_response
            print("Отчёт успешно сгенерирован!")
            break
Обработка rate limits:
error_code = error_data['error'].get('error_code')
if error_code in [52, 53]:
    wait_time = int(error_data['error'].get('error_detail', delay))
    print(f"Лимит запросов. Ждём {wait_time} сек.")
    time.sleep(wait_time)
    continue
Идемпотентная загрузка в PostgreSQL:
INSERT INTO yd_campaigns_stats (
    client_login, date, campaign_name, campaign_id,
    impressions, clicks, cost, conversions
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
ON CONFLICT (client_login, date, campaign_id, targeting_location_name)
DO UPDATE SET
    impressions = EXCLUDED.impressions,
    clicks = EXCLUDED.clicks,
    cost = EXCLUDED.cost,
    conversions = EXCLUDED.conversions;
Весь код открыт на GitHub: https://github.com/olkhovii/data-engineer-portfolio

Результат

  • Данные за 3+ года по трём аккаунтам
  • 450+ кампаний в единой витрине
  • Время подготовки отчётов сократилось с 1 часа до 5 минут
2026-06-10 22:48 BI аналитика