2019年2月11日月曜日

PythonでWikipediaの記念日一覧をGoogleカレンダーに登録する

PythonでWikimedia APIを使ってWikipediaの記事を取得するのようにPythonとWikimedia APIを使ってWikipediaの記事を取得できるので、これを利用してWikipediaの日本の記念日一覧の記事を取得して、これをもとに記念日のGoogleカレンダーを作成する。


環境


Raspberry PiとRaspbian Stretch。



Wikipediaの日本の記念日一覧の取得


PythonでWikimedia APIを使ってWikipediaの記事を取得するのコードの「ウィキペディア」を「日本の記念日一覧」に変更して実行する。結果をanniversary_list.txtとして保存しておく。以下のようなWikipedia書式(ヘルプ:書式整形)のテキストになる。



Googleカレンダーの作成


登録に失敗したときのことを考えて、使用中のカレンダーを使わずに記念日登録用のGoogleカレンダーを作成しておく。作成したら「カレンダーの設定」を開いて、「カレンダーの統合」の下にあるカレンダーIDをコピーしておく。


カレンダーAPIの有効化


GoogleのCalendar APIでGoogleカレンダーへイベントとして記念日を登録できる。はじめてCalendar APIを使うときは、APIを有効にして認証キーをダウンロードする。

APIの有効化はPython Quickstartにあるリンク「Enable the Google Calendar API」から行う。ログインしたら既存のプロジェクトを選ぶか、新規プロジェクトを作成する。

続いて「DOWNLOAD CLIENT CONFIGURATION」をクリックして認証キーとなるcredentials.jsonをダウンロードする。


Googleカレンダーへの記念日の登録


GoogleのCalendar APIとPythonでのGoogleカレンダーへのイベント登録は図書館の休館日をGoogleカレンダーに自動登録するでも行っているが、Python Quickstartの内容が更新されているので、改めて確認。

まずは必要ライブラリのインストール。


記念日一覧のテキストanniversary_list.txtと、APIの認証キーcredentials.jsonを同じディレクトリに置いて以下のコードを実行する。コード内の「カレンダーID」は、コピーしておいた登録対象のカレンダーIDと書き換えておく。
import os
import re
from collections import OrderedDict
from httplib2 import Http
from googleapiclient.discovery import build
from oauth2client import file, client, tools

# カレンダー編集用
SCOPES = 'https://www.googleapis.com/auth/calendar'

# 記念日を登録するカレンダーID
CALENDAR_ID = 'カレンダーID'

def get_credentials():
    #認証情報の取得

    home_dir = os.path.expanduser('~')
    credential_dir = os.path.join(home_dir, '.credentials')
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)
    credential_path = os.path.join(credential_dir, 'calendar-python-quickstart.json')

    store = file.Storage(credential_path)
    credentials = store.get()
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets('credentials.json', SCOPES)
        credentials = tools.run_flow(flow, store)

    return credentials

def add_event(anniv_dict):
    #Googleカレンダーに記念日を登録

    # API利用の認証
    credentials = get_credentials()
    service = build('calendar', 'v3', http=credentials.authorize(Http()))

    # 記念日を登録
    for anniv, date in anniv_dict.items():
        # 登録イベントに記念日と日付を設定
        event = {
            'summary': anniv,
            'start': {
                'date': date,
                'timeZone': 'Asia/Tokyo',
            },
            'end': {
                'date': date,
                'timeZone': 'Asia/Tokyo',
            },
        }

        # 記念日を登録するGoogleカレンダーIDをcalendarIdに指定し、イベントを登録する
        event = service.events().insert(calendarId=CALENDAR_ID, body=event).execute()
        if event:
            print(event['start'].get('date'), event['summary'])
        else:
            print('Failed to add an anniversary.')

def create_anniversary_dict():
    # Wikipedia書式のテキストから、記念日名をキー、要素を日付とした辞書リストを作成

    with open('anniversary_list.txt', 'r') as f:
        wiki_list = f.readlines()

    wiki_iter = iter(wiki_list)
    anniv_dict = OrderedDict()
    for i, line in enumerate(wiki_iter):
        # 各月の行を取得
        m = re.match('== (\d{1,2})月 ==', line)

        if m:
            try:
                pat_day = re.compile('\[\[(\d{1,2})月(\d{1,2})日\|')
                pat_name = re.compile('\[\[(.*?)\]\]')
                pat_url = re.compile('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+/?')
                while True:
                    anniv_line = next(wiki_iter)

                    # 日付と記念日部分を分割
                    # はじめの「-」のみ分割(記念日部分に「-」を含むURLがある場合がある)
                    anniv_split = anniv_line.strip().split('-', 1)

                    # 日付の取得
                    match_day = pat_day.search(anniv_split[0])
                    if match_day:

                        # 2月29日は2019年にないので除外
                        if match_day.group(1) == '2' and match_day.group(2) == '29':
                            break

                        # Gogleカレンダーへの登録用にYYYY-MM-DDのフォーマットにする
                        dt = '2019-{:0>2}-{:0>2}'.format(match_day.group(1), match_day.group(2))
                    else:
                        break

                    # 記念日部分からURLと「[」「]」を除去して記念名そ取得
                    anniv_name = pat_url.sub('', anniv_split[1]).strip()
                    match_name = anniv_name.replace('[', '').replace(']', '').split('、')

                    # 空の要素を除外
                    match_name = list(filter(lambda x: len(x) != 0, match_name))

                    for i, name in enumerate(match_name):
                        # 「|」で区切られているときは後の方が記念日名
                        name_split = name.split('|')
                        if len(name_split) > 1:
                            anniv_dict[name_split[1]] = dt
                        else:
                            anniv_dict[name] = dt

            except StopIteration as e:
                # イテレータの最後までいったらループを抜ける
                break

    return anniv_dict

if __name__ == '__main__':
    add_event(create_anniversary_dict())


カレンダーAPIをはじめて使用するときは、端末にAPIの認証情報を保存する必要がある。ターミナルで実行する場合は以下のように--noauth_local_webserverオプションを付けて実行する。URLが表示されるので、それをコピーして、別PCなどのブラウザで開くとコードが表示される。それをコピーして、ターミナルのコード入力欄にペーストする。これで認証情報が端末に保存されるので、2回目以降は--noauth_local_webserverオプションは不要。


結果は以下のようにGoogleカレンダーに記念日が登録された。

それにしても、世の中にはいろんな記念日があるもんだ・・


0 件のコメント:

コメントを投稿