مقدمة
سيوضّح لك هذا الدليل كيفية إنشاء تقرير وتنزيله باستخدام واجهة برمجة التطبيقات. ويتناول كلاً من استخدام طلب بحث تقرير محفوظ حالي وإنشاء طلب بحث تقرير مخصّص.
المتطلبات الأساسية
- الوصول إلى شبكة "إدارة إعلانات Google" للإنتاج
- مكتبة برامج "مدير إعلانات Google"
Primer
إذا لم تكن على دراية بإعداد التقارير في "مدير الإعلانات"، يمكنك الاطّلاع على مقالة إنشاء تقرير جديد للحصول على نظرة عامة حول كيفية تنفيذ تقرير في واجهة مستخدم "مدير الإعلانات". تتضمّن واجهة المستخدم معاينة للنتائج، بالإضافة إلى تلميحات تشرح مجموعات الأعمدة والسمات المتاحة. عند إنشاء طلب بحث معقّد لتقرير، قد يكون من الأسهل إنشاؤه في واجهة المستخدم أولاً، ثم استرداد طلب البحث باستخدام واجهة برمجة التطبيقات.
استرداد ReportQuery محفوظ
يحتوي العنصر ReportQuery على جميع تفاصيل التقرير. يمكنك إنشاء طلبات بحث للتقارير في واجهة مستخدم "إدارة إعلانات Google" واستردادها باستخدام طريقة ReportService.getSavedQueriesByStatement. يتم تضمين رقم تعريف طلب البحث المحفوظ في عنوان URL عند عرض طلب بحث في
واجهة المستخدم. على سبيل المثال، في عنوان URL
https://www.google.com/admanager/1234#reports/report/detail/report_id=456789
يكون رقم تعريف طلب البحث هو 456789.
إذا لم يكن طلب البحث متوافقًا مع إصدار واجهة برمجة التطبيقات، ستكون قيمة SavedQuery.reportQuery هي null وستكون قيمة SavedQuery.isCompatibleWithApiVersion هي false.
يمكن تشغيل طلبات البحث المحفوظة المتوافقة مع تعديل أو بدونه.
جافا
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='v202608') .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). لإجراء ذلك، عليك ضبط سمات التقرير وسمات السمة والأعمدة والفلتر والنطاق الزمني. هذا المثال مخصّص لتقرير تسليم أساسي لطلب واحد.
جافا
// 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='v202608') .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() }
إنشاء ReportJob
بعد الحصول على ReportQuery، يحين وقت تنفيذ التقرير. يحتوي العنصر ReportJob على حالة التقرير، ويُعلمك عندما يصبح جاهزًا للتنزيل. لبدء تنفيذ تقريرك، استخدِم طريقة ReportService.runReportJob.
جافا
// 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='v202608') 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);
تنزيل التقرير
بعد بدء مهمة التقرير، سيكون لها معرّف يحدّده الخادم. استخدِم هذا المعرّف مع طريقة ReportService.getReportJobStatus للتحقّق من حالة تقريرك. عندما تصبح الحالة ReportJobStatus.COMPLETED، يكون التقرير جاهزًا للتنزيل.
تتضمّن بعض مكتبات العملاء أدوات مساعدة ستستطلع واجهة برمجة التطبيقات وتنتظر اكتمال التقرير. عند اكتمال التقرير، يمكنك الحصول على عنوان URL للتنزيل باستخدام طريقة ReportService.getReportDownloadURL. يمكن تنزيل التقرير بتنسيقات مختلفة. إذا أردت إجراء المزيد من المعالجة الآلية للتقرير، عليك استخدام تنسيق CSV_DUMP.
جافا
// 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 << URI.open(download_url).read() end
قراءة بيانات التقرير
تتضمّن العديد من مكتبات العملاء أدوات مساعدة لقراءة بيانات التقارير. ويُعدّ ذلك مفيدًا لإجراء معالجة إضافية لبيانات التقارير أو دمج التقارير من نطاقات زمنية مختلفة. يُرجى العِلم أنّ الرمز البرمجي في المثال يفترض أنّ الملف غير مضغوط.
جافا
List<String[]> rows = 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في تقريري؟ - لا تتوفّر بعض مجموعات الأعمدة والسمات في "مدير إعلانات Google". بالنسبة إلى التقارير المعقّدة، قد يكون من الأسهل إنشاء تقرير صالح في واجهة المستخدم ثم استرداده باستخدام طريقة ReportService.getSavedQueriesByStatement.
- لماذا لا يظهر تقريري المحفوظ في واجهة برمجة التطبيقات؟
- تأكَّد من أنّ مالك التقرير قد شارك التقرير مع المستخدم الذي تتم مصادقته.
- لماذا لا يتوافق تقريري المحفوظ مع واجهة برمجة التطبيقات؟
- بعض ميزات إعداد التقارير غير متاحة في واجهة برمجة التطبيقات. ويشمل ذلك الأعمدة وسمات السمات والسمات وأنواع النطاقات الزمنية. بالنسبة إلى أنواع النطاقات الزمنية غير المتوافقة، يمكنك حفظ التقرير بنوع متوافق لجعله قابلاً للاسترداد، ثم تعديل
ReportQueryليتوافق مع النطاق الزمني الثابت المطلوب. - لماذا لا تتطابق النقرات/مرات الظهور على مدار الفترة مع تقريري في واجهة المستخدم؟
- مرّات الظهور خلال الفترة منذ الإنشاء هي مرّات الظهور طوال فترة عرض البند الإعلاني، بغض النظر عن النطاق الزمني للتقرير. إذا كان تفصيل الإعلان لا يزال قيد العرض، من المحتمل أن تتغيّر القيمة بين تشغيل أي تقريرَين.
- تستغرق تقاريري وقتًا طويلاً وتنتهي مهلتها أحيانًا. ما الذي يمكنني فعله؟
- سيساعد تقليل النطاق الزمني أو عدد السمات في تحسين الأداء. بدلاً من ذلك، حاوِل إنشاء تقارير متعددة لنطاقات زمنية أصغر. يمكنك بعد ذلك دمج بيانات التقارير لتغطية النطاق الزمني المطلوب.
- ما الفرق بين عمودَي "
INVENTORY_LEVEL" و"LINE_ITEM_LEVEL"؟ أيّ منهما عليّ استخدامه؟ لا يمكن استخدام الأعمدة التي تحتوي على
LINE_ITEM_LEVELإلا إذا كان لديك تخصيص ديناميكي على مستوى البند الإعلاني مفعَّل على شبكتك. تتضمّن هذه الأعمدة بيانات من التخصيص الديناميكي على مستوى تفاصيل الإعلان في AdSense أو Ad Exchange. وبالمثل، تتضمّن أعمدةINVENTORY_LEVELبيانات من التخصيص الديناميكي على مستوى المستودع. لمزيد من المعلومات عن التخصيص الديناميكي، يُرجى الاطّلاع على البنود الإعلانية في Ad Exchange.إذا لم تكن متأكدًا من أعمدة واجهة برمجة التطبيقات التي يجب استخدامها، يمكنك إنشاء طلب بحث محفوظ في واجهة مستخدم "إدارة إعلانات Google" واسترداده باستخدام طريقة ReportService.getSavedQueriesByStatement.