由于生成大型报告请求可能需要一定的时间,因此 Search Ads 360 API 提供了一种用于请求和下载报告的异步技术。这个 方法时,您需要发送一个初始请求,指定您希望在报告中包含的数据, 然后发送其他轮询请求,直到 Search Ads 360 生成报告。 Search Ads 360 会将报表数据拆分为多个文件,具体取决于报表的大小。部署 已生成报告,您可以发送下载每个报告文件的请求。如果您 但请求的数据量较少,您可以只发送一个同步 请求。
发出异步请求
- 致电
Reports.request()以指定您要在报告中包含的数据类型请参阅报告类型,了解您 可以请求。Search Ads 360 会验证请求并返回报表 ID(此 ID 是此 ID 的唯一标识符) 请求。
- 致电
Reports.get()。Search Ads 360 的响应表明:
- 报告是否可供下载。
- 如果报告已准备就绪,则提供一个或多个用于下载报告的网址。
- 致电
Reports.getFile()即可下载经过编码的报告文件,也可以直接从网址下载。Search Ads 360 会以 UTF-8 编码的文件返回报表。
我应该以怎样的频率轮询报告以查看报告是否准备就绪?
Search Ads 360 生成报告所需的时间主要取决于 报告。尝试每分钟轮询一次报告状态,然后 如果您的平均报告请求时间明显增加或减少,请调整频率 即可。
将异步报表拆分为多个文件
为响应异步请求,Search Ads 360 会自动将大型报表拆分为
多个文件。使用 Reports.request.maxRowsPerFile
属性指定文件大小上限。生成的每个报告文件都必须包含
最多 maxRowsPerFile 个报告行(不包括标题)。其他网址
是为每个文件生成的,并返回以响应 Reports.get()。相关信息
有关如何下载报告文件的信息,请参阅下载
报告。
对于 CSV 报告,每个文件中的标题都会重复。
异步示例
以下是使用异步方法的示例请求和响应。
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']
如果验证成功
如果报表通过验证,Search Ads 360 会返回一个报表 ID。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."
}
}
针对报告状态的投票
使用报告 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
如果报告尚未就绪
如果报表尚未生成,Search Ads 360 会返回 HTTP 202 响应,而 isReportReady
字段为 false。
{
"kind": "doubleclicksearch#report",
"id": "MTMyNDM1NDYK",
"isReportReady": false,
"request": {
...
},
...
}
报告准备就绪后
当报告生成完毕并可供下载时,isReportReady
字段为 true。响应还包含一个附加字段 files,
(包含用于下载报告文件的网址)。
{
"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 无法生成报告,则会返回 以及相应的说明
{
"error" : {
"code" : 410, // Or other error codes.
"message" : "Processing was halted on the backend and will not continue."
}
}
请参阅响应代码,获取 Search Ads 360 可能返回的错误。
下载报告
您可以直接点击每个报告文件网址,或调用 Reports.getFile() 以下载报告。
报告 ID 和文件编号(索引为 0)。Search Ads 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
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 映射文件
您可以下载包含旧版 Search Ads 360 和 新版 Search Ads 360。对于所请求的广告客户,该文件包含所有子实体(例如 引擎账号、广告系列、广告组等)同时存在于旧版 Search Ads 360 中, 和新版 Search Ads 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()