非同期リクエスト

新しい Search Ads 360 Reporting API をご利用いただけるようになりました。新しい API では、柔軟性の向上により、カスタム レポートを作成し、レポート作成のアプリケーションやプロセスにデータを統合することができます。詳しくは、新しい Search Ads 360 Reporting API への移行と使用についての記事をご覧ください。

サイズの大きいレポートのリクエストの生成には時間がかかることがあるため、Search Ads 360 API には、レポートのリクエストとダウンロードに非同期の手法が用意されています。この手法では、レポートに含めるデータを指定する最初のリクエストを送信してから、検索広告 360 でレポートの生成が終了するまで追加のポーリング リクエストを送信します。レポートのサイズに応じて、データは複数のファイルに分割されます。レポートが生成されたら、各レポート ファイルをダウンロードするようにリクエストを送信します。リクエストするデータ量を減らしたい場合は、1 回の同期リクエストで送信できます。

非同期リクエストを実行するには

  1. Reports.request() を呼び出して、レポートに含めるデータのタイプを指定します。リクエストできるデータのタイプについては、レポートタイプをご覧ください。

    検索広告 360 でリクエストが確認され、レポート ID(このリクエストの一意の識別子)が返されます。

  2. レポート ID を指定して Reports.get() を呼び出します。

    検索広告 360 から次のレスポンスが返されます。

    • レポートをダウンロードできる状態かどうか。
    • レポートの準備ができたら、レポートをダウンロードするための 1 つ以上の URL。
  3. Reports.getFile() を呼び出してエンコードされたレポート ファイルをダウンロードするか、URL から直接ダウンロードします。

    レポートは UTF-8 エンコード形式のファイルで返されます。

レポートの準備状況を確認するためには、どのくらいの頻度でレポートをポーリングする必要がありますか?

検索広告 360 でのレポート作成に必要な時間は、主にレポート内のデータ量によって異なります。レポート ステータスを 1 分に 1 回ポーリングして、平均レポート リクエストが完了するまでにかかった時間が大幅に増減する場合は、頻度を調整してみてください。

非同期レポートを複数のファイルに分割する

非同期リクエストに応じて、検索広告 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.
}
          

Java

/**
 * 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);
}

.NET

この関数は、広告主のキャンペーンをリストするレポートを作成し、返されたトークンを 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,
    };
}

Python

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']

検証に成功した場合

レポートの検証に合格すると、検索広告 360 からレポート ID が返されます。検索広告 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).
}
      

検証で不合格だった場合

レポートが検証に合格しなかった場合、検索広告 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."
 }
}

レポートのステータスについてポーリングする

レポート ID を指定して Report.Get() を呼び出します。

JSON

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

Java

/**
 * 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.
  }
}

.NET

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.
    }
}

Python

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

レポートの準備ができていない場合

レポートの準備ができていない場合は、検索広告 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"
    }
  ],
}
      

レポートの生成に失敗した場合

検索広告 360 でレポートを生成できない場合は、HTTP エラーコードのいずれかとその説明が返されます。

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

検索広告 360 が返すエラーのリストについては、レスポンス コードをご覧ください。

レポートをダウンロードする

レポートをダウンロードするには、各レポート ファイルの URL に直接アクセスするか、Reports.getFile() を呼び出して、レポート ID とファイル番号(0 のインデックス番号)を指定します。レポートは 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
          

Java

/**
 * 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();
  }
}

.NET

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);
        }
    }
}

Python

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
      

ID マッピング ファイルをダウンロード

検索広告 360 従来版とリニューアル版間の ID マッピングを含むファイルをダウンロードできます。リクエストされた広告主については、ファイルには検索広告 360 従来版とリニューアル版の両方に存在するすべての子エンティティ(エンジン アカウント、キャンペーン、広告グループなど)が含まれています。

Python

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()