【Python】AWSの課金額をNotion DBに出力、グラフ化してみた

## 概要
最近自己学習などでAWSを利用することが多くなってきたので、
どのくらい課金されているのか知りたくなりました。

また、手順や構築時参考にしたサイト等をNotionで管理してます。

このよく使うNotionの見えるところにどんくらい課金されているのか見えるようにしたいと思い、
投稿します。

よかったら参考にしてみてください。

注意：Notionには棒グラフなどのチャートを利用することができるが、
チャートは無料版だと１つしか作成できないようです。
複数利用したいけどNotionに課金するのはなぁ。。。。
って人はNotionはよりGrafanaとかを利用するのはいいかもしれないです。

## 環境設定

### Pythonバージョン

- Python3.12.6

### Pythonライブラリ(おそらく不要なものも入ってる)

```
$ pip3 freeze
boto3==1.35.81
botocore==1.35.81
cachetools==5.5.0
certifi==2024.8.30
charset-normalizer==3.4.0
google-api-core==2.24.0
google-api-python-client==2.155.0
google-auth==2.37.0
google-auth-httplib2==0.2.0
google-auth-oauthlib==1.2.1
googleapis-common-protos==1.66.0
httplib2==0.22.0
idna==3.10
jmespath==1.0.1
oauthlib==3.2.2
proto-plus==1.25.0
protobuf==5.29.1
pyasn1==0.6.1
pyasn1_modules==0.4.1
pyparsing==3.2.0
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
requests==2.32.3
requests-oauthlib==2.0.0
rsa==4.9
s3transfer==0.10.4
six==1.17.0
uritemplate==4.1.1
urllib3==2.2.3
```

## 処理設計

1.  AWS、Notion関連のシークレットトークン等を取得
2.  Boto3Client作成
3. boto3で前日の課金額取得
4. 取得した金額をNotion APIを使用してNotionDBに追加
5. 終了メッセージ出力

## スクリプト内容

main.py

```python
import boto3
import requests
import json
from datetime import datetime, timedelta, timezone
import os
from dotenv import load_dotenv

# 環境変数用.env読み込み
env_file_exists = os.path.exists('.env')

# .envが存在しない場合はFileNotFoundErrorを出力して異常終了
if env_file_exists:
    load_dotenv()
else:
    raise FileNotFoundError(".envファイルが存在しません。必要な環境変数を設定してください。")

# AWS設定
aws_region = os.getenv('aws_region')
aws_access_key = os.getenv('aws_access_key')
aws_secret_key = os.getenv('aws_secret_key')

# Notion設定
notion_token = os.getenv('notion_token')
notion_database_id = os.getenv('notion_database_id')

ce_client = boto3.client(
    'ce',
    region_name=aws_region,
    aws_access_key_id=aws_access_key,
    aws_secret_access_key=aws_secret_key
)

# AWS課金額取得
def get_aws_billing_data():
    # 現在のUTC時刻を取得
    utc_now = datetime.now(timezone.utc)
    # 終了日: JSTの今日 (UTC+9)
    end_date = utc_now.astimezone(timezone(timedelta(hours=9))).date()
    # 開始日: 前日
    start_date = end_date - timedelta(days=1)

    response = ce_client.get_cost_and_usage(
        TimePeriod={
            'Start': start_date.strftime('%Y-%m-%d'),
            'End': end_date.strftime('%Y-%m-%d')
        },
        Granularity='DAILY',
        Metrics=['UnblendedCost']
    )
    return start_date, response['ResultsByTime'][0]['Total']['UnblendedCost']['Amount']

# Notion APIでデータベースにデータを入力
def add_to_notion(date, amount):
    url = f"https://api.notion.com/v1/pages"
    headers = {
        "Authorization": f"Bearer {notion_token}",
        "Content-Type": "application/json",
        "Notion-Version": "2022-06-28"
    }
    # DBのDateカラムとCostカラムにデータ投入
    data = {
        "parent": {"database_id": notion_database_id},
        "properties": {
            "Date": {"type": "date", "date": {"start": str(date)}},
            "Cost": {"type": "number", "number": float(amount)}
        }
    }
    response = requests.post(url, headers=headers, data=json.dumps(data))
    # 正常終了(status code: 200)なら正常終了メッセージ、その他はエラーメッセージを出力させる
    if response.status_code == 200:
        print("データがNotionに正常に保存されました。")
    else:
        print(f"エラー: {response.status_code}, {response.text}")

if __name__ == "__main__":
    try:
        # 前日の開始日と課金額を取得
        start_date, billing_amount = get_aws_billing_data()
        print(f"前日のAWS課金額: ${billing_amount} (日付: {start_date})")

        # Notionに追加
        add_to_notion(start_date, billing_amount)
    except Exception as e:
        print(f"エラーが発生しました: {str(e)}")

```

.env

```
# AWS設定
aws_region = "<リージョン名>" #東京リージョンなら ap-northeast-1
aws_access_key = "<AWSのアクセスキー>"
aws_secret_key = "<AWSのシークレットキー>"

# Notion設定
notion_token = "<Notionインテグレーションのシークレットキー>"
notion_database_id = "<対象NotionDBのID>"
```

## Notion DB設定

Notion DB（チャート）、インテグレーションの作成とNotion DBでインテグレーションに接続する設定を行う。

1. `/chart`で検索して「線グラフを選択」をクリック。
2. 「新規」ボタンの左にあるメニューボタンから「データへのリンクコピー」をクリック。
3. どこかに貼り付けて`https://www.notion.so/XXXXXXXXXXXXXXXXXXXXXX?v=〜`のX部分を控えておく（X部分がDB IDになる）。
4.  Notion APIのインテグレーションを作成
以下URLを参照
https://programming-zero.net/notion-api-setting/
5. 作成したインテグレーションのシークレットトークンを控える
6. Notion DBページのメニューボタンから「接続」⇨ 「作成したインテグレーション」を選択する

これで完成！！

## 最後に
今回は個人的に利用したいのでデータ投入先を自身のNotionにしましたが、
他のグラフも一緒に見たいとかもあると思うので、
その際にはGrafanaとか利用するのがいいかもしれないですね。

また、今回のスクリプトをAWSのLambda関数とEventSchedulerを利用すれば、
自動取得できるので今後やってみようと思います。