Получение статистики за произвольные даты

Python версии 2 или 3, формат XML, используются библиотеки requests, pyxb

После установки библиотеки pyxb станет доступна утилита для генерации классов pyxbgen. Выполните команду

pyxbgen -u https://api.direct.yandex.com/v5/reports.xsd -m directapi5reports

В результате будут сформированы два файла: _general.py и directapi5reports.py. Импортируйте файл directapi5reports.py в скрипт, чтобы генерировать корректные XML-коды запроса. Более подробную информацию вы можете найти на странице http://pyxb.sourceforge.net.

Пример демонстрирует выполнение запроса к сервису Reports, обработку и вывод результата. Режим формирования отчета выбирается автоматически. Если отчет поставлен в очередь на формирование в режиме офлайн, выполняются повторные запросы.

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

Для использования примера во входных данных укажите OAuth-токен. При запросе от имени агентства необходимо также указать логин клиента. В теле запроса укажите начальную и конечную даты отчетного периода, а также название отчета, уникальное для рекламодателя.

# -*- coding: utf-8 -*-
import requests
from requests.exceptions import ConnectionError
from time import sleep
import directapi5reports
import pyxb

# Метод для корректной обработки строк в кодировке UTF-8 как в Python 3, так и в Python 2
import sys

if sys.version_info < (3,):
    def u(x):
        try:
            return x.encode("utf8")
        except UnicodeDecodeError:
            return x
else:
    def u(x):
        if type(x) == type(b''):
            return x.decode('utf8')
        else:
            return x

# --- Входные данные ---
# Адрес сервиса Reports для отправки XML-запросов (регистрозависимый)
ReportsURL = 'https://api.direct.yandex.com/v5/reports'

# OAuth-токен пользователя, от имени которого будут выполняться запросы
token = 'ТОКЕН'

# Логин клиента рекламного агентства
# Обязательный параметр, если запросы выполняются от имени рекламного агентства
clientLogin = 'ЛОГИН_КЛИЕНТА'

# --- Подготовка запроса ---
# Создание HTTP-заголовков запроса
headers = {
           # OAuth-токен. Использование слова Bearer обязательно
           "Authorization": "Bearer " + token,
           # Логин клиента рекламного агентства
           "Client-Login": clientLogin,
           # Язык ответных сообщений
           "Accept-Language": "ru",
           # Режим формирования отчета
           "processingMode": "auto"
           # Формат денежных значений в отчете
           # "returnMoneyInMicros": "false",
           # Не выводить в отчете строку с названием отчета и диапазоном дат
           # "skipReportHeader": "true",
           # Не выводить в отчете строку с названиями полей
           # "skipColumnHeader": "true",
           # Не выводить в отчете строку с количеством строк статистики
           # "skipReportSummary": "true"
           }

# Создание тела запроса
requestData = directapi5reports.ReportDefinition()
# Критерии отбора данных
requestData.SelectionCriteria = pyxb.BIND()
requestData.SelectionCriteria.DateFrom = pyxb.BIND("НАЧАЛЬНАЯ_ДАТА")
requestData.SelectionCriteria.DateTo = pyxb.BIND("КОНЕЧНАЯ_ДАТА")

# Поля, которые нужно получить в отчете
requestData.FieldNames = ["Date","CampaignName","LocationOfPresenceName","Impressions","Clicks","Cost"]
# Сортировка по дате по возрастанию
requestData.OrderBy = [pyxb.BIND("Date","ASCENDING")]
# Название отчета
requestData.ReportName = u("НАЗВАНИЕ_ОТЧЕТА")
# Тип отчета: статистика по кампаниям
requestData.ReportType = "CAMPAIGN_PERFORMANCE_REPORT"
# Период отчета: даты, указанные в параметрах DateFrom и DateTo
requestData.DateRangeType = "CUSTOM_DATE"
# Формат отчета
requestData.Format = "TSV"
# Стоимость кликов возвращать без НДС
requestData.IncludeVAT ="NO"
# Стоимость кликов возвращать без скидки клиента
requestData.IncludeDiscount = "NO"

# Конвертация данных в XML-код запроса
requestData = requestData.toxml()

# --- Запуск цикла для выполнения запросов ---
# Если получен HTTP-код 200, то выводится содержание отчета
# Если получен HTTP-код 201 или 202, выполняются повторные запросы
while True:
    try:
        req = requests.post(ReportsURL,requestData,headers=headers)
        req.encoding = 'utf-8'  # Принудительная обработка ответа в кодировке UTF-8
        if req.status_code == 400:
            print("Параметры запроса указаны неверно или достигнут лимит отчетов в очереди")
            print("RequestId: {}".format(req.headers.get("RequestId",False)))
            print("XML-код запроса: {}".format(u(requestData)))
            print("XML-код ответа сервера: \n{}".format(u(req.text)))
            break
        elif req.status_code == 200:
            print("Отчет создан успешно")
            print("RequestId: {}".format(req.headers.get("RequestId", False)))
            print("Результирующий файл отчета: \n{}".format(u(req.text)))
            break
        elif req.status_code == 201:
            print("Отчет успешно поставлен в очередь в режиме офлайн")
            retryIn = int(req.headers.get("retryIn",60))
            print("Повторная отправка запроса через {} секунд".format(retryIn))
            print("RequestId: {}".format(req.headers.get("RequestId", False)))
            sleep(retryIn)
        elif req.status_code == 202:
            print("Отчет формируется в режиме офлайн")
            retryIn = int(req.headers.get("retryIn", 60))
            print("Повторная отправка запроса через {} секунд".format(retryIn))
            print("RequestId: {}".format(req.headers.get("RequestId", False)))
            sleep(retryIn)
        elif req.status_code == 500:
            print("При формировании отчета произошла ошибка. Пожалуйста, попробуйте повторить запрос позднее.")
            print("RequestId: {}".format(req.headers.get("RequestId",False)))
            print("XML-код ответа сервера: \n{}".format(u(req.text)))
            break
        elif req.status_code == 502:
            print("Время формирования отчета превысило серверное ограничение.")
            print("Пожалуйста, попробуйте изменить параметры запроса - уменьшить период и количество запрашиваемых данных.")
            print("XML-код запроса: {}".format(requestData))
            print("RequestId: {}".format(req.headers.get("RequestId",False)))
            print("XML-код ответа сервера: \n{}".format(u(req.text)))
            break
        else:
            print("Произошла непредвиденная ошибка")
            print("RequestId: {}".format(req.headers.get("RequestId", False)))
            print("XML-код запроса: {}".format(requestData))
            print("XML-код ответа сервера: \n{}".format(u(req.text)))
            break

    # Обработка ошибки, если не удалось соединиться с сервером API Директа
    except ConnectionError:
        # В данном случае мы рекомендуем повторить запрос позднее
        print("Произошла ошибка соединения с сервером API")
        # Принудительный выход из цикла
        break

    # Если возникла какая-либо другая ошибка
    except:
        # В данном случае мы рекомендуем проанализировать действия приложения
        print("Произошла непредвиденная ошибка")
        # Принудительный выход из цикла
        break