Introducción
En esta guía, se indica cómo ejecutar y descargar un informe con la API. Abarca tanto el uso de una consulta de informe guardado existente como la creación de una consulta de informe ad hoc.
Requisitos previos
- Acceso a una red de producción de Google Ad Manager
- Una biblioteca cliente de Ad Manager
Primer
Si no estás familiarizado con los informes de Ad Manager, consulta Cómo crear un informe nuevo para obtener una descripción general de cómo ejecutar un informe en la IU de Ad Manager. La IU tiene una vista previa del resultado, además de información sobre la herramienta que explica qué combinaciones de columnas y dimensiones se admiten. Cuando creas una consulta de informe compleja, puede ser más fácil crearla primero en la IU y, luego, recuperar la consulta con la API.
Cómo recuperar un ReportQuery guardado
El objeto ReportQuery contiene todos los detalles del informe. Puedes crear consultas de informes en la IU de Ad Manager y recuperarlas con el método ReportService.getSavedQueriesByStatement. El ID de la consulta guardada se incluye en la URL cuando se visualiza una consulta en la IU. Por ejemplo, en la URL https://www.google.com/admanager/1234#reports/report/detail/report_id=456789
, el ID de la consulta es 456789
.
Si una consulta no es compatible con la versión de tu API, SavedQuery.reportQuery será null
y SavedQuery.isCompatibleWithApiVersion será false
.
Las consultas guardadas compatibles se pueden ejecutar con o sin modificaciones.
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
Para ejecutar la consulta, consulta Crea el ReportJob.
Cómo crear una ReportQuery
Además de usar consultas guardadas, también puedes crear una ReportQuery ad hoc. Para hacerlo, debes configurar las dimensiones, los atributos de dimensión, las columnas, el filtro y el período del informe. Este ejemplo corresponde a un informe de publicación básico sobre un solo pedido.
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 } }
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( 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() }
Cómo crear el ReportJob
Una vez que tengas un ReportQuery, es el momento de ejecutar el informe. El objeto ReportJob conserva el estado de un informe y te avisa cuando está listo para descargarlo. Para comenzar a ejecutar tu informe, usa el método 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)
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);
Cómo descargar el informe
Después de iniciar el trabajo de informe, el servidor establecerá un ID. Usa este ID con el método ReportService.getReportJobStatus para verificar el estado de tu informe. Una vez que el estado sea ReportJobStatus.COMPLETED, el informe estará listo para descargar.
Algunas de nuestras bibliotecas cliente tienen utilidades auxiliares que sondearán la API y esperarán a que se complete el informe. Cuando se complete el informe, podrás obtener la URL de descarga con el método ReportService.getReportDownloadURL. Se puede descargar un informe en diferentes formatos. Si deseas realizar más procesamiento automático con el informe, debes usar el formato 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))
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 ...%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
Lectura de los datos del informe
Muchas de nuestras bibliotecas cliente incluyen utilidades para leer datos de informes. Esto es útil para realizar un procesamiento adicional de los datos de informes o combinar informes de diferentes períodos. Ten en cuenta que, en el código de ejemplo, se supone que el archivo no está comprimido.
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
Para ver más ejemplos de informes, consulta nuestras bibliotecas cliente en GitHub.
Preguntas frecuentes
- ¿Por qué están vacíos todos los resultados del informe en mi red de prueba?
- Las redes de prueba no publican anuncios, por lo que los informes de publicación no tienen datos.
- ¿Por qué están vacíos todos los resultados del informe en mi red de producción?
- Es posible que el usuario que estás autenticando no tenga acceso a los datos sobre los que intentas informar. Verifica que los permisos de función y los equipos estén configurados de forma correcta.
- ¿Por qué recibo el error
ReportError.COLUMNS_NOT_SUPPORTED_FOR_REQUESTED_DIMENSIONS
en mi informe? - No todas las combinaciones de columnas y dimensiones se admiten en Ad Manager. Para informes complejos, puede ser más fácil compilar un informe válido en la IU y, luego, recuperarlo con el método ReportService.getSavedQueriesByStatement.
- ¿Por qué no se muestra mi informe guardado en la API?
- Asegúrate de que el propietario del informe lo haya compartido con el usuario que te autenticas.
- ¿Por qué mi informe guardado no es compatible con la API?
- Algunas funciones de informes no están disponibles en la API. Esto incluye columnas, atributos de dimensión, dimensiones y tipos de período. En el caso de los tipos de períodos incompatibles, puedes guardar el informe con un tipo admitido para que sea recuperable y, luego, modificar
ReportQuery
para cumplir con el período fijo deseado. - ¿Por qué los clics o las impresiones desde el principio no coinciden con mi informe de la IU?
- Las impresiones desde el principio corresponden a toda la vida útil de la línea de pedido, sin importar el período del informe. Si una línea de pedido aún se está publicando, es probable que el valor cambie entre ejecutar dos informes cualesquiera.
- Mis informes tardan demasiado y, en ocasiones, se agota el tiempo de espera. ¿Qué puedo hacer?
- Disminuir el período o la cantidad de dimensiones ayudará a mejorar el rendimiento. En su lugar, ejecute varios informes para períodos más pequeños. Luego, puedes combinar los datos del informe para abarcar el período deseado.
- ¿Cuál es la diferencia entre las columnas
INVENTORY_LEVEL
yLINE_ITEM_LEVEL
? ¿Cuál debo usar? Las columnas con
LINE_ITEM_LEVEL
solo se pueden usar si tienes habilitada la asignación dinámica a nivel de la línea de pedido en tu red. Estas columnas incluyen datos de la asignación dinámica a nivel de línea de pedido a AdSense o Ad Exchange. De manera similar, las columnasINVENTORY_LEVEL
incluyen datos de la asignación dinámica del nivel de inventario. Para obtener más información sobre la asignación dinámica, consulta Líneas de pedido de Ad Exchange.Si aún no sabes qué columnas de la API usar, crea una consulta guardada en la IU de Ad Manager y recupérala con el método ReportService.getSavedQueriesByStatement.