LoginSignup
1

More than 1 year has passed since last update.

[Python]Google Calendar APIのQuickstartのサンプルコードを、分解して解説してみる

Last updated at Posted at 2021-07-21

Google Calendar APIって?

  • Googleカレンダーをいじれる
  • クイックスタートがあるためとっても簡単
  • と思ったら英語なので、自分のためも兼ねて解説する

解説記事が過去にありましたが、二年前でコードも変わっていました。

ソースコード

Apache License 2.0

前提

Python 2.6以降

pipで諸々をダウンロード

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

プロジェクトを作って認証情報をダウンロードしてある

→参考

まずは動かしてみる

  1. ソースコードをGoogle公式からコピー

  2. コードをquickstart.pyに貼り付けする

  3. ダウンロードしてきたJSON形式の認証情報を、credentials.jsonにリネームして、quickstart.pyと同じディレクトリに入れる

  4. 実行!動くはず

出力結果

イベントの開始時間と、イベントの名前が出力されます

2021-08-03T09:00:00+09:00 バイト
2021-08-04T09:00:00+09:00 バイト
2021-08-10T09:00:00+09:00 バイト
2021-08-11T09:00:00+09:00 バイト
2021-08-12T09:00:00+09:00 バイト
2021-08-17T09:00:00+09:00 バイト
2021-08-18T09:00:00+09:00 バイト
2021-08-23T09:00:00+09:00 バイト
2021-08-24T09:00:00+09:00 バイト
2021-08-25T09:00:00+09:00 バイト

悲しきバイト漬け人生

さらに、同じディレクトリ内にtoken.jsonが出現しました。

この出力結果を思い出しつつ、ソースコードを理解していきましょう。

ソースコードを分解して理解

重要そうな部分は:star:マークをつけています。

ライブラリのインポート

print_function

from __future__ import print_function

Python2と3の互換性を維持するためのライブラリです。
2系でも3系のコードが動くようになります。

datetime

import datetime

Pythonで日付や時刻を扱うためのライブラリです。

os.path

import os.path

パス名を操作するためのモジュール

:star:Googleのモジュール達

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

pipでインストールしたら動くはず

googleapiclient.discoveryのリファレンス
InstalledAppFlowのリファレンス
Credentialsのリファレンス

スコープ

:star:スコープ

SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']

スコープとは直訳すると範囲のことです。
許可して欲しい範囲を選択します。
API毎に指定されているため、用途によって変更するのが良いでしょう。

コメントによると変更した場合はtoken.jsonを削除する必要があります。

認証プロセス

cred

    creds = None

credはcredentials(資格情報)の略です。

この後の条件分岐によってここに情報が入ります。

一度通信したことがある場合

    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)

os.path.exists()は存在するかどうかを確かめる関数です。
token.jsonがある = 以前通信したことがある場合になります

その場合、credsにはtoken.jsonから生成されたCredentialsインスタンスが入ります。

有効でない認証情報だった場合

    if not creds or not creds.valid:

credsがまだNone = 以前通信したことがない、もしくはcreds.validが無効 = 期限切れ等の場合この条件に入ります。

期限切れの場合

        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())

さらに、無効の理由が期限切れで、リフレッシュトークンがある場合は、トークンを更新します。

:star:それ以外の場合

        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)

多くの場合、ここに来るのは初めての通信でしょう。
あるいはリフレッシュトークンの有効期限も切れるほど古い場合です。

flowには、資格情報ファイルのcredentials.jsonから作られたFlowインスタンスが入ります。
Flowインスタンスには、ブラウザを開いて認証画面を通させるrun_local_serverメゾットがあります。

つまり、アクセストークンがないから認証を新しく行わせているということです。

次回以降のためにトークンを保存

        with open('token.json', 'w') as token:
            token.write(creds.to_json())

次回以降のために、token.jsonを保存します。

最初に実行した際、新しくtoken.jsonができたのはこれが理由なんです。

APIを利用

:star:APIを利用する準備

    service = build('calendar', 'v3', credentials=creds)

APIを使用するためのResorceインスタンスがserviceに入ります。
ここでは、バージョン3を指定してcalendarAPIを使用します。

Resorceクラスのリファレンス

時刻を設定

    now = datetime.datetime.utcnow().isoformat() + 'Z'

datetime.datetime.utcnow().isoformat()まででUTCの時刻がYYYY-MM-DDTHH:MM:SS.ffffffの文字列として生成されます。
'z'はUTCを表します。

:star:カレンダーを10個取得

    events_result = service.events().list(calendarId='primary', timeMin=now,
                                        maxResults=10, singleEvents=True,
                                        orderBy='startTime').execute()

serviceインスタンスを用いてイベントを取得します
これに関しては、公式リファレンスとサンプルを見るのがわかりやすいです。

今回はevents = 予定の取得でしたが、例えばcalendars = 予定の集まりを消去などはservice.calendars().deleteとなります。

:star:イベントの詳細を取得

    events = events_result.get('items', [])

events_resultには、要求した内容の他に種類の識別子や時間などが入っています。

そこから内容である'item'キーの値を取り出します。

内容はリファレンスに書いてあります

itemがなかった場合

    if not events:
        print('No upcoming events found.')

イベントの詳細を取得で、itemがなかった場合は[]が入ります。
その場合の処理です。

itemを取得できた場合

    for event in events:
        start = event['start'].get('dateTime', event['start'].get('date'))
        print(start, event['summary'])

まず、startに始まりの時間を入れます。

帰ってきたdictの中のstartに、dateTimeキーの値がある場合はそれを、ない場合(おそらく終日予定の場合)はdateを取得します。

その後、出力しています。

main文を実行

if __name__ == '__main__':
    main()

解説するまでもないことかもしれませんが、ここまできたので書きましょう
main関数を実行しています。

終わりに

編集リクエスト、コメントぜひお願いします。

公式リファレンスがやはり一番役に立ちますね。

参考文献

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1