درخواست های ناهمزمان

API جدید Search Ads 360 Reporting اکنون در دسترس است. API جدید انعطاف‌پذیری بیشتری برای ایجاد گزارش‌های سفارشی و ادغام داده‌ها در برنامه‌ها و فرآیندهای گزارش‌دهی شما فراهم می‌کند. درباره انتقال و استفاده از Search Ads 360 Reporting API جدید بیشتر بیاموزید.

از آنجایی که تولید درخواست‌های گزارش‌های بزرگ ممکن است کمی طول بکشد، Search Ads 360 API یک تکنیک ناهمزمان برای درخواست و دانلود گزارش‌ها ارائه می‌کند. با این تکنیک، یک درخواست اولیه ارسال می‌کنید که داده‌های مورد نظرتان را در گزارش مشخص می‌کند، و سپس درخواست‌های نظرسنجی اضافی را ارسال می‌کنید تا زمانی که Search Ads 360 تولید گزارش را به پایان برساند. بسته به اندازه گزارش، Search Ads 360 داده ها را به چندین فایل تقسیم می کند. پس از ایجاد گزارش، درخواست هایی برای دانلود هر فایل گزارش ارسال می کنید. اگر حجم کمتری از داده را درخواست می‌کنید، می‌توانید فقط یک درخواست همزمان ارسال کنید.

برای ایجاد یک درخواست ناهمزمان

  1. برای تعیین نوع داده مورد نظر در گزارش Reports.request() فراخوانی کنید. برای انواع داده هایی که می توانید درخواست کنید، به انواع گزارش مراجعه کنید.

    Search Ads 360 درخواست را تأیید می کند و یک شناسه گزارش را برمی گرداند - یک شناسه منحصر به فرد برای این درخواست.

  2. با Reports.get() با شناسه گزارش تماس بگیرید.

    پاسخ از Search Ads 360 نشان می دهد:

    • آیا گزارش برای دانلود آماده است یا خیر.
    • اگر گزارش آماده است، یک یا چند URL برای دانلود گزارش.
  3. برای دانلود فایل های گزارش کدگذاری شده، یا فقط مستقیماً از URL ها دانلود کنید، با Reports.getFile() تماس بگیرید.

    Search Ads 360 گزارش را در یک فایل رمزگذاری شده UTF-8 برمی گرداند.

چند بار باید گزارش‌های نظرسنجی را انجام دهم تا ببینم آیا آماده هستند؟

مدت زمانی که Search Ads 360 برای تولید یک گزارش نیاز دارد، بیشتر به میزان داده های موجود در گزارش بستگی دارد. در هر دقیقه یک بار نظرسنجی را برای وضعیت گزارش امتحان کنید، و سپس اگر متوسط ​​درخواست گزارش شما به طور قابل توجهی زمان بیشتری یا کمتری برای تکمیل نیاز دارد، فرکانس را تنظیم کنید.

تقسیم گزارش های ناهمزمان به چندین فایل

در پاسخ به یک درخواست ناهمزمان، Search Ads 360 به طور خودکار گزارش های بزرگ را به چندین فایل تقسیم می کند. از ویژگی Reports.request.maxRowsPerFile برای تعیین حداکثر اندازه فایل استفاده کنید. هر فایل گزارش حاصل تضمین می‌شود که حداکثر ردیف‌های گزارش maxRowsPerFile (بدون احتساب سرصفحه‌ها) داشته باشد. یک URL متفاوت برای هر فایل ایجاد می شود و در پاسخ به Reports.get() بازگردانده می شود. برای اطلاعات در مورد دانلود فایل های گزارش، به دانلود گزارش مراجعه کنید.

برای گزارش‌های CSV، هدر در هر فایل تکرار می‌شود.

توجه : API از صفحه بندی برای درخواست های ناهمزمان پشتیبانی نمی کند. یعنی نمی توانید مشخص کنید که می خواهید کدام ردیف ها در کدام فایل های گزارش قرار بگیرند. نحوه تقسیم ردیف ها بین فایل ها دلخواه است و در صورت اجرای مجدد همان گزارش ممکن است تغییر کند.

مثال ناهمزمان

در زیر نمونه درخواست ها و پاسخ ها با استفاده از تکنیک ناهمزمان آورده شده است.

JSON

POST  https://www.googleapis.com/doubleclicksearch/v2/reports
Authorization: Bearer your OAuth 2.0 access token
Content-type: application/json

{
  "reportScope": {
    "agencyId": "12300000000000456", // Replace with your ID
    "advertiserId": "21700000000011523", // Replace with your ID
  },
  "reportType": "keyword",              // This report covers all keywords in the
                                        // advertiser specified in reportScope.
  "columns": [
    { "columnName": "campaignId" },     // Here are some attribute columns available for keyword
    { "columnName": "keywordText" },    // reports.
    { "columnName": "keywordLandingPage" },

    { "columnName": "date" },           // The date column segments the report by individual days.

    { "columnName": "dfaRevenue" },     // Here are some metric columns available for keyword
    {                                   // reports
      "columnName": "visits",
      "startDate": "2013-01-01",        // Each metric column can optionally specify its own start
      "endDate": "2013-01-31",          // and end date; by default the report timeRange is used.
      "headerText": "visits last month" // Every column can optionally specify a headerText, which
                                        // changes the name of the column in the report.
    }
  ],
  "timeRange" : {
    "startDate" : "2012-05-01",         // Dates are inclusive and specified in YYYY-MM-DD format.
    "endDate" : "2012-05-02"

    // Alternatively, try the "changedMetricsSinceTimestamp" or "changedAttributesSinceTimestamp"
    // options. See Incremental reports.

  },
  "filters": [
    {
      "column" : { "columnName": "keywordLandingPage" },
      "operator" : "startsWith",
      "values" : [                      // With this filter, only keywords with landing pages
        "http://www.foo.com",           // rooted at www.foo.com or www.bar.com are returned.
        "http://www.bar.com"            // See Filtered reports.
      ]
    }
  ],
  "downloadFormat": "csv",
  "maxRowsPerFile": 6000000,            // Required. See Splitting reports into multiple files.
  "statisticsCurrency": "agency",       // Required. See Currency for statistics.
  "verifySingleTimeZone": false,        // Optional. Defaults to false. See Time zone.
  "includeRemovedEntities": false           // Optional. Defaults to false.
}
          

جاوا

/**
 * Creates a campaign report request, submits the report, and returns the report ID.
 */
private static String createReport(Doubleclicksearch service) throws IOException {
  try {
     return service.reports().request(createSampleRequest()).execute().getId();
  } catch (GoogleJsonResponseException e) {
    System.err.println("Report request was rejected.");
    for (ErrorInfo error : e.getDetails().getErrors()) {
      System.err.println(error.getMessage());
    }
    System.exit(e.getStatusCode());
    return null; // Unreachable code.
  }
}

/**
 * Creates a simple static request that lists the ID and name of all
 * campaigns under agency 12300000000000456 and advertiser 21700000000011523.
 * Substitute your own agency ID and advertiser IDs for the IDs in this sample.
 */
private static ReportRequest createSampleRequest() {
  return new ReportRequest()
      .setReportScope(new ReportScope()
          .setAgencyId(12300000000000456L) // Replace with your ID
          .setAdvertiserId(21700000000011523L)) // Replace with your ID
      .setReportType("campaign")
      .setColumns(Arrays.asList(
          new ReportApiColumnSpec[] {
            new ReportApiColumnSpec().setColumnName("campaignId"),
            new ReportApiColumnSpec().setColumnName("campaign")
          }))
      .setTimeRange(new TimeRange()
          .setStartDate("2012-05-01")
          .setEndDate("2012-05-01"))
      .setDownloadFormat("csv")
      .setStatisticsCurrency("usd")
      .setMaxRowsPerFile(5000000);
}

.خالص

این تابع گزارشی ایجاد می‌کند که کمپین‌های تحت یک تبلیغ‌کننده را فهرست می‌کند و رمز برگشتی را به reportId اختصاص می‌دهد.
using api = Google.Apis.Doubleclicksearch.v2;

/// <summary>
/// Creates a report with a sample request and returns the report ID.
/// </summary>
/// <param name="service">Search Ads 360 API service.</param>
private static string CreateReport(api.DoubleclicksearchService service)
{

    var req = service.Reports.Request(CreateSampleRequest());
    var report = req.Execute();
    Console.WriteLine("Created report: ID={0}", report.Id);
    return report.Id;
}

/// <summary>
/// Returns a simple static request that lists the ID and name of all
/// campaigns under an advertiser.
/// Substitute your own agency ID and advertiser IDs for the IDs in this sample.
/// </summary>
private static api.Data.ReportRequest CreateSampleRequest()
{
    return new api.Data.ReportRequest
    {
        ReportScope = new api.Data.ReportRequest.ReportScopeData
        {
            AgencyId = 12300000000000456, // Replace with your ID
            AdvertiserId = 21700000000011523 // Replace with your ID
        },
        ReportType = ReportType.CAMPAIGN,
        Columns = new List<api.Data.ReportApiColumnSpec>
        {
            new api.Data.ReportApiColumnSpec
            {
                ColumnName = "campaignId",
            },
            new api.Data.ReportApiColumnSpec
            {
                ColumnName = "campaign",
            },
        },
        TimeRange = new api.Data.ReportRequest.TimeRangeData
        {
            StartDate = "2015-01-01",
            EndDate = "2015-01-07",
        },
        DownloadFormat = "csv",
        StatisticsCurrency = "usd",
        MaxRowsPerFile = 5000000,
    };
}

پایتون

def request_report(service):
  """Request sample report and print the report ID that DS returns. See Set Up Your Application.

  Args:
    service: An authorized Doubleclicksearch service.
  Returns:
    The report id.
  """
  request = service.reports().request(
      body=
      {
        "reportScope": {
            "agencyId": "12300000000000456", // Replace with your ID
            "advertiserId": "21700000000011523", // Replace with your ID
            "engineAccountId": "700000000073991" // Replace with your ID
            },
        "reportType": "keyword",
        "columns": [
            { "columnName": "campaignId" },
            { "columnName": "keywordText" },
            { "columnName": "keywordLandingPage" },

            { "columnName": "date" },

            { "columnName": "dfaRevenue" },
            {
              "columnName": "visits",
              "startDate": "2013-01-01",
              "endDate": "2013-01-31",
              "headerText": "visits last month"
            }
          ],
          "timeRange" : {
            "startDate" : "2012-05-01",
            "endDate" : "2012-05-02"
          },
          "filters": [
            {
              "column" : { "columnName": "keywordLandingPage" },
              "operator" : "startsWith",
              "values" : [
                "http://www.foo.com",
                "http://www.bar.com"
              ]
            }
          ],
          "downloadFormat": "csv",
          "maxRowsPerFile": 6000000,
          "statisticsCurrency": "agency",
          "verifySingleTimeZone": "false",
          "includeRemovedEntities": "false"
        }
  )

  json_data = request.execute()
  return json_data['id']

در صورت موفقیت آمیز بودن اعتبار سنجی

اگر گزارش تأیید اعتبار را تأیید کند، Search Ads 360 یک شناسه گزارش را برمی‌گرداند. Search Ads 360 همچنین ابرداده‌های مربوط به کد ارز و منطقه زمانی را برمی‌گرداند.

{
  "kind": "adsdartsearch#report",
  "id": "MTMyNDM1NDYK",                      // This is the report id.
  "isReportReady": false,                    // The report is not finished generating.

  "request": {                               // The request that created this report.
    ...
  },

  "statisticsCurrencyCode": "CAD",           // The currency used for statistics. E.g., if
                                             // advertiser currency was requested, this would be
                                             // currency code of the advertiser in scope.

  "statisticsTimeZone": "America/New_York"   // If all statistics in the report were sourced from
                                             // a single time zone, this would be it. If
                                             // verifySingleTimeZone was set to true in the request,
                                             // then this field will always be populated (or the
                                             // request will fail).
}
      

اگر اعتبارسنجی ناموفق باشد

اگر گزارش تأیید اعتبار نکند، Search Ads 360 پاسخ HTTP 400 را با یک شی خطا برمی‌گرداند. به عنوان مثال، درخواست مثال بالا یک آژانس واقعی را مشخص نکرده است:

{
 "error": {
   "code": 400,
   "message": "statisticsCurrency: the agency in scope does not have a valid currency. Please make sure the agency is properly initialized in Search Ads 360."
 }
}

نظرسنجی برای وضعیت گزارش

Report.Get() با شناسه گزارش فراخوانی کنید.

JSON

GET https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK
          

جاوا

/**
 * Polls the reporting API with the reportId until the report is ready.
 * Returns the report.
 */
private static Report pollUntilReportIsFinished(Doubleclicksearch service, String reportId)
    throws IOException, InterruptedException {
  long delay = 1;
  while (true) {
    Report report = null;
    try {
      report = service.reports().get(reportId).execute();
    } catch (GoogleJsonResponseException e) {
      System.err.println("Report generation has failed.");
      System.exit(e.getStatusCode());
    }
    if (report.getIsReportReady()) {
      return report;
    }
    System.out.format("Report %s is not ready - waiting %s seconds.%n", reportId, delay);
    Thread.sleep(TimeUnit.SECONDS.toMillis(delay));
    delay = delay + delay; // Double the delay for the next iteration.
  }
}

.خالص

using api = Google.Apis.Doubleclicksearch.v2;

/// <summary>
/// Polls until the report with the given ID completes.
/// </summary>
/// <param name="service">Search Ads 360 API service.</param>
/// <param name="reportId">Report ID to poll.</param>
/// <exception cref="ApplicationException">
/// Thrown when the report completes, but has failed.
/// </exception>
private static api.Data.Report PollUntilReportIsFinished(
    api.DoubleclicksearchService service,
    string reportId)
{
    TimeSpan delay = TimeSpan.FromSeconds(1);
    while (true)
    {
        api.Data.Report report;
        try
        {
            report = service.Reports.Get(reportId).Execute();
        }
        catch (Google.GoogleApiException ex)
        {
            throw new ApplicationException("Report generation failed", ex);
        }
        if (report.IsReportReady.GetValueOrDefault(false))
        {
            return report;
        }
        Console.WriteLine("Report is not ready - waiting {0}", delay);
        Thread.Sleep(delay);
        delay = delay.Add(delay); // Double the delay for the next iteration.
    }
}

پایتون

import pprint
import simplejson
from googleapiclient.errors import HttpError

def poll_report(service, report_id):
  """Poll the API with the reportId until the report is ready, up to ten times.

  Args:
    service: An authorized Doubleclicksearch service.
    report_id: The ID DS has assigned to a report.
  """
  for _ in xrange(10):
    try:
      request = service.reports().get(reportId=report_id)
      json_data = request.execute()
      if json_data['isReportReady']:
        pprint.pprint('The report is ready.')

        # For large reports, DS automatically fragments the report into multiple
        # files. The 'files' property in the JSON object that DS returns contains
        # the list of URLs for file fragment. To download a report, DS needs to
        # know the report ID and the index of a file fragment.
        for i in range(len(json_data['files'])):
          pprint.pprint('Downloading fragment ' + str(i) + ' for report ' + report_id)
          download_files(service, report_id, str(i)) # See Download the report.
        return

      else:
        pprint.pprint('Report is not ready. I will try again.')
        time.sleep(10)
    except HttpError as e:
      error = simplejson.loads(e.content)['error']['errors'][0]

      # See Response Codes
      pprint.pprint('HTTP code %d, reason %s' % (e.resp.status, error['reason']))
      break

اگر گزارش آماده نیست

اگر گزارش آماده نباشد، Search Ads 360 پاسخ HTTP 202 را برمی‌گرداند و قسمت isReportReady نادرست است.

{
  "kind": "doubleclicksearch#report",
  "id": "MTMyNDM1NDYK",
  "isReportReady": false,
  "request": {
    ...
  },
  ...
}
      

وقتی گزارش آماده شد

وقتی گزارش تکمیل شد و آماده دانلود شد، قسمت isReportReady درست است. پاسخ همچنین دارای یک فیلد اضافی به نام files است که حاوی آدرس‌های اینترنتی برای دانلود فایل‌های گزارش است.

{
  "kind": "doubleclicksearch#report",
  "id": "MTMyNDM1NDYK",
  "isReportReady": true,
  "request": {
    ...
  },
  ...
  "rowCount": 1329,        // Total rows in the report, not counting headers.
  "files": [
    {
      "url": "https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/0"
      "byteCount": "10242323"
    },
    {
      "url": "https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/1"
      "byteCount": "10242323"
    }
  ],
}
      

اگر تولید گزارش ناموفق باشد

اگر Search Ads 360 نتواند گزارشی ایجاد کند، یکی از چندین کد خطای HTTP را به همراه یک توضیح برمی گرداند.

{
  "error" : {
   "code" : 410,            // Or other error codes.
   "message" : "Processing was halted on the backend and will not continue."
  }
}
      

برای لیست خطاهایی که Search Ads 360 می تواند برگرداند ، کدهای پاسخ را ببینید.

گزارش را دانلود کنید

می‌توانید با زدن مستقیم URL فایل گزارش، یا با تماس با Reports.getFile() با شناسه گزارش و شماره فایل (0 فهرست شده) گزارش را دانلود کنید. Search Ads 360 گزارش را در یک فایل رمزگذاری شده UTF-8 برمی گرداند.

در اینجا نمونه هایی از درخواست های Reports.getFile() آورده شده است:

JSON

GET https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/0?alt=media
و
GET https://www.googleapis.com/doubleclicksearch/v2/reports/MTMyNDM1NDYK/files/1?alt=media
          

جاوا

/**
 * Downloads the shards of a completed report to the given local directory.
 * Files are named CampaignReport0.csv, CampaignReport1.csv, and so on.
 */
private static void downloadFiles(
    Doubleclicksearch service,
    Report report,
    String localPath) throws IOException {
  for (int i = 0; i < report.getFiles().size(); i++) {
    FileOutputStream outputStream =
        new FileOutputStream(new File(localPath, "CampaignReport" + i));
    service.reports().getFile(report.getId(), i).executeAndDownloadTo(outputStream);
    outputStream.close();
  }
}

.خالص

using api = Google.Apis.Doubleclicksearch.v2;

/// <summary>
/// Downloads the shards of a completed report to the given local directory.
/// Files are named CampaignReport0.csv, CampaignReport1.csv, and so on.
/// </summary>
/// <param name="service">Search Ads 360 API service.</param>
/// <param name="report">Report ID to download.</param>
/// <param name="localPath">Path of the directory to place downloaded files.</param>
private static void DownloadFiles(
    api.DoubleclicksearchService service,
    api.Data.Report report,
    string localPath)
{
    Directory.CreateDirectory(localPath);
    for (int i = 0; i < report.Files.Count; ++i)
    {
        string fileName = Path.Combine(
            localPath,
            string.Format("CampaignReport{0}.csv", i));
        Console.WriteLine("Downloading shard {0} to {1}", i, fileName);
        using (Stream dst = File.OpenWrite(fileName))
        {
            service.Reports.GetFile(report.Id, i).Download(dst);
        }
    }
}

پایتون

def download_files(service, report_id, report_fragment):
  """Generate and print sample report.

  Args:
    service: An authorized Doubleclicksearch service.
    report_id: The ID DS has assigned to a report.
    report_fragment: The 0-based index of the file fragment from the files array.
  """
  f = file('report-' + report_fragment + '.csv', 'w')
  request = service.reports().getFile_media(reportId=report_id, reportFragment=report_fragment)
  f.write(request.execute().decode('utf-8'))
  f.close()

گزارش نمونه

در اینجا نمونه ای از گزارش CSV آمده است. هر قطعه فایل گزارش دارای ردیف سرصفحه خاص خود است. برای جزئیات بیشتر در مورد این قالب، RFC 4180 را ببینید.

keywordText,campaignId,landingPageUrl,day,revenue,visits last month,my revenue
google,71700000002104742,http://www.google.com,2012-05-01,10.2,5,20
google,71700000002104742,http://www.google.com,2012-05-02,11,10,60.23
      

دانلود فایل نگاشت شناسه

می‌توانید فایلی را که حاوی نگاشت‌های شناسه بین Search Ads 360 قبلی و Search Ads 360 جدید است دانلود کنید. برای تبلیغ‌کننده درخواستی، فایل شامل همه موجودیت‌های فرزند (مانند حساب‌های موتور، کمپین‌ها، گروه‌های تبلیغاتی و غیره) است که در هر دو وجود دارد. Search Ads 360 قبلی و Search Ads 360 جدید.

پایتون

def download_mapping_file(service, file_name, agency_id, advertiser_id):
    """Generate and save mapping file to a csv.

    Args:
      service: An authorized Doubleclicksearch service.
      file_name: Filename to write the ID mapping file.
      agency_id: DS ID of the agency.
      advertiser_id: DS ID of the advertiser.
    """
    request = service.reports().getIdMappingFile_media(agencyId=agency_id,
        advertiserId=advertiser_id)

    response = request.execute()
    response = response.decode('utf-8')

    f = open(file_name + '.csv', 'w')
    f.write(response)
    f.close()