Get statistics for agency clients
Python version 2 or 3 using JSON with the Requests library
This example shows how to use the AgencyClients.get method to get a list of agency clients and then execute requests to the Reports service to get statistics for advertiser accounts for the past day. The mode for generating the report is selected automatically. If the report is added to the offline queue, the repeat requests are executed.
To use the example, specify the OAuth access token that you received for the agency representative in the input data.
# -*- coding: utf-8 -*-
import requests
from requests.exceptions import ConnectionError
from time import sleep
import json
from datetime import date, timedelta
from time import time
# Метод для корректной обработки строк в кодировке 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 isinstance(x, bytes):
return x.decode('utf8')
else:
return x
# --- Входные данные ---
# Адрес сервиса AgencyClients для отправки JSON-запросов (регистрозависимый)
AgencyClientsURL = 'https://api.direct.yandex.com/json/v5/agencyclients'
# Адрес сервиса Reports для отправки JSON-запросов (регистрозависимый)
ReportsURL = 'https://api.direct.yandex.com/json/v5/reports'
# OAuth-токен представителя агентства, от имени которого будут выполняться запросы
token = 'ТОКЕН'
# --- Подготовка запроса к сервису AgencyClients ---
# Создание HTTP-заголовков запроса
headers = {
# OAuth-токен. Использование слова Bearer обязательно
"Authorization": "Bearer " + token,
# Язык ответных сообщений
"Accept-Language": "ru"
}
AgencyClientsBody = {
"method": "get",
"params": {
"SelectionCriteria": {
"Archived": "NO" # Получить только активных клиентов
},
"FieldNames": ["Login"],
"Page": {
"Limit": 10000, # Получить не более 10000 клиентов в ответе сервера
"Offset": 0
}
}
}
# --- Выполнение запросов к сервису AgencyClients ---
# Отсутствие параметра LimitedBy в ответе означает, что
# получены все клиенты
HasAllClientLoginsReceived = False
ClientList = []
while not HasAllClientLoginsReceived:
ClientsResult = requests.post(AgencyClientsURL, json.dumps(AgencyClientsBody), headers=headers).json()
for Client in ClientsResult['result']['Clients']:
ClientList.append(Client["Login"])
if ClientsResult['result'].get("LimitedBy", False):
AgencyClientsBody['Page']['Offset'] = ClientsResult['result']["LimitedBy"]
else:
HasAllClientLoginsReceived = True
# --- Подготовка запроса к сервису Reports ---
# Создание тела запроса
# Отчет содержит количество показов, кликов и расход средств по всем кампаниям клиента
body = {
"params": {
"SelectionCriteria": {},
"FieldNames": [
"Impressions",
"Clicks",
"Cost"
],
"ReportName": u("ACCOUNT_PERFORMANCE"),
"ReportType": "ACCOUNT_PERFORMANCE_REPORT",
"DateRangeType": "AUTO",
"Format": "TSV",
"IncludeVAT": "NO",
"IncludeDiscount": "NO"
}
}
# Создание результирующих данных
resultcsv = "Login;Impressions;Clicks;Costs\n"
# Дополнительные HTTP-заголовки для запроса отчетов
headers['skipReportHeader'] = "true"
headers['skipColumnHeader'] = "true"
headers['skipReportSummary'] = "true"
headers['returnMoneyInMicros'] = "false"
# --- Выполнение запросов к сервису Reports ---
for Client in ClientList:
# Добавление HTTP-заголовка "Client-Login"
headers['Client-Login'] = Client
# Кодирование тела запроса в JSON
requestBody = json.dumps(body, indent=4)
# Запуск цикла для выполнения запросов
# Если получен HTTP-код 200, то содержание отчета добавляется к результирующим данным
# Если получен HTTP-код 201 или 202, выполняются повторные запросы
while True:
try:
req = requests.post(ReportsURL, requestBody, headers=headers)
req.encoding = 'utf-8' # Принудительная обработка ответа в кодировке UTF-8
if req.status_code == 400:
print("Параметры запроса указаны неверно или достугнут лимит отчетов в очереди")
print("RequestId: {}".format(req.headers.get("RequestId", False)))
print("JSON-код запроса: {}".format(u(body)))
print("JSON-код ответа сервера: \n{}".format(u(req.json())))
break
elif req.status_code == 200:
print("Отчет для аккаунта {} создан успешно".format(str(Client)))
print("RequestId: {}".format(req.headers.get("RequestId", False)))
if req.text != "":
tempresult = req.text.split('\t')
resultcsv += "{};{};{};{}\n".format(Client, tempresult[0], tempresult[1], str(tempresult[2]).replace('.', ','))
else:
resultcsv += "{};0;0;0\n".format(Client)
break
elif req.status_code == 201:
print("Отчет для аккаунта {} успешно поставлен в очередь в режиме offline".format(str(Client)))
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("Отчет формируется в режиме офлайн".format(str(Client)))
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("JSON-код ответа сервера: \n{}".format(u(req.json())))
break
elif req.status_code == 502:
print("Время формирования отчета превысило серверное ограничение.")
print(
"Пожалуйста, попробуйте изменить параметры запроса - уменьшить период и количество запрашиваемых данных.")
print("JSON-код запроса: {}".format(body))
print("RequestId: {}".format(req.headers.get("RequestId", False)))
print("JSON-код ответа сервера: \n{}".format(u(req.json())))
break
else:
print("Произошла непредвиденная ошибка")
print("RequestId: {}".format(req.headers.get("RequestId", False)))
print("JSON-код запроса: {}".format(body))
print("JSON-код ответа сервера: \n{}".format(u(req.json())))
break
# Обработка ошибки, если не удалось соединиться с сервером API Директа
except ConnectionError:
# В данном случае мы рекомендуем повторить запрос позднее
print("Произошла ошибка соединения с сервером API")
# Принудительный выход из цикла
break
# Если возникла какая-либо другая ошибка
except:
# В данном случае мы рекомендуем проанилизировать действия приложения
print("Произошла непредвиденная ошибка")
# Принудительный выход из цикла
break
print("Создание отчетов для аккаунтов завершено")
# Создание и запись файла
filename = "AccountsPerfomanceReport_{}.csv".format(str(time()))
resultfile = open(filename, 'w+')
resultfile.write(resultcsv)
resultfile.close()
print("Результат записан в файл {}".format(filename))