API báo cáo chính – Hướng dẫn cho nhà phát triển

Tài liệu này giải thích cách sử dụng API Báo cáo chính để truy cập vào Dữ liệu Google Analytics.

Giới thiệu

API Báo cáo chính cho phép bạn truy cập vào dữ liệu dạng bảng trong các báo cáo chuẩn và báo cáo tuỳ chỉnh của Google Analytics. Để truy cập dữ liệu, bạn tạo một truy vấn chỉ định: chế độ xem (hồ sơ), ngày bắt đầu và ngày kết thúc, cũng như những phương diện và chỉ số tạo nên các tiêu đề cột trong bảng. Truy vấn này được gửi đến API Báo cáo chính và API Báo cáo chính sẽ trả về tất cả dữ liệu dưới dạng bảng.

Nếu bạn mới sử dụng API này, hãy đọc bài viết Tổng quan về API báo cáo chính để biết phần giới thiệu về mục đích của API báo cáo chính và dữ liệu mà API này cung cấp.

Trước khi bắt đầu

Hướng dẫn này minh hoạ cách truy cập vào API Google Analytics bằng ngôn ngữ lập trình Java, Python, PHP và JavaScript.

  • Hãy đọc trang thư viện ứng dụng để biết danh sách đầy đủ các thư viện ứng dụng cụ thể của ngôn ngữ lập trình hoạt động với API.
  • Đọc Hướng dẫn tham khảo để truy cập API mà không cần thư viện ứng dụng.

Mỗi thư viện ứng dụng cung cấp một đối tượng dịch vụ phân tích duy nhất để truy cập vào tất cả dữ liệu của API Báo cáo chính. Để tạo đối tượng dịch vụ, thường thì bạn phải trải qua các bước sau:

  1. Đăng ký ứng dụng của bạn trong Google API Console.
  2. Uỷ quyền truy cập vào dữ liệu Google Analytics.
  3. Tạo một đối tượng dịch vụ Analytics.

Nếu bạn chưa hoàn tất các bước này, vui lòng dừng hoạt động và đọc Xin chào hướng dẫn về API Google Analytics. Tài liệu hướng dẫn này sẽ trình bày các bước đầu tiên để tạo một ứng dụng API Google Analytics. Sau khi hoàn tất, bạn sẽ có thể sử dụng hướng dẫn này để thực hiện các công việc thực tế.

Đoạn mã sau đây chứa một biến để lưu trữ đối tượng dịch vụ được uỷ quyền.

Java

Analytics analytics = // Read Hello Analytics Tutorial for details.

Python

analytics = # Read Hello Analytics Tutorial for details.

1.199

$client = // Read Hello Analytics Tutorial for details.

// Return results as objects.
$client->setUseObjects(true);

$analytics = new apiAnalyticsService($client);

Thư viện PHP sẽ trả về tất cả kết quả API dưới dạng một mảng kết hợp. Để trả về các đối tượng thực, bạn có thể gọi phương thức useObject của ứng dụng như được minh hoạ trong ví dụ trên.

JavaScript

<script src="https://apis.google.com/js/client.js?onload=loadLib"</script>
<script>
function loadLib() {
  // Handle all the authorization work.
  // Read Hello Analytics Tutorial for details.
  gapi.client.load('analytics', 'v3', makeApiCall);
}
</script>

Thẻ tập lệnh đầu tiên tải thư viện JavaScript của Google API. Sau khi tải, loadLib sẽ được thực thi để tải lớp dịch vụ phân tích. Sau khi hoàn tất, đối tượng gapi.client.analytics sẽ tồn tại trong DOM và sẵn sàng để sử dụng để truy vấn API Báo cáo chính.

Sau khi tạo đối tượng dịch vụ phân tích, bạn có thể gửi yêu cầu đến API Báo cáo chính.

Lưu ý: Bạn cũng có thể dùng đối tượng dịch vụ phân tích để truy cập vào API Quản lý.

Tổng quan

Một ứng dụng sử dụng API báo cáo chính thường sẽ tuân theo 2 bước:

  • Truy vấn API báo cáo chính
  • Xử lý các kết quả API

Hãy xem xét cả hai bước.

Truy vấn API báo cáo chính

Tạo truy vấn API báo cáo chính

Đối tượng dịch vụ phân tích chứa phương thức để tạo truy vấn API báo cáo chính.

Mỗi truy vấn API Báo cáo chính chứa một nhóm các tham số chỉ định dữ liệu cần trả về.

Một trong những tham số truy vấn quan trọng nhất là tham số ids hoặc mã nhận dạng bảng. Tham số này chỉ định chế độ xem Google Analytics (hồ sơ) cần truy xuất dữ liệu. Giá trị có định dạng ga:xxx, trong đó xxx là mã nhận dạng chế độ xem (hồ sơ).

Java

Get apiQuery = analytics.data().ga()
    .get(tableId,                  // Table Id.
        "2012-01-01",              // Start date.
        "2012-01-15",              // End date.
        "ga:sessions")               // Metrics.
    .setDimensions("ga:source,ga:keyword")
    .setSort("-ga:sessions,ga:source")
    .setFilters("ga:medium==organic")
    .setMaxResults(25);

Python

api_query = service.data().ga().get(
    ids=TABLE_ID,
    start_date='2012-01-01',
    end_date='2012-01-15',
    metrics='ga:sessions',
    dimensions='ga:source,ga:keyword',
    sort='-ga:sessions,ga:source',
    filters='ga:medium==organic',
    max_results='25')

1.199

private function queryCoreReportingApi() {
  $optParams = array(
      'dimensions' => 'ga:source,ga:keyword',
      'sort' => '-ga:sessions,ga:source',
      'filters' => 'ga:medium==organic',
      'max-results' => '25');

  return $service->data_ga->get(
      TABLE_ID,
      '2010-01-01',
      '2010-01-15',
      'ga:sessions',
      $optParams);
}

Trong thư viện này, phương thức get không chỉ tạo truy vấn API Báo cáo chính, mà còn thực thi yêu cầu đến API.

JavaScript

function makeApiCall() {
  var apiQuery = gapi.client.analytics.data.ga.get({
    'ids': TABLE_ID,
    'start-date': '2010-01-01',
    'end-date': '2010-01-15',
    'metrics': 'ga:sessions',
    'dimensions': 'ga:source,ga:keyword',
    'sort': '-ga:sessions,ga:source',
    'filters': 'ga:medium==organic',
    'max-results': 25
  });
  // ...
}

Trong ví dụ này, hàm makeApiCall được gọi sau khi thư viện ứng dụng JavaScript tải xong. Bên trong, hàm này sẽ tạo một truy vấn API Google Analytics mới và lưu trữ đối tượng trong biến apiQuery.

Bạn có thể xem danh sách đầy đủ về tất cả các tham số truy vấn và chức năng của các tham số đó trong Hướng dẫn tham khảo về API Báo cáo chính. Ngoài ra, các thông số phương diện và chỉ số cho phép bạn chỉ định dữ liệu cần truy xuất từ Google Analytics. Bạn có thể xem danh sách đầy đủ trên trang tham khảo về phương diện và chỉ số.

Tạo yêu cầu dữ liệu API Báo cáo chính

Sau khi xác định một truy vấn, hãy gọi phương thức đó là execute để gửi truy vấn đó đến máy chủ của Google Analytics.

Java

try {
  apiQuery.execute();
  // Success. Do something cool!

} catch (GoogleJsonResponseException e) {
  // Catch API specific errors.
  handleApiError(e);

} catch (IOException e) {
  // Catch general parsing network errors.
  e.printStackTrace();
}

Nếu bạn muốn truy cập vào phản hồi thô của API, hãy sử dụng phương thức executeUnparsed():

HttpResponse response = apiQuery.executeUnparsed();

Python

try:
  results = get_api_query(service).execute()
  print_results(results)

except TypeError, error:
  # Handle errors in constructing a query.
  print ('There was an error in constructing your query : %s' % error)

except HttpError, error:
  # Handle API service errors.
  print ('There was an API error : %s : %s' %
         (error.resp.status, error._get_reason()))

1.199

  try {
    $results = queryCoreReportingApi();
    // Success. Do something cool!

  } catch (apiServiceException $e) {
    // Handle API service exceptions.
    $error = $e->getMessage();
  }

JavaScript

function makeApiCall() {
  // ...

  apiQuery.execute(handleCoreReportingResults);
}

function handleCoreReportingResults(results) {
  if (!results.error) {
    // Success. Do something cool!
  } else {
    alert('There was an error: ' + results.message);
  }
}

Ví dụ này tiếp nối từ bước trước khi tạo truy vấn API Báo cáo chính. Ở bước này, truy vấn được thực thi. Tham số cho phương thức execute là mã tham chiếu đến một hàm callback sẽ được thực thi sau khi dữ liệu được trả về từ API.

Sau khi API trả về cùng với kết quả, hàm callback sẽ được thực thi và được truyền dữ liệu từ API. Nếu xảy ra lỗi, kết quả sẽ chứa một thuộc tính có tên là error.

Trong ví dụ này, hệ thống sẽ kiểm tra xem error có tồn tại hay không hoặc liệu API có được trả về thành công hay không.

Nếu truy vấn thành công, API sẽ trả về dữ liệu được yêu cầu. Nếu xảy ra lỗi, API sẽ trả về mã trạng thái cụ thể và thông báo mô tả lỗi. Tất cả các ứng dụng phải phát hiện và xử lý lỗi đúng cách.

Làm việc với các kết quả API

Nếu truy vấn API Báo cáo chính thành công, API sẽ trả về cùng với dữ liệu báo cáo của Analytics cũng như các thông tin liên quan khác về dữ liệu.

Dữ liệu báo cáo Analytics

Bạn có thể coi dữ liệu chính mà API trả về là một bảng có 2 loại dữ liệu chính:

  • Tiêu đề mô tả các loại giá trị trong mỗi cột
  • Các hàng dữ liệu trong bảng

Dữ liệu tiêu đề cột

Mỗi phản hồi của API chứa một trường tiêu đề cột đại diện cho thông tin tiêu đề của bảng. Trường này là một danh sách (hoặc một mảng) các đối tượng, trong đó mỗi đối tượng mô tả loại dữ liệu trong cột. Thứ tự cột là các cột phương diện, theo sau là các cột chỉ số theo cùng thứ tự được chỉ định trong truy vấn ban đầu.

Java

private void printColumnHeaders(GaData gaData) {
 System.out.println("Column Headers:");

 for (GaDataColumnHeaders header : gaData.getColumnHeaders()) {
   System.out.println("Column Name: " + header.getName());
   System.out.println("Column Type: " + header.getColumnType());
   System.out.println("Column Data Type: " + header.getDataType());
 }
}

Python

def print_column_headers():
  headers = results.get('columnHeaders')

  for header in headers:
    # Print Dimension or Metric name.
    print 'Column name = %s' % header.get('name'))
    print 'Column Type = %s' % header.get('columnType')
    print 'Column Data Type = %s' % header.get('dataType')

1.199

private function printColumnHeaders(&results) {
  $html = '';
  $headers = $results->getColumnHeaders();

  foreach ($headers as $header) {
    $html .= <<<HTML
Column Name = {$header->getName()}
Column Type = {$header->getColumnType()}
Column Data Type = {$header->getDataType()}
HTML;

  print $html;
}

JavaScript

function printColumnHeaders(results) {
  var output = [];

  for (var i = 0, header; header = results.columnHeaders[i]; ++i) {
    output.push(
        'Name        = ', header.name, '\n',
        'Column Type = ', header.columnType, '\n',
        'Data Type   = ', header.dataType, '\n'
    );
  }

  alert(output.join(''));
}

Dữ liệu hàng

Dữ liệu chính mà API trả về sẽ được trả về ở dạng List 2 chiều của chuỗi. Danh sách bên ngoài đại diện cho tất cả các hàng dữ liệu. Mỗi danh sách bên trong đại diện cho một hàng, trong đó thứ tự các ô trong một hàng giống với các trường trong đối tượng tiêu đề cột được mô tả ở trên.

Vì dữ liệu trong mỗi ô được trả về dưới dạng chuỗi, nên trường DataType trong mỗi đối tượng tiêu đề cột sẽ đặc biệt hữu ích vì có thể dùng trường này để phân tích cú pháp các giá trị chuỗi thành loại phù hợp. Xem phản hồi của API siêu dữ liệu để biết tất cả các loại dữ liệu có thể có.

Các ví dụ sau đây in cả tiêu đề và hàng của bảng.

Java

private void printDataTable(GaData gaData) {
 if (gaData.getTotalResults() > 0) {
   System.out.println("Data Table:");

   // Print the column names.
   for (GaDataColumnHeaders header : gaData.getColumnHeaders()) {
     System.out.format("%-32s", header.getName() + '(' + header.getDataType() + ')');
   }
   System.out.println();

   // Print the rows of data.
   for (List<String> rowValues : gaData.getRows()) {
     for (String value : rowValues) {
       System.out.format("%-32s", value);
     }
     System.out.println();
   }
 } else {
   System.out.println("No Results Found");
 }

Python

def print_data_table(results):
  # Print headers.
  output = []
  for header in results.get('columnHeaders'):
    output.append('%30s' % header.get('name'))
  print ''.join(output)

  # Print rows.
  if results.get('rows', []):
    for row in results.get('rows'):
      output = []
      for cell in row:
        output.append('%30s' % cell)
      print ''.join(output)
  else:
    print 'No Results Found'

1.199

private function printDataTable(&$results) {
  if (count($results->getRows()) > 0) {
    $table .= '<table>';

    // Print headers.
    $table .= '<tr>';

    foreach ($results->getColumnHeaders() as $header) {
      $table .= '<th>' . $header->name . '</th>';
    }
    $table .= '</tr>';

    // Print table rows.
    foreach ($results->getRows() as $row) {
      $table .= '<tr>';
        foreach ($row as $cell) {
          $table .= '<td>'
                 . htmlspecialchars($cell, ENT_NOQUOTES)
                 . '</td>';
        }
      $table .= '</tr>';
    }
    $table .= '</table>';

  } else {
    $table .= '<p>No Results Found.</p>';
  }
  print $table;
}

JavaScript

function printRows(results) {
  output = [];

  if (results.rows && results.rows.length) {
    var table = ['<table>'];

    // Put headers in table.
    table.push('<tr>');
    for (var i = 0, header; header = results.columnHeaders[i]; ++i) {
      table.push('<th>', header.name, '</th>');
    }
    table.push('</tr>');

    // Put cells in table.
    for (var i = 0, row; row = results.rows[i]; ++i) {
      table.push('<tr><td>', row.join('</td><td>'), '</td></tr>');
    }
    table.push('</table>');

    output.push(table.join(''));
  } else {
    output.push('<p>No Results Found</p>');
  }

  alert(output.join(''));
}

Thông tin báo cáo

Cùng với dữ liệu trong bảng chính, dữ liệu mà API trả về còn chứa một số thông tin cấp cao về phản hồi. Bạn có thể in bằng:

Java

private void printResponseInfo(GaData gaData) {
  System.out.println("Contains Sampled Data: " + gaData.getContainsSampledData());
  System.out.println("Kind: " + gaData.getKind());
  System.out.println("ID:" + gaData.getId());
  System.out.println("Self link: " + gaData.getSelfLink());
}

Python

def print_response_info(results):
  print 'Contains Sampled Data = %s' % results.get('containsSampledData')
  print 'Kind                  = %s' % results.get('kind')
  print 'ID                    = %s' % results.get('id')
  print 'Self Link             = %s' % results.get('selfLink')

1.199

private function printReportInfo(&$results) {
  $html = <<<HTML
  <pre>
Contains Sampled Data = {$results->getContainsSampledData()}
Kind                  = {$results->getKind()}
ID                    = {$results->getId()}
Self Link             = {$results->getSelfLink()}
</pre>
HTML;

  print $html;
}

JavaScript

function printReportInfo(results) {
  var output = [];

  output.push(
      'Contains Sampled Data  = ', results.containsSampledData, '\n',
      'Kind                   = ', results.kind, '\n',
      'ID                     = ', results.id, '\n',
      'Self Link              = ', results.selfLink, '\n');

  alert(output.join(''));
}

Trường containsSampledData rất quan trọng vì trường này mô tả liệu phản hồi API đã được lấy mẫu hay chưa. Việc lấy mẫu có thể ảnh hưởng đến kết quả dữ liệu của bạn và lý do phổ biến khiến các giá trị được trả về từ API không khớp với giao diện web. Hãy xem hướng dẫn về khái niệm Lấy mẫu để biết thêm thông tin chi tiết.

Thông tin về chế độ xem (Hồ sơ)

Mỗi phản hồi chứa một nhóm các thông số cho biết Tài khoản, Thuộc tính web và Chế độ xem (Hồ sơ) chứa dữ liệu này.

Java

private void printProfileInfo(GaData gaData) {
  GaDataProfileInfo profileInfo = gaData.getProfileInfo();

  System.out.println("Account ID: " + profileInfo.getAccountId());
  System.out.println("Web Property ID: " + profileInfo.getWebPropertyId());
  System.out.println("Internal Web Property ID: " + profileInfo.getInternalWebPropertyId());
  System.out.println("View (Profile) ID: " + profileInfo.getProfileId());
  System.out.println("View (Profile) Name: " + profileInfo.getProfileName());
  System.out.println("Table ID: " + profileInfo.getTableId());
}

Python

def print_profile_info(result):

  info = results.get('profileInfo')
  print 'Account Id          = %s' % info.get('accountId')
  print 'Web Property Id     = %s' % info.get('webPropertyId')
  print 'Web Property Id     = %s' % info.get('internalWebPropertyId')
  print 'View (Profile) Id   = %s' % info.get('profileId')
  print 'Table Id            = %s' % info.get('tableId')
  print 'View (Profile) Name = %s' % info.get('profileName')

1.199

private function printProfileInformation(&$results) {
  $profileInfo = $results->getProfileInfo();

  $html = <<<HTML
<pre>
Account ID               = {$profileInfo->getAccountId()}
Web Property ID          = {$profileInfo->getWebPropertyId()}
Internal Web Property ID = {$profileInfo->getInternalWebPropertyId()}
Profile ID               = {$profileInfo->getProfileId()}
Table ID                 = {$profileInfo->getTableId()}
Profile Name             = {$profileInfo->getProfileName()}
</pre>
HTML;

  print $html;
}

JavaScript

function printProfileInfo(results) {
  var output = [];

  var info = results.profileInfo;
  output.push(

      'Account Id          = ', info.accountId, '\n',
      'Web Property Id     = ', info.webPropertyId, '\n',
      'View (Profile) Id   = ', info.profileId, '\n',
      'Table Id            = ', info.tableId, '\n',
      'View (Profile) Name = ', info.profileName);

  alert(output.join(''));
}

Mỗi mã trong số này tương ứng với nhiều thực thể trong hệ phân cấp API Quản lý. Bạn có thể sử dụng các mã nhận dạng này để tạo truy vấn API Quản lý nhằm nhận thêm thông tin cấu hình về chế độ xem (hồ sơ). Ví dụ: bạn có thể truy vấn Tập hợp mục tiêu API Quản lý để xem Mục tiêu nào đang hoạt động cùng với tên mục tiêu được định cấu hình của các Mục tiêu đó.

Thông tin về truy vấn

Mỗi phản hồi của API Báo cáo chính chứa một đối tượng chứa tất cả giá trị tham số truy vấn dùng để tạo phản hồi.

Java

private void printQueryInfo(GaData gaData) {
  GaDataQuery query = gaData.getQuery();

  System.out.println("Ids: " + query.getIds());
  System.out.println("Start Date: " + query.getStartDate());
  System.out.println("End Date: " + query.getEndDate());
  System.out.println("Metrics: " + query.getMetrics()); // List
  System.out.println("Dimensions: " + query.getDimensions());
  System.out.println("Sort: " + query.getSort()); // List
  System.out.println("Segment: " + query.getSegment());
  System.out.println("Filters: " + query.getFilters());
  System.out.println("Start Index: " + query.getStartIndex());
  System.out.println("Max Results: " + query.getMaxResults());
}

Python

def print_query_info(results):
  query = results.get('query')
  for key, value in query.iteritems():
    print '%s = %s' % (key, value)

1.199

private function printQueryParameters(&$results) {
  $query = $results->getQuery();

  $html = '<pre>';
  foreach ($query as $paramName => $value) {
    $html .= "$paramName = $value\n";
  }
  $html .= '</pre>';

  print $html;
}

JavaScript

function printQuery(results) {
  output = [];

  for (var key in results.query) {
    output.push(key, ' = ', results.query[key], '\n');
  }

  alert(output.join(''));
}

Tham số metricssort được trả về dưới dạng giá trị trong danh sách, trong khi các tham số khác được trả về dưới dạng chuỗi.

Thông tin phân trang

Mọi yêu cầu API Báo cáo chính có thể khớp với hàng trăm nghìn hàng dữ liệu của Google Analytics. API Báo cáo chính sẽ chỉ trả về một tập hợp con tại một thời điểm nhất định, có thể được gọi là một trang dữ liệu. Bạn sử dụng các trường phân trang để truy xuất tất cả các trang dữ liệu.

Java

private void printPaginationInfo(GaData gaData) {
  System.out.println("Items Per Page: " + gaData.getItemsPerPage());
  System.out.println("Total Results: " + gaData.getTotalResults());
  System.out.println("Previous Link: " + gaData.getPreviousLink());
  System.out.println("Next Link: " + gaData.getNextLink());
}

Python

def print_pagination_info(results):
  print 'Items per page = %s' % results.get('itemsPerPage')
  print 'Total Results  = %s' % results.get('totalResults')
  print 'Previous Link  = %s' % results.get('previousLink')
  print 'Next Link      = %s' % results.get('nextLink')

1.199

private function getPaginationInfo(&$results) {
  $html = <<<HTML
<pre>
Items per page = {$results->getItemsPerPage()}
Total results  = {$results->getTotalResults()}
Previous Link  = {$results->getPreviousLink()}
Next Link      = {$results->getNextLink()}
</pre>
HTML;

  print $html;
}

JavaScript

function printPaginationInfo(results) {
  var output = [];

  output.push(
      'Items Per Page = ', results.itemsPerPage, '\n',
      'Total Results  = ', results.totalResults, '\n',
      'Previous Link  = ', results.previousLink, '\n',
      'Next Link      = ', results.nextLink, '\n');

  alert(output.join(''));
}

Trường totalResults thể hiện tổng số hàng dữ liệu mà truy vấn của bạn khớp trong Google Analytics. Giá trị này có thể lớn hơn số hàng thực tế được trả về trong một trang của phản hồi. Trường itemsPerPage thể hiện số lượng hàng được trả về trong trang này.

Các tham số previousLinknextLink chỉ xuất hiện nếu đã có trang trước đó hoặc trang tiếp theo. Hãy truy cập vào các đường liên kết này để xem liệu có thể truy xuất thêm trang dữ liệu từ API Báo cáo chính hay không.

Tổng số cho tất cả kết quả

Như đã đề cập trong phần thông tin phân trang ở trên, một truy vấn đến API Báo cáo chính có thể khớp với nhiều hàng dữ liệu trong Google Analytics, nhưng chỉ trả về một số ít dữ liệu. Tổng giá trị chỉ số cho tất cả các hàng trùng khớp sẽ được trả về trong đối tượng totalsForAllResults. Dữ liệu này rất hữu ích khi tính toán giá trị trung bình.

Java

private void printTotalsForAllResults(GaData gaData) {
  Map totalsMap = gaData.getTotalsForAllResults();

  for (Map.Entry entry : totalsMap.entrySet()) {
    System.out.println(entry.getKey() + " : " + entry.getValue());
  }
}

Python

def print_totals_for_all_results(results):
  totals = results.get('totalsForAllResults')

  for metric_name, metric_total in totals.iteritems():
    print 'Metric Name  = %s' % metric_name
    print 'Metric Total = %s' % metric_total

1.199

private function printTotalsForAllResults(&$results) {
  $totals = $results->getTotalsForAllResults();

  foreach ($totals as $metricName => $metricTotal) {
    $html .= "Metric Name  = $metricName\n";
    $html .= "Metric Total = $metricTotal";
  }

  print $html;
}

JavaScript

function printTotalsForAllResults(results) {
  var output = [];

  var totals = results.totalsForAllResults;
  for (metricName in totals) {
    output.push(
        'Metric Name  = ', metricName, '\n',
        'Metric Total = ', totals[metricName], '\n');
  }

  alert(output.join(''));
}

Mẫu đang hoạt động

Để xem các mẫu hoạt động đầy đủ, hãy xem Mẫu API Báo cáo chính trong thư mục mẫu của mỗi thư viện ứng dụng.

Java

Thư viện ứng dụng Java của Google API Mẫu API báo cáo chính

Python

Thư viện ứng dụng Google API Python Mẫu API báo cáo chính

1.199

Thư viện ứng dụng PHP API của Google Mẫu API báo cáo chính

JavaScript

Thư viện ứng dụng JavaScript của Google API Mẫu API báo cáo chính

Nguồn JavaScript