LoginSignup
3
11

More than 3 years have passed since last update.

Googleカレンダーの任意の予定をPythonで抽出する方法

Last updated at Posted at 2020-01-11

はじめに

今回は以下のようなカレンダーから任意の予定を抽出していきたいと思います。任意の予定を表示させる方法というのがわからなくて、結構しらべてしまいました。結局は公式ドキュメントをみれば一発だったのですが…

そこで「どうせなら全部書くかー」と思い、Qiitaに書き込んだまでです。

image.png

導入

基本の設定は公式ドキュメントのPython Quickstarに書いてあるので詳細は飛ばします。

必要なもの

  • credentials.jsonファイル
  • カレンダーID
  • Google Clientのライブラリ

ファイルはこちらからダウンロードできます。これから作るmain.pyのスクリプトと同じディレクトリに入れてください。

カレンダーIDは自分のGoogleカレンダーの設定に載っています。わからない場合はググるか、こちらを参照してみてください。もし[マイカレンダー]→[名前]を使うのであれば、カレンダーIDはGmailアドレスとなります。それ以外(例えば以下の図の「Test」など)は調べないとわかりません。
image.png

Google Clientのライブラリは、インストールしていなければインストールしてください。

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

公式サンプル

公式ドキュメントのサンプルは以下のようになっています。これを少し改良すれば、好き放題できそうです。

sample1.py
from __future__ import print_function
import datetime
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']

def main():
    """Shows basic usage of the Google Calendar API.
    Prints the start and name of the next 10 events on the user's calendar.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    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)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

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

    # Call the Calendar API
    now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
    print('Getting the upcoming 10 events')
    events_result = service.events().list(calendarId='primary', timeMin=now,
                                        maxResults=10, singleEvents=True,
                                        orderBy='startTime').execute()
    events = events_result.get('items', [])

    if not events:
        print('No upcoming events found.')
    for event in events:
        start = event['start'].get('dateTime', event['start'].get('date'))
        print(start, event['summary'])

if __name__ == '__main__':
    main()

任意の予定検索

公式ドキュメントの前半はごちゃごちゃとコードが書いてありますが、基本はそのままで大丈夫です。# Call the Calendar APIのあたりからコードを変形させていきます。まずevents_resultのリストは、サンプルとして以下のように設定しておきます。

events_result = service.events().list(
        calendarId = calendar_id,
        q = "test",
        timeMin = "2020-02-01T00:00:00+00:00",
        timeMax = "2020-02-29T00:00:00+00:00",
        timeZone = None,
        singleEvents = True,
        orderBy = "startTime",
        ).execute()
events = events_result.get("items", [])

q = "test"は検索するキーワードを指しています。リストの要素はこちらに色々と書いてあるので必要になったらみてください。

サンプルとしては2020年2月の予定を表示したいのでtimeMintimeMaxは2月の範囲をdatetimeで指定します。ここは注意が必要です。

表示を整える

次に、その後のスクリプトを改良していきます。ここはご自由に設定して良いのですが、Googleカレンダーの説明descriptionを読み込むときには注意が必要です。

if not events:
    print("not found")
for event in events:
    start = event['start'].get('dateTime',event['start'].get('date'))
    description = event.get('description', "not found")
    print(start)
    print("Event :",event['summary'])
    print("Description :",description,"\n")

event['description']ではなく、description = event.get('description', "not found")としてget.()を使用します。ちなみに予定に説明文が書かれていなかったときにはnot foundを返します。

start = event['start'].get('dateTime',event['start'].get('date'))でも同じように、予定に時間設定がある場合は、'dateTime'を返し、予定が終日の場合はevent['start'].get('date')を返すようにしています。

実装

以上のコードを繋げていきます。一応完成したコートをのせていますが、こちらは他の作業のために自分用に作っているので、下手にクラスや関数を使っていることは大目に見てください。

main.py
from __future__ import print_function
import pickle
import os.path

from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/calendar']

calendar_id = "your calendar id"

class Writer(object):
    def __init__(self):
        """Shows basic usage of the Google Calendar API.
            Prints the start and name of the next 10 events on the user's calendar.
            """
        creds = None
        # The file token.pickle stores the user's access and refresh tokens, and is
        # created automatically when the authorization flow completes for the first
        # time.
        if os.path.exists('token.pickle'):
            with open('token.pickle', 'rb') as token:
                creds = pickle.load(token)
        # If there are no (valid) credentials available, let the user log in.
        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)
            # Save the credentials for the next run
            with open('token.pickle', 'wb') as token:
                pickle.dump(creds, token)

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

    def google_calendar_reader(self):

            events_result = self.service.events().list(
                calendarId= calendar_id,
                q="test",
                timeMin = "2020-02-01T00:00:00+00:00",
                timeMax = "2020-02-29T00:00:00+00:00",
                timeZone = None,
                singleEvents=True,
                orderBy="startTime",
                ).execute()
            events = events_result.get("items", [])

            if not events:
                print("not found")
            for event in events:
                start = event['start'].get('dateTime',event['start'].get('date'))
                description = event.get('description', "not found")
                print(start)
                print("Event :",event['summary'])
                print("Description :",description,"\n")

writer = Writer()
writer.google_calendar_reader()

出力結果はこのようになりました。

2020-02-03
Event : test 1
Description : This is description of test_1. 

2020-02-10T10:00:00+09:00
Event : test 3
Description : not found 

2020-02-11
Event : Test
Description : not found 

さて、しっかりと抽出できたといわれれば、そうではないことがわかります。もう一度、サンプルのカレンダーを見てみます。

image.png

Testカレンダーにある「テスト」はもちろん表示されませんが、「test_4」も表示されていませんね。逆に大文字の「Test」は出力されています。ここで使うq=はどうやら綴りが完全一致の単語を検索しているのだということが読み取れます。

したがって「テスト」を表示したい場合はq="テスト"、「test_4」を表示したい場合はq=test_4とする必要があります。

まとめ

用途によっては色々と使えそうですね。自分の予定からどれくらいの頻度で、何をしているのかといったような行動分析もできるような気がします。

私はまた違った使い方をしようと思っているのですが…

何かのお役に立てれば幸いです。間違っている箇所があれば指摘お願いします。(""''がごちゃごちゃになっているのはご了承ください。すいません)

参考文献

3
11
0

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
3
11