Асинхронные запросы

Новый API отчетов Search Ads 360 теперь доступен. Новый API обеспечивает повышенную гибкость для создания пользовательских отчетов и интеграции данных в ваши приложения и процессы отчетности. Узнайте больше о переходе и использовании нового API отчетов Search Ads 360 .

Поскольку создание запросов на большие отчеты может занять некоторое время, API Search Ads 360 предоставляет асинхронный метод запроса и загрузки отчетов. При использовании этого метода вы отправляете первоначальный запрос, в котором указаны данные, которые вы хотите включить в отчет, а затем отправляете дополнительные запросы опроса, пока Search Ads 360 не завершит создание отчета. В зависимости от размера отчета Search Ads 360 разбивает данные на несколько файлов. После создания отчета вы отправляете запросы на загрузку каждого файла отчета. Если вы запрашиваете меньшие объемы данных, вы можете отправить только один синхронный запрос .

Чтобы сделать асинхронный запрос

  1. Вызовите Reports.request() , чтобы указать тип данных, которые вы хотите включить в отчет. См. «Типы отчетов» , чтобы узнать о типах данных, которые вы можете запросить.

    Поисковая реклама 360 проверяет запрос и возвращает идентификатор отчета — уникальный идентификатор этого запроса.

  2. Вызовите Reports.get() с идентификатором отчета.

    В ответе Search Ads 360 указано:

    • Готов ли отчет к загрузке.
    • Если отчет готов, укажите один или несколько URL-адресов для загрузки отчета.
  3. Вызовите Reports.getFile() , чтобы загрузить закодированные файлы отчетов, или просто загрузите их напрямую с URL-адресов.

    Поисковая реклама 360 возвращает отчет в файле с кодировкой UTF-8.

Как часто мне следует проверять отчеты, чтобы убедиться в их готовности?

Время, необходимое Search Ads 360 для создания отчета, в основном зависит от объема данных в отчете. Попробуйте опрашивать статус отчета раз в минуту , а затем отрегулируйте частоту, если выполнение среднего запроса отчета занимает значительно больше или меньше времени.

Разделение асинхронных отчетов на несколько файлов

В ответ на асинхронный запрос Search Ads 360 автоматически разбивает большие отчеты на несколько файлов. Используйте свойство Reports.request.maxRowsPerFile , чтобы указать максимальный размер файла. Каждый результирующий файл отчета гарантированно будет содержать не более maxRowsPerFile строк отчета (не считая заголовков). Для каждого файла генерируется отдельный URL-адрес, который возвращается в ответ на вызов Reports.get() . Информацию о загрузке файлов отчетов см. в разделе Загрузка отчета .

В отчетах CSV заголовок повторяется в каждом файле.

Примечание . API не поддерживает подкачку для асинхронных запросов. То есть вы не можете указать, какие строки в каких файлах отчетов вы хотите видеть. Способ разделения строк между файлами является произвольным и может измениться при повторном запуске того же отчета.

Асинхронный пример

Ниже приведены примеры запросов и ответов с использованием асинхронного метода.

JSON

POST  https://www.googleapis.com/doubleclicksearch/v2/reports
Authorization: Bearer your OAuth 2.0 access token
Content-type: application/json

{
  "reportScope": {
    "agencyId": "12300000000000456", // Replace with your ID
    "advertiserId": "21700000000011523", // Replace with your ID
  },
  "reportType": "keyword",              // This report covers all keywords in the
                                        // advertiser specified in reportScope.
  "columns": [
    { "columnName": "campaignId" },     // Here are some attribute columns available for keyword
    { "columnName": "keywordText" },    // reports.
    { "columnName": "keywordLandingPage" },

    { "columnName": "date" },           // The date column segments the report by individual days.

    { "columnName": "dfaRevenue" },     // Here are some metric columns available for keyword
    {                                   // reports
      "columnName": "visits",
      "startDate": "2013-01-01",        // Each metric column can optionally specify its own start
      "endDate": "2013-01-31",          // and end date; by default the report timeRange is used.
      "headerText": "visits last month" // Every column can optionally specify a headerText, which
                                        // changes the name of the column in the report.
    }
  ],
  "timeRange" : {
    "startDate" : "2012-05-01",         // Dates are inclusive and specified in YYYY-MM-DD format.
    "endDate" : "2012-05-02"

    // Alternatively, try the "changedMetricsSinceTimestamp" or "changedAttributesSinceTimestamp"
    // options. See Incremental reports.

  },
  "filters": [
    {
      "column" : { "columnName": "keywordLandingPage" },
      "operator" : "startsWith",
      "values" : [                      // With this filter, only keywords with landing pages
        "http://www.foo.com",           // rooted at www.foo.com or www.bar.com are returned.
        "http://www.bar.com"            // See Filtered reports.
      ]
    }
  ],
  "downloadFormat": "csv",
  "maxRowsPerFile": 6000000,            // Required. See Splitting reports into multiple files.
  "statisticsCurrency": "agency",       // Required. See Currency for statistics.
  "verifySingleTimeZone": false,        // Optional. Defaults to false. See Time zone.
  "includeRemovedEntities": false           // Optional. Defaults to false.
}
          

Джава

/**
 * Creates a campaign report request, submits the report, and returns the report ID.
 */
private static String createReport(Doubleclicksearch service) throws IOException {
  try {
     return service.reports().request(createSampleRequest()).execute().getId();
  } catch (GoogleJsonResponseException e) {
    System.err.println("Report request was rejected.");
    for (ErrorInfo error : e.getDetails().getErrors()) {
      System.err.println(error.getMessage());
    }
    System.exit(e.getStatusCode());
    return null; // Unreachable code.
  }
}

/**
 * Creates a simple static request that lists the ID and name of all
 * campaigns under agency 12300000000000456 and advertiser 21700000000011523.
 * Substitute your own agency ID and advertiser IDs for the IDs in this sample.
 */
private static ReportRequest createSampleRequest() {
  return new ReportRequest()
      .setReportScope(new ReportScope()
          .setAgencyId(12300000000000456L) // Replace with your ID
          .setAdvertiserId(21700000000011523L)) // Replace with your ID
      .setReportType("campaign")
      .setColumns(Arrays.asList(
          new ReportApiColumnSpec[] {
            new ReportApiColumnSpec().setColumnName("campaignId"),
            new ReportApiColumnSpec().setColumnName("campaign")
          }))
      .setTimeRange(new TimeRange()
          .setStartDate("2012-05-01")
          .setEndDate("2012-05-01"))
      .setDownloadFormat("csv")
      .setStatisticsCurrency("usd")
      .setMaxRowsPerFile(5000000);
}

.СЕТЬ

Эта функция создает отчет, в котором перечислены кампании рекламодателя, и присваивает возвращенный токен reportId .
using api = Google.Apis.Doubleclicksearch.v2;

/// <summary>
/// Creates a report with a sample request and returns the report ID.
/// </summary>
/// <param name="service">Search Ads 360 API service.</param>
private static string CreateReport(api.DoubleclicksearchService service)
{

    var req = service.Reports.Request(CreateSampleRequest());
    var report = req.Execute();
    Console.WriteLine("Created report: ID={0}", report.Id);
    return report.Id;
}

/// <summary>
/// Returns a simple static request that lists the ID and name of all
/// campaigns under an advertiser.
/// Substitute your own agency ID and advertiser IDs for the IDs in this sample.
/// </summary>
private static api.Data.ReportRequest CreateSampleRequest()
{
    return new api.Data.ReportRequest
    {
        ReportScope = new api.Data.ReportRequest.ReportScopeData
        {
            AgencyId = 12300000000000456, // Replace with your ID
            AdvertiserId = 21700000000011523 // Replace with your ID
        },
        ReportType = ReportType.CAMPAIGN,
        Columns = new List<api.Data.ReportApiColumnSpec>
        {
            new api.Data.ReportApiColumnSpec
            {
                ColumnName = "campaignId",
            },
            new api.Data.ReportApiColumnSpec
            {
                ColumnName = "campaign",
            },
        },
        TimeRange = new api.Data.ReportRequest.TimeRangeData
        {
            StartDate = "2015-01-01",
            EndDate = "2015-01-07",
        },
        DownloadFormat = "csv",
        StatisticsCurrency = "usd",
        MaxRowsPerFile = 5000000,
    };
}

Питон

def request_report(service):
  """Request sample report and print the report ID that DS returns. See Set Up Your Application.

  Args:
    service: An authorized Doubleclicksearch service.
  Returns:
    The report id.
  """
  request = service.reports().request(
      body=
      {
        "reportScope": {
            "agencyId": "12300000000000456", // Replace with your ID
            "advertiserId": "21700000000011523", // Replace with your ID
            "engineAccountId": "700000000073991" // Replace with your ID
            },
        "reportType": "keyword",
        "columns": [
            { "columnName": "campaignId" },
            { "columnName": "keywordText" },
            { "columnName": "keywordLandingPage" },

            { "columnName": "date" },

            { "columnName": "dfaRevenue" },
            {
              "columnName": "visits",
              "startDate": "2013-01-01",
              "endDate": "2013-01-31",
              "headerText": "visits last month"
            }
          ],
          "timeRange" : {
            "startDate" : "2012-05-01",
            "endDate" : "2012-05-02"
          },
          "filters": [
            {
              "column" : { "columnName": "keywordLandingPage" },
              "operator" : "startsWith",
              "values" : [
                "http://www.foo.com",
                "http://www.bar.com"
              ]
            }
          ],
          "downloadFormat": "csv",
          "maxRowsPerFile": 6000000,
          "statisticsCurrency": "agency",
          "verifySingleTimeZone": "false",
          "includeRemovedEntities": "false"
        }
  )

  json_data = request.execute()
  return json_data['id']

Если проверка прошла успешно

Если отчет проходит проверку, Search Ads 360 возвращает идентификатор отчета. Search Ads 360 также возвращает метаданные, касающиеся кода валюты и часового пояса.

{
  "kind": "adsdartsearch#report",
  "id": "MTMyNDM1NDYK",                      // This is the report id.
  "isReportReady": false,                    // The report is not finished generating.

  "request": {                               // The request that created this report.
    ...
  },

  "statisticsCurrencyCode": "CAD",           // The currency used for statistics. E.g., if
                                             // advertiser currency was requested, this would be
                                             // currency code of the advertiser in scope.

  "statisticsTimeZone": "America/New_York"   // If all statistics in the report were sourced from
                                             // a single time zone, this would be it. If
                                             // verifySingleTimeZone was set to true in the request,
                                             // then this field will always be populated (or the
                                             // request will fail).
}
      

Если проверка не удалась

Если отчет не проходит проверку, Search Ads 360 возвращает ответ HTTP 400 с объектом ошибки. Например, в приведенном выше примере запроса не указано реальное агентство:

{
 "error": {
   "code": 400,
   "message": "statisticsCurrency: the agency in scope does not have a valid currency. Please make sure the agency is properly initialized in Search Ads 360."
 }
}

Опрос о статусе отчета

Вызовите Report.Get() с идентификатором отчета.

JSON

GET https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK
          

Джава

/**
 * Polls the reporting API with the reportId until the report is ready.
 * Returns the report.
 */
private static Report pollUntilReportIsFinished(Doubleclicksearch service, String reportId)
    throws IOException, InterruptedException {
  long delay = 1;
  while (true) {
    Report report = null;
    try {
      report = service.reports().get(reportId).execute();
    } catch (GoogleJsonResponseException e) {
      System.err.println("Report generation has failed.");
      System.exit(e.getStatusCode());
    }
    if (report.getIsReportReady()) {
      return report;
    }
    System.out.format("Report %s is not ready - waiting %s seconds.%n", reportId, delay);
    Thread.sleep(TimeUnit.SECONDS.toMillis(delay));
    delay = delay + delay; // Double the delay for the next iteration.
  }
}

.СЕТЬ

using api = Google.Apis.Doubleclicksearch.v2;

/// <summary>
/// Polls until the report with the given ID completes.
/// </summary>
/// <param name="service">Search Ads 360 API service.</param>
/// <param name="reportId">Report ID to poll.</param>
/// <exception cref="ApplicationException">
/// Thrown when the report completes, but has failed.
/// </exception>
private static api.Data.Report PollUntilReportIsFinished(
    api.DoubleclicksearchService service,
    string reportId)
{
    TimeSpan delay = TimeSpan.FromSeconds(1);
    while (true)
    {
        api.Data.Report report;
        try
        {
            report = service.Reports.Get(reportId).Execute();
        }
        catch (Google.GoogleApiException ex)
        {
            throw new ApplicationException("Report generation failed", ex);
        }
        if (report.IsReportReady.GetValueOrDefault(false))
        {
            return report;
        }
        Console.WriteLine("Report is not ready - waiting {0}", delay);
        Thread.Sleep(delay);
        delay = delay.Add(delay); // Double the delay for the next iteration.
    }
}

Питон

import pprint
import simplejson
from googleapiclient.errors import HttpError

def poll_report(service, report_id):
  """Poll the API with the reportId until the report is ready, up to ten times.

  Args:
    service: An authorized Doubleclicksearch service.
    report_id: The ID DS has assigned to a report.
  """
  for _ in xrange(10):
    try:
      request = service.reports().get(reportId=report_id)
      json_data = request.execute()
      if json_data['isReportReady']:
        pprint.pprint('The report is ready.')

        # For large reports, DS automatically fragments the report into multiple
        # files. The 'files' property in the JSON object that DS returns contains
        # the list of URLs for file fragment. To download a report, DS needs to
        # know the report ID and the index of a file fragment.
        for i in range(len(json_data['files'])):
          pprint.pprint('Downloading fragment ' + str(i) + ' for report ' + report_id)
          download_files(service, report_id, str(i)) # See Download the report.
        return

      else:
        pprint.pprint('Report is not ready. I will try again.')
        time.sleep(10)
    except HttpError as e:
      error = simplejson.loads(e.content)['error']['errors'][0]

      # See Response Codes
      pprint.pprint('HTTP code %d, reason %s' % (e.resp.status, error['reason']))
      break

Если отчет не готов

Если отчет не готов, Search Ads 360 возвращает ответ HTTP 202 , а поле isReportReady имеет значение false.

{
  "kind": "doubleclicksearch#report",
  "id": "MTMyNDM1NDYK",
  "isReportReady": false,
  "request": {
    ...
  },
  ...
}
      

Когда отчет будет готов

Когда отчет завершен и готов к загрузке, поле isReportReady имеет значение true. В ответе также есть дополнительное поле files , содержащее URL-адреса для загрузки файлов отчета.

{
  "kind": "doubleclicksearch#report",
  "id": "MTMyNDM1NDYK",
  "isReportReady": true,
  "request": {
    ...
  },
  ...
  "rowCount": 1329,        // Total rows in the report, not counting headers.
  "files": [
    {
      "url": "https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/0"
      "byteCount": "10242323"
    },
    {
      "url": "https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/1"
      "byteCount": "10242323"
    }
  ],
}
      

Если формирование отчета не удалось

Если Search Ads 360 не может создать отчет, он возвращает один из нескольких кодов ошибок HTTP вместе с описанием.

{
  "error" : {
   "code" : 410,            // Or other error codes.
   "message" : "Processing was halted on the backend and will not continue."
  }
}
      

Список ошибок, которые может возвращать Search Ads 360, см. в разделе «Коды ответов» .

Скачать отчет

Вы можете загрузить отчет, напрямую нажав URL-адрес каждого файла отчета или вызвав Reports.getFile() с идентификатором отчета и номером файла (индексируется 0). Поисковая реклама 360 возвращает отчет в файле с кодировкой UTF-8.

Вот примеры запросов Reports.getFile() :

JSON

GET https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/0?alt=media
и
GET https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/1?alt=media
          

Джава

/**
 * Downloads the shards of a completed report to the given local directory.
 * Files are named CampaignReport0.csv, CampaignReport1.csv, and so on.
 */
private static void downloadFiles(
    Doubleclicksearch service,
    Report report,
    String localPath) throws IOException {
  for (int i = 0; i < report.getFiles().size(); i++) {
    FileOutputStream outputStream =
        new FileOutputStream(new File(localPath, "CampaignReport" + i));
    service.reports().getFile(report.getId(), i).executeAndDownloadTo(outputStream);
    outputStream.close();
  }
}

.СЕТЬ

using api = Google.Apis.Doubleclicksearch.v2;

/// <summary>
/// Downloads the shards of a completed report to the given local directory.
/// Files are named CampaignReport0.csv, CampaignReport1.csv, and so on.
/// </summary>
/// <param name="service">Search Ads 360 API service.</param>
/// <param name="report">Report ID to download.</param>
/// <param name="localPath">Path of the directory to place downloaded files.</param>
private static void DownloadFiles(
    api.DoubleclicksearchService service,
    api.Data.Report report,
    string localPath)
{
    Directory.CreateDirectory(localPath);
    for (int i = 0; i < report.Files.Count; ++i)
    {
        string fileName = Path.Combine(
            localPath,
            string.Format("CampaignReport{0}.csv", i));
        Console.WriteLine("Downloading shard {0} to {1}", i, fileName);
        using (Stream dst = File.OpenWrite(fileName))
        {
            service.Reports.GetFile(report.Id, i).Download(dst);
        }
    }
}

Питон

def download_files(service, report_id, report_fragment):
  """Generate and print sample report.

  Args:
    service: An authorized Doubleclicksearch service.
    report_id: The ID DS has assigned to a report.
    report_fragment: The 0-based index of the file fragment from the files array.
  """
  f = file('report-' + report_fragment + '.csv', 'w')
  request = service.reports().getFile_media(reportId=report_id, reportFragment=report_fragment)
  f.write(request.execute().decode('utf-8'))
  f.close()

Пример отчета

Вот пример отчета в формате CSV. Каждый фрагмент файла отчета имеет собственную строку заголовка. Подробности об этом формате см. в RFC 4180 .

keywordText,campaignId,landingPageUrl,day,revenue,visits last month,my revenue
google,71700000002104742,http://www.google.com,2012-05-01,10.2,5,20
google,71700000002104742,http://www.google.com,2012-05-02,11,10,60.23
      

Скачать файл сопоставления идентификаторов

Вы можете скачать файл, содержащий сопоставления идентификаторов между предыдущей версией Поисковой рекламы 360 и новой Поисковой рекламой 360. Для запрошенного рекламодателя файл включает в себя все дочерние объекты (например, учетные записи системы, кампании, группы объявлений и т. д.), существующие в обеих версиях. предыдущая версия Search Ads 360 и новая Search Ads 360.

Питон

def download_mapping_file(service, file_name, agency_id, advertiser_id):
    """Generate and save mapping file to a csv.

    Args:
      service: An authorized Doubleclicksearch service.
      file_name: Filename to write the ID mapping file.
      agency_id: DS ID of the agency.
      advertiser_id: DS ID of the advertiser.
    """
    request = service.reports().getIdMappingFile_media(agencyId=agency_id,
        advertiserId=advertiser_id)

    response = request.execute()
    response = response.decode('utf-8')

    f = open(file_name + '.csv', 'w')
    f.write(response)
    f.close()