소개
이 가이드에서는 API를 사용하여 보고서를 실행하고 다운로드하는 방법을 설명합니다. 기존에 저장된 보고서 쿼리를 사용하는 방법과 임시 보고서 쿼리를 만드는 방법을 모두 다룹니다.
기본 요건
- 프로덕션 Google Ad Manager 네트워크 액세스
- Ad Manager 클라이언트 라이브러리
Primer
Ad Manager의 보고에 익숙하지 않다면 새 보고서 만들기에서 Ad Manager UI에서 보고서를 실행하는 방법에 관한 개요를 확인하세요. UI에는 출력 미리보기와 지원되는 열 및 측정기준 조합을 설명하는 도움말이 제공됩니다. 복잡한 보고서 쿼리를 만드는 경우 먼저 UI에서 쿼리를 만든 후 API를 사용하여 쿼리를 검색하는 것이 더 쉬울 수 있습니다.
저장된 ReportQuery 검색
ReportQuery 객체에는 보고서의 모든 세부정보가 포함됩니다. Ad Manager UI에서 보고서 쿼리를 만들고 ReportService.getSavedQueriesByStatement 메서드를 사용하여 쿼리를 검색할 수 있습니다. 저장된 쿼리 ID는 UI에서 쿼리를 볼 때 URL에 포함됩니다. 예를 들어 URL https://www.google.com/admanager/1234#reports/report/detail/report_id=456789
에서 쿼리 ID는 456789
입니다.
쿼리가 API 버전과 호환되지 않는 경우 SavedQuery.reportQuery는 null
가 되고 SavedQuery.isCompatibleWithApiVersion이 false
가 됩니다.
호환되는 저장된 쿼리는 수정 여부와 관계없이 실행할 수 있습니다.
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 = (ad_manager.StatementBuilder(version='v202402') .Where('id = :id') .WithBindVariable('id', int(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 = ad_manager.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 빌드
저장된 쿼리를 사용하는 것 외에 임시 ReportQuery를 만들 수도 있습니다. 이렇게 하려면 보고서의 측정기준, 측정기준 속성, 열, 필터, 기간을 설정해야 합니다. 다음은 단일 주문에 대한 기본 전송 보고서 예시입니다.
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 = (ad_manager.StatementBuilder(version='v202402') .Where('ORDER_ID = :id') .WithBindVariable('id', int(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 } }
2,399필리핀
// 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( AdManagerDateTimes::fromDateTime( new DateTime( '-10 days', new DateTimeZone('America/New_York') ) ) ->getDate() ); $reportQuery->setEndDate( AdManagerDateTimes::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 = ad_manager.today() report_start_date = report_end_date - 7 # Create statement object to filter for an order. statement = ad_manager.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='v202402') try: # Run the report and wait for it to finish. report_job_id = report_downloader.WaitForReport(report_job) except errors.AdManagerReportError as e: print('Failed to generate report. Error was: %s' % e)
2,399필리핀
// 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. if (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."); } else { System.out.printf("Report job %d failed.%n", reportJob.getId()); }
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))
2,399필리핀
// 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 ...%s", $filePath, PHP_EOL); // 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)
2,399필리핀
$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의 클라이언트 라이브러리를 확인하세요.
FAQ
- 테스트 네트워크의 모든 보고서 결과가 비어 있는 이유는 무엇인가요?
- 테스트 네트워크에서는 광고를 게재하지 않으므로 게재 보고서에는 데이터가 포함되지 않습니다.
- 프로덕션 네트워크의 모든 보고서 결과가 비어 있는 이유는 무엇인가요?
- 인증하는 사용자에게 보고하려는 데이터에 대한 액세스 권한이 없을 수 있습니다. 역할 권한 및 팀이 올바르게 설정되어 있는지 확인합니다.
- 보고서에
ReportError.COLUMNS_NOT_SUPPORTED_FOR_REQUESTED_DIMENSIONS
오류가 표시되는 이유는 무엇인가요? - Ad Manager에서는 열과 측정기준의 모든 조합이 지원되지 않습니다. 복잡한 보고서의 경우 UI에서 유효한 보고서를 빌드한 후 ReportService.getSavedQueriesByStatement 메서드를 사용하여 보고서를 검색하는 것이 더 쉬울 수 있습니다.
- 저장된 보고서가 API에서 반환되지 않는 이유는 무엇인가요?
- 보고서 소유자가 내가 인증하는 사용자와 보고서를 공유했는지 확인합니다.
- 저장된 보고서가 API와 호환되지 않는 이유는 무엇인가요?
- 일부 보고 기능은 API에서 지원되지 않습니다. 여기에는 열, 측정기준 속성, 측정기준, 기간 유형이 포함됩니다. 호환되지 않는 기간 유형의 경우 지원되는 유형으로 보고서를 저장하여 검색할 수 있도록 한 다음
ReportQuery
를 원하는 고정 기간에 맞게 변경할 수 있습니다. - 전체 기간 클릭수/노출수가 UI의 내 보고서와 일치하지 않는 이유는 무엇인가요?
- 평생 노출수는 보고서 기간에 관계없이 광고 항목의 전체 기간 동안 집계됩니다. 광고 항목이 아직 게재되고 있는 경우 두 보고서 실행 사이에 값이 변경될 수 있습니다.
- 보고서가 너무 오래 걸리고 가끔 시간이 초과됩니다. 어떻게 해야 할까요?
- 기간 또는 측정기준 수를 줄이면 실적을 개선하는 데 도움이 됩니다. 대신 더 짧은 기간에 대해 여러 개의 보고서를 실행해 보세요. 그런 다음 원하는 기간을 포함하도록 보고서 데이터를 병합할 수 있습니다.
INVENTORY_LEVEL
열과LINE_ITEM_LEVEL
열의 차이점은 무엇인가요? 어떤 것을 사용해야 하나요?LINE_ITEM_LEVEL
가 있는 열은 네트워크에서 광고 항목 수준의 동적 할당을 사용 설정한 경우에만 사용할 수 있습니다. 이 열에는 애드센스 또는 Ad Exchange로의 광고 항목 수준 동적 할당 데이터가 포함됩니다. 마찬가지로INVENTORY_LEVEL
열에는 인벤토리 수준 동적 할당의 데이터가 포함됩니다. 동적 할당에 대해 자세히 알아보려면 Ad Exchange 광고 항목을 참조하세요.어떤 API 열을 사용해야 할지 잘 모르겠다면 Ad Manager UI에 저장된 쿼리를 만들고 ReportService.getSavedQueriesByStatement 메서드를 사용하여 쿼리를 가져오세요.