Get statistics for any dates

Python 2 or 3 using XML with the Requests and PyXB libraries

After installing the PyXB library, the utility for generating pyxbgen classes will be available. Run the command

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

As a result, two files will be formed: _general.py and directapi5reports.py. Import the directapi5reports.py file to the script to generate valid XML request codes. For more information, see http://pyxb.sourceforge.net.

This example shows a request to the Reports service, along with the result processing and output. The mode for generating the report is selected automatically. If the report is added to the offline queue, the repeat requests are executed.

The report contains statistics on impressions, clicks, and expenditures for all the advertiser's campaigns for any specified period, with grouping by date, campaign name, and user location.

To use the example, specify the OAuth access token in the input data. If you're submitting a request on behalf of an agency, be sure to include the client's login. In the request message body, specify the start and end dates of the report period and a report name that is unique among the advertiser's reports.

# -*- 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