Amazonの購入時刻をGmailの受信トレイから調べて可視化する

## 背景
Amazonで衝動買いする癖があるので購入時間を可視化していつ買っているかを把握することで気をつけたい。

- 何時に買っていることが多いか
- 何曜日に買っていることが多いか

## 手順
1. Gmailの注文完了メールをGmail APIで抽出する
2. 受信日時を取り出せるので時刻、曜日で集計し可視化する

## 準備
Gmail APIから自分用の `credentials.json` をダウンロードして同じディレクトリに置く。APIの用意方法は以下を参照する。

Gmail APIはPythonのライブラリが提供されているためそれを利用した。

https://developers.google.com/gmail/api/quickstart/python

## 実施（取得）
認証部分はサンプルとほぼ同じ。
「Amazon.co.jpでのご注文」の検索結果のリストを取得しそれぞれのメッセージ内容を参照している。

```python:pull.py
from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

q = 'Amazon.co.jpでのご注文'
email = 'test@gmail.com'

SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
creds = None

# 認証
if os.path.exists('token.json'):
    creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
    else:
        flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', SCOPES)
        creds = flow.run_local_server(port=0)
    with open('token.json', 'w') as token:
        token.write(creds.to_json())


# 注文取り出し 
service = build('gmail', 'v1', credentials=creds)
results = service.users().messages().list(userId=email, q=q).execute()
messages = results.get('messages', [])

for message in messages:
    message_id = message.get('id')
    mail = service.users().messages().get(userId=email, id=message_id, format='minimal').execute()
    print(mail.get('internalDate'))
```

### 出力値

`internalDate` にはUNIX時間でミリ秒まで記録されている。

```
1556799xxx000
1556032xxx000
1556031xxx000
1555086xxx000
1554382xxx000
...
```

## 実施（可視化）
出力値から時刻情報と曜日情報のみ取り出し棒グラフで表示している。

```python:draw.py
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np

# 読み込み
df = pd.read_csv('created_dates.txt', header=None)
datetimes = pd.to_datetime(df[0], unit='ms')

# 時刻情報だけのデータに変換
times = datetimes.dt.time
times = pd.DataFrame(pd.to_datetime(times, format='%H:%M:%S', utc=True))
times.set_index(0, inplace=True)
times.index = times.index.tz_convert('Asia/Tokyo')
times[1] = 0
times = times.rename(columns={1: 'count'}, index={0: 'date'})
group = times.groupby(pd.Grouper(freq='60min')).count()

# 曜日のデータに変換
weeks = pd.DataFrame(pd.to_datetime(datetimes, utc=True)).set_index(0)
weeks.index = weeks.index.tz_convert('Asia/Tokyo')
weekdays = weeks.index.weekday
weekdays = pd.DataFrame(weekdays)
weekdays[1] = 1

# 可視化
fig = plt.figure(figsize=(20,10))
## 時間帯
x = group.index.strftime("%H:%M:%S")
y = group
ax = fig.add_subplot(2,1,1)
ax.bar(x, group['count'], color="brown", align="center")
ax.set_title('Every Hour')
ax.set_xticks(x)
ax.set_yticks(np.arange(0, y.max().item() ))

## 曜日
x = ["Sun","Mon","Tue","Wed","Thr","Fri","Sat"]
y = weekdays.groupby(0).count()[1]
ax2 = fig.add_subplot(2,1,2)
ax2.bar(x, y, color="green", align="center")
ax2.set_title('Every Date')
ax2.set_xticks(x)
ax2.set_yticks(np.arange(0, y.max() ))

# 保存
fig.savefig("figure.png")
```

## 結果
時刻では夜の23時、0時にピークを迎えている。曜日では大きく変わらないが金曜日に頻度が増えている。

![ダウンロード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/359375/01336ba9-9fd2-d6b5-e717-dcdf1fc18af2.png)

## 結論
- 週末に密集していると思ったが意外とまんべんなく買っている
- 寝る前の時間帯は危険・・・！

GitHubに実行環境をまとめてます。

https://github.com/octop162/amazon_purchased_date