أساسيات إعداد التقارير

مقدمة

سيوضّح لك هذا الدليل كيفية تشغيل تقرير وتنزيله باستخدام واجهة برمجة التطبيقات. ويتناول كلاً من استخدام طلب تقرير محفوظ حالي، وإنشاء طلب تقرير مخصّص.

المتطلبات الأساسية

  • الوصول إلى شبكة "مدير إعلانات Google" في قناة الإصدار العلني
  • مكتبة عملاء في "مدير إعلانات Google"

Primer

إذا لم تكن على دراية بإعداد التقارير في "مدير إعلانات Google"، اطّلِع على مقالة إنشاء تقرير جديد للحصول على نظرة عامة حول كيفية عرض تقرير في واجهة مستخدم "مدير إعلانات Google". تحتوي واجهة المستخدم على معاينة الأخرى، بالإضافة إلى تلميحات تشرح مجموعات الأعمدة والأبعاد عند إنشاء طلب تقرير معقد، قد يكون من الأسهل إنشاؤه في واجهة المستخدم أولاً، ثم استرداد الاستعلام باستخدام واجهة برمجة التطبيقات.

استرداد طلب بحث محفوظ

يمثِّل ReportQuery على جميع تفاصيل التقرير. يمكنك إنشاء طلبات بحث التقارير في واجهة مستخدم مدير الإعلانات، واستردادها باستخدام ReportService.getSavedQueriesByStatement . يتم تضمين معرّف طلب البحث المحفوظ في عنوان URL عند عرض طلب بحث في واجهة مستخدم على سبيل المثال، في عنوان URL https://www.google.com/admanager/1234#reports/report/detail/report_id=456789 معرف طلب البحث هو 456789.

إذا لم يكن طلب البحث متوافقًا مع إصدار واجهة برمجة التطبيقات، سيكون null هو قيمة SavedQuery.reportQuery وfalse هي قيمة SavedQuery.isCompatibleWithApiVersion .

يمكن تنفيذ الطلبات المحفوظة المتوافقة مع التعديل أو بدونه.

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='v202408')
               .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.

إنشاء تقرير استعلام

إضافةً إلى استخدام طلبات البحث المحفوظة، يمكنك أيضًا إنشاء طلب بحث مخصّص. ولإجراء ذلك، عليك ضبط تسلسل استدعاء الدوال البرمجية للتقرير السمات، سمة والسمات، الأعمدة والتصفية النطاق الزمني. هذا المثال مخصَّص لتقرير تسليم أساسي لطلب واحد.

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='v202408')
               .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 .

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='v202408')

  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 .

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
    

قراءة بيانات التقرير

تتضمّن العديد من مكتبات العملاء أدوات لقراءة بيانات التقارير. هذا هو لإجراء معالجة إضافية لبيانات التقرير أو دمج التقارير من نطاقات زمنية مختلفة لاحظ أن مثال التعليمة البرمجية يفترض أن الملف ليس مضغوطًا.

Java

  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:

إذا لم تكن متأكّدًا من أعمدة واجهة برمجة التطبيقات التي يجب استخدامها، أنشئ طلب بحث محفوظًا في واجهة مستخدم Ad Manager واسترِده باستخدام الأسلوب ReportService.getSavedQueriesByStatement .