サーバーレスでEvernoteに登録したブックマークをランダムにSlackへ通知するアプリを作る①
みなさん、「これ後でしっかり見返そう」と思ってブックマークまではするけど、それで満足して全然見返さないなんてことありませんか?私はかなりあります。全然見ないブックマークばかりEvernoteにたまっております。
昔に登録したブックマークを定期的にお知らせしてくれれば、まったく目を通していなかったブックマークを見るのではないかとふと思い立ちました。EvernoteのAPIを使えば簡単に実装できそうです。
要件
- Evernoteに登録されたブックマークを1日1回ランダムに5件取得し、slackの個人チャンネルに投稿する。
- AWS Lambdaを使いサーバーレス構成で実現する。
- インフラ構成はSAMを使用してコード管理する。
将来的に実装したいこと
- 同じブックマークを連日投稿しないように制御する。
- EvernoteだけでなくPocketのブックマークも取得して通知する。
インフラ構成
CloudWatchのTimeBasedEventで24時間おきにLambdaを起動し、EvernoteAPIからブックマーク情報を取得し、Slackに通知するというシンプルな構成です。
Evernote APIの調査
まずはEvernote APIを使ってブックマークを取得できるか試してみましょう。
公式ドキュメント
Documentation - Evernote Developers
こちらの記事を参考に進めます。
認証
Evernote Clientの認証を通る方法として、APIキーもしくはデベロッパートークンの2種類があります。APIキーはOAuthでの実装が必要です。今回は、1年間の期限付きではありますが、手軽なデベロッパートークンで進めていきます。
Developer Tokens - Evernote Developers
検証用環境のサンドボックスと本番環境のプロダクショントークンがそれぞれ入手できます。※プロダクショントークンは2018.6.19現在Webページから取得することはできません。サポートに問い合わせ取得してください。
SDKのインストール
SDKはPython2にのみ対応している(Python3対応はbeta版)ということなので、Python2で進めていきます。インストールはpipで行います。
pip install evernote
Note一覧を取得し、ブックマークしたページのURLを抽出する
下記は今回実装したコードです。
# coding:utf-8 import random from HTMLParser import HTMLParser from evernote.api.client import EvernoteClient from evernote.edam.notestore.ttypes import NoteFilter, NotesMetadataResultSpec import settings class LinkParser(HTMLParser): # ノート内のURLを抽出するパーサー def __init__(self): HTMLParser.__init__(self) self.url = "" def handle_starttag(self, tag, attrs): if tag == "a": # 開始タグがaであるかどうか判定 attrs = dict(attrs) # タプルを辞書に変換する if 'href' in attrs: # キー値(属性名)がhrefであるか判定 self.url = attrs['href'] @property def link(self): return self.url if __name__ == '__main__': # Evernoteクライアントを初期化する(1) client = EvernoteClient(token=settings.AUTH_TOKEN, sandbox=False) note_store = client.get_note_store() # ノートブック一覧の取得(2) notebooks = note_store.listNotebooks() for notebook in notebooks: # bookmarksという名前のノートブックにブックマークを保存している。 if notebook.name == 'bookmarks': # 検索条件設定:指定ノートブックにひも付くノート(3) filter = NoteFilter() filter.notebookGuid = notebook.guid # 検索結果設定:ノートタイトルのみ取得(4) resultSpec = NotesMetadataResultSpec() resultSpec.includeTitle = True # ノートメタデータの検索(5) metalist = note_store.findNotesMetadata(filter, 0, 10000, resultSpec) parser = LinkParser() # ノートGUIDを検索条件にノートデータの取得(6) # ランダムに5件のbookmarkを抽出 for n in random.sample(metalist.notes, 5): content = note_store.getNoteContent(n.guid) print('\tNote title: ' + n.title) parser.feed(content) print('\tLink: ' + parser.link)
EvernoteAPIでのNote一覧の取得は以下のような手順で行います。
- 認証トークンを与えてEvernoteClientインスタンスを初期化。そのインスタンスからnote_storeを取得。
- note_storeからnotebook一覧を取得。
- NoteFilterインスタンスを生成。所望の検索条件を作成する。今回は、bookmarksという名前のnotebookにブックマークを保存していますので、そのnotebook内のNoteをすべて取得することとします。
- NotesMetadataResultSpecインスタンスを生成。
- NoteFilterインスタンスを与えて、ノートのメタデータリストを取得。
- メタデータリストから個別にノートのコンテンツを取得する。
5.でノートのいったんノートのメタデータを取得するのは、通信量を節約するためです。ノートのコンテンツには添付ファイルなどの大容量データが含まれる場合があるので、それを含めてリストを取得してしまうと莫大な量を通信してしまう可能性があります。コンテンツを含めてリスト取得するメソッドもあるようですが、それは非推奨となっています。
NoteのコンテンツはHTMLで記述されていますので、HTMLParserを使用してブックマークページのURLを抽出しています。
上記のコードでEvernote APIを利用してbookmarkを一括で取得し、その中からランダムに5件抽出してタイトルとリンクURLを表示させることができました。
まとめ
今回は、Evernote APIを利用してNoteの一覧を取得する方法について紹介しました。次回は、このコードをAWS SAMでデプロイしてみたいと思います。