概要
このガイドでは、API を使用してレポートを実行しダウンロードする方法について説明します。ここでは、保存済みの既存のレポートクエリを使用する場合と、アドホック レポートクエリを作成する場合の両方についてご確認いただけます。
前提条件
- 本番環境の DFP ネットワークへのアクセス
- DFP のクライアント ライブラリ
はじめに
DFP のレポートについてよくご存知ない場合は、ヘルプセンターのこちらの記事で、DFP 管理画面でのレポートの実行方法をご確認ください。管理画面では、出力のプレビューを表示したり、ヒントを参照して列とディメンションの可能な組み合わせを確認したりできます。複雑なレポートクエリを作成するときには、まず管理画面でクエリを作成してから API でそのクエリを取得すると作業が簡単になることがあります。
保存済みの ReportQuery を取得する
ReportQuery オブジェクトにはレポートのすべての詳細が含まれます。DFP 管理画面で作成したレポートクエリは ReportService.getSavedQueriesByStatement メソッドを使って取得できます。保存済みのクエリの ID は、管理画面でクエリを開いたときのページの URL に含まれています。たとえば https://www.google.com/dfp/1234#reports/query/qid=456789
という URL の場合、クエリ ID は 456789
になります。
ご利用の API バージョンにクエリが対応していない場合、SavedQuery.reportQuery は null
となり、SavedQuery.isCompatibleWithApiVersion は false
となります。
保存済みのクエリが API に対応している場合は、そのまま、または変更を加えてクエリを実行することができます。
Java
StatementBuilder statementBuilder = new StatementBuilder() .where("id = :id") .orderBy("id ASC") .limit(1) .withBindVariableValue("id", savedQueryId); SavedQueryPage page = reportService.getSavedQueriesByStatement(statementBuilder.toStatement()); SavedQuery savedQuery = Iterables.getOnlyElement(Arrays.asList(page.getResults())); if (!savedQuery.getIsCompatibleWithApiVersion()) { throw new IllegalStateException("The saved query is not compatible with this API version."); } ReportQuery reportQuery = savedQuery.getReportQuery();
Python
statement = (dfp.StatementBuilder() .Where('id = :id') .WithBindVariable('id', long(saved_query_id)) .Limit(1)) response = report_service.getSavedQueriesByStatement( statement.ToStatement()) if 'results' in response and len(response['results']): saved_query = response['results'][0] if saved_query['isCompatibleWithApiVersion']: report_job = {} # Set report query and optionally modify it. report_job['reportQuery'] = saved_query['reportQuery']
PHP
$statementBuilder = (new StatementBuilder())->where('id = :id') ->orderBy('id ASC') ->limit(1) ->withBindVariableValue('id', $savedQueryId); $savedQueryPage = $reportService->getSavedQueriesByStatement( $statementBuilder->toStatement() ); $savedQuery = $savedQueryPage->getResults()[0]; if ($savedQuery->getIsCompatibleWithApiVersion() === false) { throw new UnexpectedValueException( 'The saved query is not compatible with this API version.' ); } $reportQuery = $savedQuery->getReportQuery();
C#
StatementBuilder statementBuilder = new StatementBuilder() .Where("id = :id") .OrderBy("id ASC") .Limit(1) .AddValue("id", savedQueryId); SavedQueryPage page = reportService.getSavedQueriesByStatement(statementBuilder.ToStatement()); SavedQuery savedQuery = page.results[0]; if (!savedQuery.isCompatibleWithApiVersion) { throw new InvalidOperationException("Saved query is not compatible with this " + "API version"); } // Optionally modify the query. ReportQuery reportQuery = savedQuery.reportQuery;
Ruby
statement = dfp.new_statement_builder do |sb| sb.where = 'id = :saved_query_id' sb.with_bind_variable('saved_query_id', saved_query_id) end saved_query_page = report_service.get_saved_queries_by_statement( statement.to_statement() ) unless saved_query_page[:results].nil? saved_query = saved_query_page[:results].first if saved_query[:is_compatible_with_api_version] # Create report job. report_job = {:report_query => saved_query[:report_query]} else raise StandardError, 'Report query is not compatible with the API' end
クエリを実行するには、ReportJob を作成するをご覧ください。
ReportQuery を作成する
保存済みのクエリを使用する以外に、1 回限り(アドホック)の ReportQuery を作成することもできます。その場合は、レポートのディメンション、ディメンション属性、列、フィルタ、期間を設定する必要があります。次の例は、1 つのオーダーを対象とした基本的な配信レポートの作成方法を示しています。
Java
// Create report query. ReportQuery reportQuery = new ReportQuery(); reportQuery.setDimensions(new Dimension[] {Dimension.DATE, Dimension.ORDER_ID}); reportQuery.setColumns(new Column[] {Column.AD_SERVER_IMPRESSIONS, Column.AD_SERVER_CLICKS, Column.AD_SERVER_CTR, Column.AD_SERVER_CPM_AND_CPC_REVENUE}); reportQuery.setDimensionAttributes(new DimensionAttribute[] { DimensionAttribute.ORDER_TRAFFICKER, DimensionAttribute.ORDER_START_DATE_TIME, DimensionAttribute.ORDER_END_DATE_TIME}); // Create statement to filter for an order. StatementBuilder statementBuilder = new StatementBuilder() .where("ORDER_ID = :orderId") .withBindVariableValue("orderId", orderId); // Set the filter statement. reportQuery.setStatement(statementBuilder.toStatement()); // Set the start and end dates or choose a dynamic date range type. reportQuery.setDateRangeType(DateRangeType.CUSTOM_DATE); reportQuery.setStartDate( DateTimes.toDateTime("2013-05-01T00:00:00", "America/New_York").getDate()); reportQuery.setEndDate( DateTimes.toDateTime("2013-05-31T00:00:00", "America/New_York").getDate());
Python
# Create statement object to filter for an order. statement = (dfp.StatementBuilder() .Where('ORDER_ID = :id') .WithBindVariable('id', long(order_id)) .Limit(None) # No limit or offset for reports .Offset(None)) # Set the start and end dates of the report to run (past 8 days). end_date = datetime.now().date() start_date = end_date - timedelta(days=8) # Create report job. report_job = { 'reportQuery': { 'dimensions': ['ORDER_ID', 'ORDER_NAME'], 'dimensionAttributes': ['ORDER_TRAFFICKER', 'ORDER_START_DATE_TIME', 'ORDER_END_DATE_TIME'], 'statement': statement.ToStatement(), 'columns': ['AD_SERVER_IMPRESSIONS', 'AD_SERVER_CLICKS', 'AD_SERVER_CTR', 'AD_SERVER_CPM_AND_CPC_REVENUE', 'AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM'], 'dateRangeType': 'CUSTOM_DATE', 'startDate': start_date, 'endDate': end_date } }
PHP
// Create report query. $reportQuery = new ReportQuery(); $reportQuery->setDimensions( [ Dimension::ORDER_ID, Dimension::ORDER_NAME ] ); $reportQuery->setDimensionAttributes( [ DimensionAttribute::ORDER_TRAFFICKER, DimensionAttribute::ORDER_START_DATE_TIME, DimensionAttribute::ORDER_END_DATE_TIME ] ); $reportQuery->setColumns( [ Column::AD_SERVER_IMPRESSIONS, Column::AD_SERVER_CLICKS, Column::AD_SERVER_CTR, Column::AD_SERVER_CPM_AND_CPC_REVENUE, Column::AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM ] ); // Create statement to filter for an order. $statementBuilder = (new StatementBuilder())->where('ORDER_ID = :orderId') ->withBindVariableValue( 'orderId', $orderId ); // Set the filter statement. $reportQuery->setStatement($statementBuilder->toStatement()); // Set the start and end dates or choose a dynamic date range type. $reportQuery->setDateRangeType(DateRangeType::CUSTOM_DATE); $reportQuery->setStartDate( DfpDateTimes::fromDateTime( new DateTime( '-10 days', new DateTimeZone('America/New_York') ) ) ->getDate() ); $reportQuery->setEndDate( DfpDateTimes::fromDateTime( new DateTime( 'now', new DateTimeZone('America/New_York') ) ) ->getDate() );
C#
// Create report job. ReportJob reportJob = new ReportJob(); reportJob.reportQuery = new ReportQuery(); reportJob.reportQuery.dimensions = new Dimension[] { Dimension.ORDER_ID, Dimension.ORDER_NAME }; reportJob.reportQuery.dimensionAttributes = new DimensionAttribute[] { DimensionAttribute.ORDER_TRAFFICKER, DimensionAttribute.ORDER_START_DATE_TIME, DimensionAttribute.ORDER_END_DATE_TIME}; reportJob.reportQuery.columns = new Column[] {Column.AD_SERVER_IMPRESSIONS, Column.AD_SERVER_CLICKS, Column.AD_SERVER_CTR, Column.AD_SERVER_CPM_AND_CPC_REVENUE, Column.AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM}; // Set a custom date range for the last 8 days reportJob.reportQuery.dateRangeType = DateRangeType.CUSTOM_DATE; System.DateTime endDateTime = System.DateTime.Now; reportJob.reportQuery.startDate = DateTimeUtilities.FromDateTime(endDateTime.AddDays(-8), "America/New_York").date; reportJob.reportQuery.endDate = DateTimeUtilities.FromDateTime(endDateTime, "America/New_York").date; // Create statement object to filter for an order. StatementBuilder statementBuilder = new StatementBuilder() .Where("ORDER_ID = :id") .AddValue("id", orderId); reportJob.reportQuery.statement = statementBuilder.ToStatement();
Ruby
# Specify a report to run for the last 7 days. report_end_date = dfp.today() report_start_date = report_end_date - 7 # Create statement object to filter for an order. statement = dfp.new_report_statement_builder do |sb| sb.where = 'ORDER_ID = :order_id' sb.with_bind_variable('order_id', order_id) end # Create report query. report_query = { :date_range_type => 'CUSTOM_DATE', :start_date => report_start_date.to_h, :end_date => report_end_date.to_h, :dimensions => ['ORDER_ID', 'ORDER_NAME'], :dimension_attributes => ['ORDER_TRAFFICKER', 'ORDER_START_DATE_TIME', 'ORDER_END_DATE_TIME'], :columns => ['AD_SERVER_IMPRESSIONS', 'AD_SERVER_CLICKS', 'AD_SERVER_CTR', 'AD_SERVER_CPM_AND_CPC_REVENUE', 'AD_SERVER_WITHOUT_CPD_AVERAGE_ECPM'], :statement => statement.to_statement() }
ReportJob を作成する
ReportQuery を作成したら、次はレポートの実行です。ReportJob オブジェクトではレポートのステータスを確認することができるため、ダウンロードの準備が整ったかどうかを把握することが可能です。レポートの実行を開始するには、ReportService.runReportJob メソッドを使用します。
Java
// Create report job. ReportJob reportJob = new ReportJob(); reportJob.setReportQuery(reportQuery); // Run report job. reportJob = reportService.runReportJob(reportJob);
Python
# Initialize a DataDownloader. report_downloader = client.GetDataDownloader(version='v201805') try: # Run the report and wait for it to finish. report_job_id = report_downloader.WaitForReport(report_job) except errors.DfpReportError, e: print 'Failed to generate report. Error was: %s' % e
PHP
// Create report job and start it. $reportJob = new ReportJob(); $reportJob->setReportQuery($reportQuery); $reportJob = $reportService->runReportJob($reportJob);
C#
// Run report job. reportJob = reportService.runReportJob(reportJob);
Ruby
# Create report job. report_job = {:report_query => report_query} # Run report job. report_job = report_service.run_report_job(report_job);
レポートをダウンロードする
レポートジョブの開始後、サーバーによってジョブ ID が設定されます。レポートのステータスを確認するには、この ID と ReportService.getReportJobStatus メソッドを使用します。ステータスが ReportJobStatus.COMPLETED になったらレポートをダウンロードできます。
一部のクライアント ライブラリには、API をポーリングしてレポートの完了を待機する補助ユーティリティが含まれています。レポートが完了したら、ReportService.getReportDownloadURL メソッドを使ってダウンロード URL を取得できます。ダウンロード可能な形式はいくつかあります。レポートをさらに加工する場合は、CSV_DUMP 形式を使用します。
Java
// Create report downloader. ReportDownloader reportDownloader = new ReportDownloader(reportService, reportJob.getId()); // Wait for the report to be ready. reportDownloader.waitForReportReady(); // Change to your file location. File file = File.createTempFile("delivery-report-", ".csv.gz"); System.out.printf("Downloading report to %s ...", file.toString()); // Download the report. ReportDownloadOptions options = new ReportDownloadOptions(); options.setExportFormat(ExportFormat.CSV_DUMP); options.setUseGzipCompression(true); URL url = reportDownloader.getDownloadUrl(options); Resources.asByteSource(url).copyTo(Files.asByteSink(file)); System.out.println("done.");
Python
# Change to your preferred export format. export_format = 'CSV_DUMP' report_file = tempfile.NamedTemporaryFile(suffix='.csv.gz', delete=False) # Download report data. report_downloader.DownloadReportToFile( report_job_id, export_format, report_file) report_file.close() # Display results. print 'Report job with id "%s" downloaded to:\n%s' % ( report_job_id, report_file.name)
PHP
// Create report downloader to poll report's status and download when ready. $reportDownloader = new ReportDownloader($reportService, $reportJob->getId()); if ($reportDownloader->waitForReportToFinish()) { // Write to system temp directory by default. $filePath = sprintf( '%s.csv.gz', tempnam(sys_get_temp_dir(), 'delivery-report-') ); printf("Downloading report to %s ...\n", $filePath); // Download the report. $reportDownloader->downloadReport(ExportFormat::CSV_DUMP, $filePath); print "done.\n"; } else { print "Report failed.\n"; }
C#
ReportUtilities reportUtilities = new ReportUtilities(reportService, reportJob.id); // Set download options. ReportDownloadOptions options = new ReportDownloadOptions(); options.exportFormat = ExportFormat.CSV_DUMP; options.useGzipCompression = true; reportUtilities.reportDownloadOptions = options; // Download the report. using (ReportResponse reportResponse = reportUtilities.GetResponse()) { reportResponse.Save(filePath); } Console.WriteLine("Report saved to \"{0}\".", filePath);
Ruby
MAX_RETRIES.times do |retry_count| # Get the report job status. report_job_status = report_service.get_report_job_status(report_job[:id]) break unless report_job_status == 'IN_PROGRESS' puts 'Report with ID %d is still running.' % report_job[:id] sleep(RETRY_INTERVAL) end puts 'Report job with ID %d finished with status "%s".' % [report_job[:id], report_service.get_report_job_status(report_job[:id])] # Get the report URL. download_url = report_service.get_report_download_url( report_job_id, export_format ) puts 'Downloading "%s" to "%s"...' % [download_url, file_name] open(file_name, 'wb') do |local_file| local_file << open(download_url).read() end
レポートのデータを読み取る
クライアント ライブラリの多くには、レポートのデータを読み取るためのユーティリティが含まれています。これは、レポートのデータをさらに加工したり、別の期間のレポートと組み合わせたりする場合に便利です。次のコード例は、ファイルが圧縮されていないことを前提としたものです。
Java
Listrows = CsvFiles.getCsvDataArray(filePath, true); for (String[] row : rows) { // Additional row processing processReportRow(row); }
Python
with open(report_file.name, 'rb') as report: report_reader = csv.reader(report) for row in report_reader: # Additional row processing process_row(row)
PHP
$report = fopen($filePath, 'r'); while (!feof($report)) { // Additional row processing processRow(fgetcsv($report)); } fclose($report);
C#
CsvFile file = new CsvFile(); file.Read(fileName, true); for (String[] row : file.Records) { // Additional row processing ProcessReportRow(row); }
Ruby
CSV.foreach(file_name, converters: :numeric, headers: true) do |row| # Additional row processing process_row(row) end
他のレポート例については、GitHub のクライアント ライブラリをご覧ください。
よくある質問
テスト ネットワークのレポートがすべて空白になるのはなぜですか?
テスト ネットワークでは広告が配信されないため、配信レポートにはデータが表示されません。
レポートで ReportError.COLUMNS_NOT_SUPPORTED_FOR_REQUESTED_DIMENSIONS
エラーが返されるのはなぜですか?
列とディメンションの組み合わせが DFP でサポートされていない可能性があります。複雑なレポートの場合は、管理画面で有効なクエリを作成してから ReportService.getSavedQueriesByStatement メソッドを使ってそのクエリを取得すると、作業が簡単になることがあります。
保存したクエリが API に対応していないのはなぜですか?
一部のレポート機能は API では使用できません。これには、列、ディメンション属性、ディメンション、期間タイプが含まれます。サポートされていない期間タイプをクエリで使用している場合は、サポートされている期間タイプに変更して保存すると、クエリを取得可能になります。次に、クエリを編集し、希望する固定期間を指定してください。
全期間のクリック数やインプレッション数が、管理画面で作成したレポートと一致しないのはどうしてですか?
全期間のインプレッション数とは、広告申込情報の全期間に発生したインプレッション数であり、レポートの期間には関係ありません。広告申込情報が配信中の場合は、実行した 2 つのレポートでインプレッション数が異なる可能性は大いにあります。
レポートの実行に時間がかかりすぎ、タイムアウトになることもあります。どうしたらよいですか?
期間を短くするか、ディメンションの数を少なくすると、パフォーマンスが改善されます。レポートを短い期間に区切って複数回実行し、それらのデータを合わせて必要な期間のレポートにすることができます。
INVENTORY_LEVEL
列と LINE_ITEM_LEVEL
列の違いは何ですか?どちらを使用したらよいでしょうか?
ネットワークで、広告申込情報単位のダイナミック アロケーションを有効にしている場合、使用できるのは LINE_ITEM_LEVEL
の列のみです。この列には、広告申込情報単位のダイナミック アロケーションを通じて AdSense または Ad Exchange に送信されたデータが含まれます。同様に、INVENTORY_LEVEL
の列には広告枠単位のダイナミック アロケーションから発生したデータが含まれます。ダイナミック アロケーションについて詳しくは、ヘルプセンターのこちらの記事をご覧ください。
どちらの API 列を使用すればよいか判断しかねる場合は、DFP 管理画面でクエリを作成して保存し、ReportService.getSavedQueriesByStatement メソッドを使ってそのクエリを取得してください。