APIを利用してGAのアカウント、プロパティ、ビューの一覧を縦持ちデータで取得する

Qiita記事初投稿です。
APIの利用が初めてだったのも含めて、至らない点もあると思いますがよろしくお願いします。

- [概要・やりたいこと](#概要やりたいこと)
- [Try this APIを利用してみる(非エンジニア向け)](#try-this-apiを利用してみる非エンジニア向け)
- [開発環境・モジュールのバージョン](#開発環境モジュールのバージョン)
- [事前の作業内容](#事前の作業内容)
- [実装コード](#実装コード)
- [今後の展望](#今後の展望)

## 概要・やりたいこと
私の会社ではサイト上の数値をGoogle Analytics(以降GA)を利用して計測しています。
社員もある程度おり数年以上利用を続けていたのですが、運用保守までしっかりと手が回らず、
様々なアカウントやプロパティが乱立してしまいました。

GAの管理画面上では、アカウントやプロパティの一覧をスクロールしながら表示することは可能です。
その結果をスプレッドシート上などで閲覧できる状態にしたい、というのが今回のゴールになります。

## Try this APIを利用してみる(非エンジニア向け)
下記APIを利用すると、ログインしているChromeのアカウントに紐づくGAのアカウントデータをJSON形式で取得できます。
[Management API > リファレンス > アカウント：list](https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/accounts/list?hl=ja)

実行結果を整形しても、ある程度やりたいことはできるようになります。
[JSONファイルをExcelに変換](https://qiita.com/afukuma/items/65c6e96bd15b319e160f)
[JSON ファイルを CSV ファイルに変換したい](https://eng-blog.iij.ad.jp/archives/934)

1つ目の方法はExcelのバージョン都合で実行できず、2つ目の方法で実際に試したところ問題が発生しました。

1. アウトプットの形式が意図通りではない  
GAの構造ですが、アカウント > プロパティ > ビュー という構成になっています。  
csv変換後のファイルは、アカウントの行数分だけ出力されます。  
またアカウントによってプロパティ数は異なるため、個人的には意図していないデータが生成されました。  

| アカウント | プロパティ_1 | ビュー_1_1 | ビュー_1_2 | ・・・ | プロパティ_2 |・・・ | 
|:-----------:|:-----------:|:-----------:|:-----------:|:-----------:|:----------:|:----------:|
| A | Aに紐づくプロパティ1 |プロパティ1に紐づくビュー1 |プロパティ1に紐づくビュー2 | ・・・ |Aに紐づくプロパティ2|・・・ | 

本来欲しかったのは、下記のような縦持ちのデータになります。

| アカウント | プロパティ | ビュー| 
|:-----------:|:-----------:|:-----------:|
| A | Aに紐づくプロパティ1 |プロパティ1に紐づくビュー1 |
| A | Aに紐づくプロパティ1 |プロパティ1に紐づくビュー2 |
| A |・・・ |・・・ |
| A |A紐づくプロパティ2 |プロパティ2に紐づくビュー1|
| A |・・・ |・・・ |
| B | Bに紐づくプロパティ1 |プロパティ1に紐づくビュー1 |

2.取得できるアカウントの数に限界がある？ 
社内では実行時59個のアカウントが存在していたのですが、取得できたのは49件でした。
パラメータの数値をいじったりしましたが、コードを書いてデータを取得しよう、となったため原因は深く調査していません。
何か心当たりがある方がいましたら、コメントいただけると嬉しいです。

## 開発環境・モジュールのバージョン 
* python                   3.8.2 
* google-api-python-client 1.8.0
* build                    1.0.2
* pandas                   0.24.2
* numpy                    1.16.4

## 事前の作業内容
発行したサービスアカウントを、取得したいGAのアカウントに追加した後に作業を行っています。
本来は社内の管理者アカウントに紐づくGAのアカウントを取得したかったのですが、対処方法が分からず。。

アカウントが多くてつらかったので、歌いながら片手間で作業して乗り切りました。笑

## 実装コード
以下、本題の実装コードになります。

実装コードの大部分が、下記からの引用です。
[はじめてのアナリティクス API: サービス アカウント向け Python クイックスタート](https://developers.google.com/analytics/devguides/config/mgmt/v3/quickstart/service-py?hl=ja)

APIを利用してアカウント、プロパティ、ビューごとのdfを作成し、空のdfにappendさせる、という処理を行っています。
[Management API > リファレンス > ウェブ プロパティ: list](https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/webproperties/list?hl=ja)
[Management API > リファレンス > ビュー（旧プロファイル）: list](https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/profiles/list?hl=ja)

```python:qiita.python
from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials
import pandas as pd
import numpy as np

def get_service(api_name, api_version, scopes, key_file_location):

    credentials = ServiceAccountCredentials.from_json_keyfile_name(
            key_file_location, scopes=scopes)
    service = build(api_name, api_version, credentials=credentials)
    return service

def get_account_propaty_view_info(service):
    accounts = service.management().accounts().list().execute()

    # アカウントの一覧をdfに格納する
    account_df = pd.DataFrame(columns=['account_name', 'account_id'])

    for account in accounts.get('items', []):  
        account_array = np.array([[account.get('name'), account.get('id')]])
        df_account = pd.DataFrame(data=account_array,columns=account_df.columns)
        account_df = account_df.append(df_account, ignore_index=False)

    # プロパティの一覧をdfに格納する
    property_df = pd.DataFrame(columns=['account_number','account_id', 'property_name', 'property_id'])

    # アカウントのdfから、対象のプロパティ一覧を取得する
    for i in range(len(account_df)):
        properties = service.management().webproperties().list(accountId=account_df['account_id'].iloc[i]).execute()
        for property in properties.get('items', []):
            property_array = np.array([[i, account_df['account_id'].iloc[i], property.get('name'), property.get('id')]])
            df_property = pd.DataFrame(data=property_array,columns=property_df.columns)
            property_df = property_df.append(df_property, ignore_index=False)
        
    # ビューの一覧をdfに格納する
    view_df = pd.DataFrame(columns=['account_id', 'property_id', 'view_name', 'view_id'])

    # プロパティのdfから、対象のビュー一覧を取得する
    for i in range(len(property_df)):
        views  = service.management().profiles().list(accountId=property_df['account_id'].iloc[i],
        webPropertyId=property_df['property_id'].iloc[i] ).execute()
        for view in views.get('items', []):
            view_array = np.array([[property_df['account_id'].iloc[i], property_df['property_id'].iloc[i], view.get('name'), view.get('id')]])
            df_view = pd.DataFrame(data=view_array,columns=view_df.columns)

            view_df = view_df.append(df_view, ignore_index=False)
            
    # アカウントの一覧、プロパティの一覧、ビューの一覧を1つのdfにまとめてみる
    # 結合時の処理都合でaccount_numberの位置が気になる方は、カラムの順序を変更してください。
    ga_account_list = pd.merge(pd.merge(account_df, property_df, on='account_id', how='inner'), view_df, on=['account_id', 'property_id'], how='inner')
    ga_account_list.to_csv('作成するcsvファイル名', encoding='utf_8_sig')

def main():
    scope = 'https://www.googleapis.com/auth/analytics.readonly'
    key_file_location = '発行したサービスアカウントのJSONキーファイル'

    service = get_service(
            api_name='analytics',
            api_version='v3',
            scopes=[scope],
            key_file_location=key_file_location)

    get_account_propaty_view_info(service)

if __name__ == '__main__':
    main()
```

現状のアウトプット例
アカウントのIDは綺麗に数字が並んでいる訳ではないので、代わりにaccount_numberというものを持たせています

| account_name |account_id| account_number| property_name | property_id | view_name |view_id |  
|:-----------:|:-----------:|:-----------:|:-----------:|:-----------:|:-----------:|:-----------:|
| A | 10 |0 | property_1 | 100 | view_1 | 1000 |
| A | 10 |0 | property_1 | 100 | view_2 | 1001 |
| A |・・・ |・・・ |・・・ |・・・ |・・・ |・・・ |
| A | 10 |0 | property_2 | 101 | view_1 | 1100 |
| A |・・・ |・・・ |・・・ |・・・ |・・・ |・・・ |
| B | 20 |1 | property_1 | 200 | view_1 | 2000 |

## 今後の展望
まずは今回の結果を利用して、不要なアカウントやプロパティの整理を行っていく予定です。

それに基づいて、社内の部署ごとでグループを作りたいと思っています。
現在はGAの権限付与を個人に対して行っているのですが、グループごとの権限付与が可能です。

新しく入社するAさんは○○部署なので、□□の権限をあげればいいよね、というイメージで
ボタン一つで自動化される未来を目指したいな、と思っています。

もし同じような悩みを持っている方の参考になれば幸いです。