Web系零細企業での出来事

組み込み屋からWeb系エンジニアへ異世界転生を果たした筆者がWeb系技術の話題を中心に書き連ねるブログ

サーバーレスでEvernoteに登録したブックマークをランダムにSlackへ通知するアプリを作る①

 みなさん、「これ後でしっかり見返そう」と思ってブックマークまではするけど、それで満足して全然見返さないなんてことありませんか?私はかなりあります。全然見ないブックマークばかりEvernoteにたまっております。

 昔に登録したブックマークを定期的にお知らせしてくれれば、まったく目を通していなかったブックマークを見るのではないかとふと思い立ちました。EvernoteAPIを使えば簡単に実装できそうです。

要件

  • Evernoteに登録されたブックマークを1日1回ランダムに5件取得し、slackの個人チャンネルに投稿する。
  • AWS Lambdaを使いサーバーレス構成で実現する。
  • インフラ構成はSAMを使用してコード管理する。

将来的に実装したいこと

  • 同じブックマークを連日投稿しないように制御する。
  • EvernoteだけでなくPocketのブックマークも取得して通知する。

インフラ構成

f:id:yuki86042239:20180612204906p:plain

 CloudWatchのTimeBasedEventで24時間おきにLambdaを起動し、EvernoteAPIからブックマーク情報を取得し、Slackに通知するというシンプルな構成です。

Evernote APIの調査

 まずはEvernote APIを使ってブックマークを取得できるか試してみましょう。

公式ドキュメント

Documentation - Evernote Developers

codezine.jp

こちらの記事を参考に進めます。

認証

 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一覧の取得は以下のような手順で行います。

  1. 認証トークンを与えてEvernoteClientインスタンスを初期化。そのインスタンスからnote_storeを取得。
  2. note_storeからnotebook一覧を取得。
  3. NoteFilterインスタンスを生成。所望の検索条件を作成する。今回は、bookmarksという名前のnotebookにブックマークを保存していますので、そのnotebook内のNoteをすべて取得することとします。
  4. NotesMetadataResultSpecインスタンスを生成。
  5. NoteFilterインスタンスを与えて、ノートのメタデータリストを取得。
  6. メタデータリストから個別にノートのコンテンツを取得する。

 5.でノートのいったんノートのメタデータを取得するのは、通信量を節約するためです。ノートのコンテンツには添付ファイルなどの大容量データが含まれる場合があるので、それを含めてリストを取得してしまうと莫大な量を通信してしまう可能性があります。コンテンツを含めてリスト取得するメソッドもあるようですが、それは非推奨となっています。

 NoteのコンテンツはHTMLで記述されていますので、HTMLParserを使用してブックマークページのURLを抽出しています。

 上記のコードでEvernote APIを利用してbookmarkを一括で取得し、その中からランダムに5件抽出してタイトルとリンクURLを表示させることができました。

まとめ

 今回は、Evernote APIを利用してNoteの一覧を取得する方法について紹介しました。次回は、このコードをAWS SAMでデプロイしてみたいと思います。