#はじめに
今回は以下のようなカレンダーから任意の予定を抽出していきたいと思います。任意の予定を表示させる方法というのがわからなくて、結構しらべてしまいました。結局は公式ドキュメントをみれば一発だったのですが…
そこで「どうせなら全部書くかー」と思い、Qiitaに書き込んだまでです。
#導入
基本の設定は公式ドキュメントのPython Quickstarに書いてあるので詳細は飛ばします。
必要なもの
- credentials.jsonファイル
- カレンダーID
- Google Clientのライブラリ
ファイルはこちらからダウンロードできます。これから作るmain.py
のスクリプトと同じディレクトリに入れてください。
カレンダーIDは自分のGoogleカレンダーの設定に載っています。わからない場合はググるか、こちらを参照してみてください。もし[マイカレンダー]→[名前]を使うのであれば、カレンダーIDはGmailアドレスとなります。それ以外(例えば以下の図の「Test」など)は調べないとわかりません。
Google Clientのライブラリは、インストールしていなければインストールしてください。
pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
#公式サンプル
公式ドキュメントのサンプルは以下のようになっています。これを少し改良すれば、好き放題できそうです。
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月の予定を表示したいのでtimeMin
とtimeMax
は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')
を返すようにしています。
実装
以上のコードを繋げていきます。一応完成したコートをのせていますが、こちらは他の作業のために自分用に作っているので、下手にクラスや関数を使っていることは大目に見てください。
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
さて、しっかりと抽出できたといわれれば、そうではないことがわかります。もう一度、サンプルのカレンダーを見てみます。
Testカレンダーにある「テスト」はもちろん表示されませんが、「test_4」も表示されていませんね。逆に大文字の「Test」は出力されています。ここで使うq=
はどうやら綴りが完全一致の単語を検索しているのだということが読み取れます。
したがって「テスト」を表示したい場合はq="テスト"
、「test_4」を表示したい場合はq=test_4
とする必要があります。
#まとめ
用途によっては色々と使えそうですね。自分の予定からどれくらいの頻度で、何をしているのかといったような行動分析もできるような気がします。
私はまた違った使い方をしようと思っているのですが…
何かのお役に立てれば幸いです。間違っている箇所があれば指摘お願いします。(""
と''
がごちゃごちゃになっているのはご了承ください。すいません)