🐋

GA4|Google Analytics 4のデータをPythonで取得する

2022/10/27に公開

はじめに

Google Analytics 4のデータをpythonで処理したいなーと思い、Analytics Data APIを使ってみました。使ってみて思ったことをまとめたので、このAPIを利用する参考になれば幸いです。

使用したコードこちらからダウンロードできます.
https://github.com/gradus-AP/python-ga4-tips


まずは使ってみる

準備

公式のクイックスタートに沿って以下の準備を行います。

<手順1> Google Analytics Data APIを有効にする
クイックスタートのページの[Enable the Google Analytics Data API v1]というボタンを押し、GCPプロジェクトを新規作成します。
このとき同時に認証用のJSONファイルがダウンロードをダウンロードしておきます。

<手順2> サービスアカウントにGA4のユーザーに追加
先ほどダウンロードした認証用のJSONファイルを開くと、client_emailの項目からサービスアカウントが確認できます。
次にGA4にアクセスし、[管理 > プロパティのアクセス管理]の項目からサービスアカウントを新規ユーザーに追加し、閲覧権限以上の権限を与えてください。

<手順3> クライアント向けライブラリのインストール
以下のコマンドを実行し、クライアントライブラリをインストールします。

pip
pip install google-api-python-client
pip install google-analytics-data

以上で、準備は完了です。

アクティブユーザー数の推移を取得する

日付毎にアクティブユーザー数を取得するプログラムは次のようになります(公式ドキュメントのサンプルを参考にしています)

main.py
"""アクティブユーザーの日次推移を取得するプログラム"""
from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.analytics.data_v1beta.types import DateRange
from google.analytics.data_v1beta.types import Dimension
from google.analytics.data_v1beta.types import Metric
from google.analytics.data_v1beta.types import RunReportRequest
import os

# アカウント設定
# credential.jsonを/credentialに保存 && GA4 プロパティIDを設定
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'credential/credential.json'
GA_PROPERTY_ID = {YOUR GA4 PROPERTY ID}

def sample_run_report(property_id=GA_PROPERTY_ID):
    client = BetaAnalyticsDataClient()

    request = RunReportRequest(
        property=f"properties/{GA_PROPERTY_ID}",
        dimensions=[Dimension(name="date")],
        metrics=[Metric(name="activeUsers")],
        date_ranges=[DateRange(start_date="28daysAgo", end_date="yesterday")],
    )
    response = client.run_report(request)

    for row in response.rows:
        print(row)

if __name__ == '__main__':
    sample_run_report()

実行結果を見ると、各行が次のような形で取得できていることがわかります。

{
    dimension_values: [{value: "20221021"}],
    metric_values: [{value: "19"}],
}

コードの説明

RunReportRequestのパラメータのうち、使用頻度の高いものを挙げておきます。

パラメータ 意味
property プロパティ ID。properties/{property ID}の形で指定します
dimensions ディメンション(リスト)
(詳しいディメンション・指標名はAPI Dimensions & Metrics)
metrics 指標(リスト)
dateRanges データ取得期間
dimensionFilter ディメンションのフィルタを指定します

その他のオプションについてはこちらから確認できます。


使い方に関するTips

ここでは、Analytics Data APIを使う際に役立ちそうなことを紹介します。

フィルタ

指定した条件を満たすデータに対象を絞って集計できます。
次のリクエストは、トップページ(パスが'/'に一致)を訪れたアクティブユーザー数のデータを取得します。

request = RunReportRequest(
        property=f"properties/{GA_PROPERTY_ID}",
        dimensions=[Dimension(name="date")],
        metrics=[Metric(name="activeUsers")],
        date_ranges=[DateRange(start_date="7daysAgo", end_date="yesterday")],
        dimension_filter=FilterExpression(
            filter=Filter(
                field_name="pagePath",
                string_filter=Filter.StringFilter(value="/"),
            )
        )
    )

文字列の条件はFilterオブジェクトのパラメータで指定できます。

パラメータ 説明
string_filter 完全一致 Filter.StringFilter(value='/')
トップページ(パス /)のみ集計
string_filter 前方一致 Filter.StringFilter(match_type='BEGINS_WITH', value='/products'))
/productsで始まるパスのみ集計
string_filter 前方一致 Filter.StringFilter(match_type='ENDS_WITH', value='/thanks'))
/thanksで終わるパスのみ集計
string_filter 部分一致 Filter.StringFilter(match_type='CONTAINS', value='2022'))
2022を含むパスのみ集計
string_filter 正規表現一致 Filter.StringFilter(match_type='PARTIAL_REGEXP', value='products.*detail'))
'products.*detail'に正規表現一致するパスのみ集計
in_list_filter リスト Filter.InListFilter(values=['/aaa', '/bbb']))
'/aaa'または'/bbb'に一致するパスのみ集計

さらに詳しいフィルタ指定についてはこちら

取得した結果をデータフレームに加工する

実際の用途を考えると、runReportから取得したデータをデータフレームに加工したい場面が多いと思います。

そこで次のようなクラスを用意して、より簡潔に書けるでしょう:

GoogleAnalytics4Report.py
from google.analytics.data_v1beta.types import DateRange
from google.analytics.data_v1beta.types import Dimension
from google.analytics.data_v1beta.types import Filter
from google.analytics.data_v1beta.types import FilterExpression
from google.analytics.data_v1beta.types import FilterExpressionList
from google.analytics.data_v1beta.types import Metric
from google.analytics.data_v1beta.types import RunReportRequest

"""
class: Google Analytics4 Report
see doc https://developers.google.com/analytics/devguides/reporting/data/v1/basics
"""
class GoogleAnalytics4Report:
    def __init__(self, propertyId):
        self._propertyId = propertyId
        self._metrics = []
        self._dimensions = []
        self._dateRange = ['28daysAgo', 'yesterday']
        self._filters = None
        self._result = []
    
    def setMetrics(self, metrics):
        """setter for report metrics."""
        self._metrics = metrics
        return self
    
    def setDimensions(self, dimensions):
        """setter for report dimensions."""
        self._dimensions = dimensions
        return self
    
    def setDateRange(self, dateRange):
        """setter for date range."""
        self._dateRange = dateRange
        return self
    
    def setFilters(self, **kwargs):
        """setter for report filters."""
        self._filters = kwargs
        return self

    def run(self, client):
        """Run this report on a Data API(GA4)."""
        
        def filterExprBuilder(filters):
            if isinstance(filters, list):
                return FilterExpressionList(expressions=[FilterExpression(filter=filter) for filter in filters])
            return FilterExpression(filter=filters)
        
        dimension_filter = None
        if self._filters is not None:
            dimension_filter = FilterExpression(
                **dict(map(lambda filter: (filter[0], filterExprBuilder(filter[1]) if filter[0] != 'filter' else filter[1]), self._filters.items()))
            )

        request = RunReportRequest(
            property=f"properties/{self._propertyId}",
            metrics=[Metric(name=name) for name in self._metrics],
            dimensions=[Dimension(name=name) for name in self._dimensions],
            date_ranges=[DateRange(start_date=self._dateRange[0], end_date=self._dateRange[1])],
            dimension_filter=dimension_filter
        )

        response = client.run_report(request)
        print(f"{response.row_count} rows received")
        self._result = [self._parseRow(row) for row in response.rows]
        return self
    
    def getResult(self):
        """get result returned by Data API(GA4)."""
        return self._result
    
    def getRecords(self):
        """get result as a list of record."""
        columns = [('dimensions', col) for col in self._dimensions]
        columns.extend([('metrics', col) for col in self._metrics])
        return [dict([(name, item[i][name]) for i, name in columns]) for item in self._result]

    def _parseRow(self, row):
      dimensions = self._dimensions
      metrics = self._metrics

      return {
          'dimensions':dict([(name, row.dimension_values[i].value) for i, name in enumerate(self._dimensions)]),
          'metrics':dict([(name, float(row.metric_values[i].value)) for i, name in enumerate(self._metrics)])
          }

使用例 アクティブユーザーの日次推移データをデータフレームに加工する

sample.py
from google.analytics.data_v1beta import BetaAnalyticsDataClient
import datetime
import pandas as pd
import os

"""アクティブユーザーの過去7日間の推移データを取得(GA4)"""

# アカウント設定
# credential.jsonを/credentialに設置 && GA4 プロパティIDを設定
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'credential/credential.json'
GA_PROPERTY_ID = {YOUR_PROPERTY_ID}

client = BetaAnalyticsDataClient()

activeUserReport = GoogleAnalytics4Report(GA_PROPERTY_ID).setDimensions(
        dimensions=['date']
    ).setMetrics(
        metrics=['activeUsers']
    ).setDateRange(
        dateRange=['7daysAgo', 'yesterday']
    ).run(client)

# データフレームに加工
df = pd.DataFrame.from_records(activeUserReport.getRecords())
df['date'] = pd.to_datetime(df['date']) # datetime型に変換
df['date'] = df['date'].dt.to_period('D')
df
実行結果
	date	activeUsers
0	2022-10-21	19.0
1	2022-10-20	15.0
2	2022-10-25	15.0
3	2022-10-26	14.0
4	2022-10-22	9.0
5	2022-10-24	9.0
6	2022-10-23	7.0

Discussion