2020-04-13

[Python] Google Analytics Reporting API v4 で直近一週間のページごとの PV 数を取得する

ブログでよくある「最近読まれている記事」みたいなものを静的サイトでも実現したいと思い、Google Analytics Reporting API v4 を使って直近一週間のページごとの PV 数を取得してみました。取得したデータを JSON とかで保持しておけば、前日までのデータで PV ランキングが作成できそうです。

目次

概要

Google Analytics Reporting API v4 (以下、Reporting API) を使用して、直近一週間の各ページごとの PV 数を取得します。取得したデータは、下記のような形で保存します。

[
  {
    "page_path": "/path/to/post_1",
    "page_view": 100
  },
  {
    "page_path": "/path/to/post_2",
    "page_view": 99
  }
]

取得スクリプトは Python 3.x で実装します。

(.venv) $ python -V
Python 3.7.6

適宜、仮想環境を作るなりして作業してください。

前提

上記の準備については下記の公式レイファレンスを参照してください。

実装

実装については公式のクイックスタートにあるサンプルがほぼそのまま使えるので、それをもとに下記の手順で進めていきます。

  1. 必要なライブラリのインストール
  2. サンプルスクリプトの実行
  3. PV 取得用に編集

1. 必要なライブラリのインストール

Reporting API を Python で使用するために、まずはクライアントライブラリをインストールします。

$ pip install --upgrade google-api-python-client

これに加えて、 oauth2client もインストールします。

$ pip install oauth2client

2. サンプルスクリプトの実行

クイックスタートのページにあるサンプルスクリプト HelloAnalytics.py をコピーまたはダウンロードしてきて、下記のように編集します。

  """Hello Analytics Reporting API V4."""

  from apiclient.discovery import build
  from oauth2client.service_account import ServiceAccountCredentials

  SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
- KEY_FILE_LOCATION = '<REPLACE_WITH_JSON_FILE>'
- VIEW_ID = '<REPLACE_WITH_VIEW_ID>'
+ KEY_FILE_LOCATION = './client_secrets.json'
+ VIEW_ID = '1234567890123'

認証情報は client_secrets.json という名前で、このスクリプトと同じディレクトリに保存されているとします。

VIEW_ID に指定するのは、 Google Analytics のビューの ID です。確認するには、 Google Analytics のコンソールか、 Account Explorer を使用します。

コンソールで確認する場合は、下のキャプチャで赤く塗られている部分の値を確認します。

Google Analytics view id

サンプルスクリプトを実行すると、7 日前から今日までの 各国 (地域) ごとのセッション数が出力されます。

$ python HelloAnalytics.py
ga:country: (not set)
Date range: 0
ga:sessions: 5
ga:country: Australia
Date range: 0
ga:sessions: 1
ga:country: Bahrain
Date range: 0
ga:sessions: 1
ga:country: Brazil
Date range: 0
ga:sessions: 1
ga:country: Canada
Date range: 0
...

3. PV 取得用に編集

各ページ (パス) ごとの PV 数を取得するために、サンプル内の get_report() 関数を次のように編集します。

  return analytics.reports().batchGet(
      body={
          'reportRequests': [
              {
                  'viewId': VIEW_ID,
-                 'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'today'}],
-                 'metrics': [{'expression': 'ga:sessions'}],
-                 'dimensions': [{'name': 'ga:country'}]
+                 'dateRanges': [{'startDate': '7daysAgo', 'endDate': 'yesterday'}],
+                 'metrics': [{'expression': 'ga:pageviews'}],
+                 'dimensions': [{'name': 'ga:pagePath'}]
              }]
      }
  ).execute()

上記のように metricsdimensions を編集することで、次のようなレスポンスが取得できます。

{
  "reports": [
    {
      "columnHeader": {
        "dimensions": [
          "ga:pagePath"
        ],
        "metricHeader": {
          "metricHeaderEntries": [
            {
              "name": "ga:pageviews",
              "type": "INTEGER"
            }
          ]
        }
      },
      "data": {
        "rows": [
          {
            "dimensions": [
              "/path/to_post_1"
            ],
            "metrics": [
              {
                "values": [
                  "100"
                ]
              }
            ]
          },
          {
            "dimensions": [
              "/path/to/post_2"
            ],
            "metrics": [
              {
                "values": [
                  "99"
                ]
              }
            ]
          }
        ]
      }
    }
  ]
}

このレスポンスから各パスの PV 数を集計するための関数を作成します。合わせて、結果を出力する関数も作成します。この際、レスポンスに含まれるパスにはクエリパラメータも含まれているので、集計時には無視するようにしています。

def calc(response):
    # type: (dict) -> ()
    """Calculate page views of each page path.

    Args:
        response: The Analytics Reporting API V4 response.
    """
    calc_res = dict()
    pv_summary = []
    report = response.get('reports', [])[0]
    for report_data in report.get('data', {}).get('rows', []):
        # get page path
        page_path = report_data.get('dimensions', [])[0]
        # ignore query parameters
        page_path = re.sub(r'\?.+$', '', page_path)

        # get page view
        page_view = int(report_data.get('metrics', [])[0].get('values')[0])

        if page_path in calc_res:
            calc_res[page_path] += page_view
        else:
            calc_res[page_path] = page_view

    for path in calc_res:
        pv_summary.append({
            'page_path': path,
            'page_views': calc_res[path]
        })

    # sort by page views
    pv_summary.sort(
        key=lambda path_data: path_data['page_views'], reverse=True)

    return pv_summary


def save_as_json(data, file_path='./res.json'):
    # type: (dict or list, str) -> ()
    """ Save dict pr list as JSON file.

    Args:
        data: dict or list object to save.
        file_path: file path for JSON file. (default is './res.json')
    """

    with open(file_path, 'w') as f:
        f.write(json.dumps(data, indent=2))

もともとあった print_response() 使用しないので削除して、最終的には下記のようになります。

実行すると、下記のような JSON ファイルが生成されます。

[
  {
    "page_path": "/path/to/post_1",
    "page_views": 100
  },
  {
    "page_path": "/path/to/post_2",
    "page_views": 99
  },
  {
    "page_path": "/path/to/post_4",
    "page_views": 10
  },
  {
    "page_path": "/path/to/post_3",
    "page_views": 5
  }
]

まとめ

Google Analytics Reporting API v4 を使って直近一週間のページごとの PV 数を取得してみた話でした。本当は記事のタイトルも取得できれば良いのですが、今回はパスごとの PV 数で一旦妥協してます。ただ、URL さえわかればはてなブログの埋め込みスクリプトを使用してリンクを作成することができるので、この情報だけでもなんとかなりそうです。

あとはこのスクリプトを定期的に (1日1回) 実行して S3 にでも JSON を配置できれば、静的サイトでも記事の閲覧数ランキングが簡単に作成できそうです。