Evernote API を使ってみる


Evernote API の使い方などの説明です。

Evernote API / 導入 / 初期化 / 基本 / ノート / 戻る / トップページ


Evernote API

Evernote は、 テキストや画像・PDF ファイルの情報をサーバーに蓄積して、 記憶したデータを検索できるようにするメモサービスです。
 
Evernote API は、その Evernote のノートを操作できるようにする 公式の API サービスです。 Evernote クライアントが使っているものと同じ API が提供されているので、 その気になれば Evernote クライアントの代替品を作ることも 不可能ではありません。 拙作のツール もこの Evernote API を利用させてもらっています。
 
API は Facebook の開発した Thrift フレームワークに従っています。 ですが、提供されているライブラリ (Java, Perl, PHP, Python, Ruby, C# が提供されてます) を使えば、 その仕組みを詳しく理解せずとも普通に言語のライブラリを 使っているようにアクセスできます。 ここでは Python を使った説明を書きますが、 処理の流れや呼び出すべき関数は同じです。
 
API の構造はシンプルになっており、 API リファレンス を見て分かるように、 NoteStore モジュール (クラスで表現されます) に ほとんどのサービス (関数で表現されます) は集約されており、 ログイン時やアカウント情報を触る時だけ UserStore モジュールを使います。

API の導入

Evernote API のドキュメント類は本家サイトで提供されています。 Evernote API Overview Evernote Corporation がそのサイトです。
 
Evernote API での開発をするには、申請をしてアクセス用の APIキー (consumerKey と consumerSecret) を取得する必要があります。 こちら で 何を作りたいかの簡単な説明を書いて申請します。 厳しいチェックがあった時期もあるようですが、 今では比較的簡単に発行してくれるようです。
 
始めの申請でもらえるコードでは、テストサーバーにのみ アクセスできるようになってます。 テストサーバー (Sandbox) は 普段使われているサーバーとはノートもユーザー管理も別管理なので、 普段自分が使っているノートとは切り離して実験できます (ただしデータは バックアップされていないなど、テストサーバーなりの保証になります)。
 
テストサーバーで十分に検証がされたら、再度申請して、 APIキーを本番サーバーでも使えるようにしてもらいます。

初期化

API を使うには、当然ながら、まず接続をする必要があります。
 
接続のフローは、UserStore を接続先 (本番サーバーかテストサーバーか) を指定して初期化し、checkVersion() 関数でバージョンの確認、authenticate() にユーザー名とパスワード、発行された consumerKey と consumerSecret で認証を行って authenticationToken を取得します。
	import thrift.protocol.TBinaryProtocol
	import thrift.transport.THttpClient
	import evernote.edam.userstore.UserStore
	import evernote.edam.userstore.constants
	import evernote.edam.notestore.NoteStore
	import evernote.edam.type.ttypes
	import evernote.edam.error.ttypes
	
	userStore=evernote.edam.userstore.UserStore.Client(
	    thrift.protocol.TBinaryProtocol.TBinaryProtocol(
	    thrift.transport.THttpClient.THttpClient(
	    "https://sandbox.evernote.com/edam/user")))
	# 本番サーバーなら https://www.evernote.com/edam/user
	
	success=userStore.checkVersion("Evernote Test/0.0.0; Windows/XP SP3",
	    evernote.edam.userstore.constants.EDAM_VERSION_MAJOR,
	    evernote.edam.userstore.constants.EDAM_VERSION_MINOR)
	# 第一引数はアプリケーション名を UserAgent 的に書くのが本当
	
	# ユーザー名とパスワードと、発行された API キーを指定
	authResult=self.userStore.authenticate(
	    username,password,consumerKey,consumerSecret)
	
	noteStore=evernote.edam.notestore.NoteStore.Client(
	    thrift.protocol.TBinaryProtocol.TBinaryProtocol(
	    thrift.transport.THttpClient.THttpClient(
	    "http://sandbox.evernote.com/edam/note/"+authResult.user.shardId)))
	# ここも本番サーバーなら https://www.evernote.com/edam/note/
	authToken=authResult.authenticationToken
認証の結果返ってきた shardId を使って NoteStore も作っておきます。 以後は authenticationToken を使って、NoteStore に対してノートの参照や追加の関数を呼ぶことになります。
	filter=evernote.edam.notestore.NoteStore.NoteFilter()
	noteList=noteStore.findNotes(authToken,filter,0,10)
	# noteList にノート 10 件を取得
authenticationToken は期限が設けられており、 それを過ぎた場合はもう一度認証を行う必要があります。 逆に言えば、期限までは同じ authenticationToken を使い続けられます。
 
期限は authenticate() の返り値の expiration フィールドに 1970/1/1 0:00 からの経過ミリ秒で格納されていますが、 サーバー上の時間と、アプリケーションを実行しているローカル環境の 時間が一致しているとは限らないため (どちらかがずれている可能性があり得る)、 サーバー上の現在時間が格納されている currentTime フィールドの 値を元に算出するのが適切です。
	expiredTime=time.time()+(authResult.expiration/1000.0-authResult.currentTime/1000.0)
	# expiredTime<time.time() なら認証し直して、authenticationToken を取得し直すべし

基本的な使い方

一度 authenticationToken の取得と NoteStore の生成が出来ていれば、 NoteStore に対して引数に authenticationToken を渡して 関数を呼ぶことでほとんどの処理はできます。
 
ノート一覧の取得
 
ノートの一覧を取る機能はなく、一覧を取る場合も検索をかける手順を取ります。 検索は NoteStore に findNotes() を呼び出して NoteList データ型 (クラスで表現されます) を取得し、 その notes フィールドにリスト型で格納されている ノート (Note データ型) を得ます。
 
findNotes() の引数には、authenticationToken, 検索条件 (NoteFilter データ型), 検索結果の何番目から, 何個取るか、 を指定します。
	filter=evernote.edam.notestore.NoteStore.NoteFilter()
	filter.order=evernote.edam.type.ttypes.NoteSortOrder.UPDATED
	# 検索条件として、検索語なし、更新日順ソートを指定
	
	noteList=noteStore.findNotes(authToken,filter,0,10)
	# noteList にノート 10 件を取得
	
	# ノートごとに処理
	for note in noteList.notes:
		title=note.title.decode("utf_8")	# ノートタイトルを取得
		
		print(title)
なお、文字列は UTF-8 で扱われているようです。 Python なら、文字列を返す関数や値は UTF-8 の str 型なので、 notebook.name.decode("utf_8") のように unicode 型に 変換して扱うと良いでしょう。
 
ノートの実体の取得
 
findNotes() で得た Note データ型には、 ノートの実体 (本文) やリソース (添付ファイル) 情報は入っていません。 NoteStore に getNote() を呼び出して、完全なノートの情報を得ましょう。
	guid=noteList.notes[0].guid
	note=noteStore.getNote(authToken,guid,True,True,True,True)
	# note.content で本文が読み取れる
第二引数には、ノートを識別する GUID を指定します。 ノートの GUID は検索結果で得られたノート情報などから参照できます。 なお、Evernote ではノート以外にもノートブックやタグも GUID で識別しています。
 
ノートの新規作成
 
ノートを新規に作って登録するには、Note データ型のデータを用意して、 NoteStore に createNote() を呼び出すことで実現します。
	note=evernote.edam.type.ttypes.Note()
	note.title=u"ノートタイトル".encode("utf_8")
	
	defaultNotebook=noteStore.getDefaultNotebook(authToken)
	# デフォルトのノートブックを取得して、その GUID を指定する
	note.notebookGuid=defaultNotebook.guid
	
	content=u"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
	content=content+u"<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">"
	content=content+u"<en-note>"
	content=content+u"ノートの本文"
	content=content+u"</en-note>"
	note.content=content.encode("utf_8")
	# 本文の指定内容は次章を参照
	
	note.created=int(time.time()*1000)
	note.updated=note.created
	# ノートの作成日と更新日の設定を忘れずに
	
	noteStore.createNote(authToken,note)

ノートの本文

ノートの本文は XHTML をベースに作られています (正確には ENML と 名付けられた XML データで、XHTML のサブセット+独自拡張)。 XHTML のほとんどのタグ・属性をサポートしてるようで、 改行の br タグのようによく使われるものから acronym のように滅多に使われないものまでサポートされてます。 BUTTON, SCRIPT タグや onclick 属性など、表示に関わるものでない ( 操作やスクリプト) ものだけを外しているように見えます。
 
style タグや外部スタイルシートの参照はサポートされていないものの (Web ページをクリップしても見た目情報がなくなるのはこのため)、 style 属性はサポートされており、実際に今も使われています。 どうやらいずれは style タグもサポート するようにしていく予定があるようです。
 
XHTML は HTML を XML で再定義し、HTML の後継を目指していたものですが、 ページ作者にメリットがなく普及しなかったため、HTML を拡張する HTML 5 の 作成に軌道修正をしたようです。 その意味ではやや時代の流れとずれてしまってますが、XML データで あることや HTML と完全ではないものの互換性があるため、 扱いやすいとも言えます。
 
そのノートの本文は NoteStore の getNote() や findNotes() で得られる Note 型の値の content フィールドに収められています。 Evernote クライアントでノートをエクスポートしたファイルをテキストエディタで開いても確認できるので、適当に作ったノートを見てみると良いでしょう。
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
    <en-note>
      <b>ノートの本文</b>
    </en-note>
ルートノードが <en-note> で、その下に本文データが入ります。 独自の拡張部分はさほど多くなく、この EN-NOTE タグの他には、 添付ファイル (画像や PDF) の貼り付けに使う EN-MEDIA タグ、 TODO チェックマークの EN-TODO タグ、 暗号化テキストの EN-CRYPT タグ、で全てです。
 
※ここから下の説明は、実際の挙動を調べて得た情報で、ドキュメントで 提供されていたものではないため、ある日突然変更がされる可能性があります。
 
ノートを Evernote の Web サイトEvernote クライアント から編集する時に、フォーマットの指定ができますが、 それによってタグや属性が自動で付与されています。 ですが、これが結構統一性がなく癖のある設定をしているようです。
 
まず、入力されたスペースは &nbsp; に (ペーストすると空白文字の場合もある)、タブキーでの入力は &nbsp; が 5 つ (Evernote クライアント 3.0 からタブ文字 \t になったようです) に変換されます。 また、1 行ごとに DIV タグでくくられるようです (メールからの登録の場合は改行を <br/> タグに変換することで行が区切られます)。
 
編集時のフォーマット指定と対応する ENML タグ
フォーマット Web サイトから編集した時 Windows クライアント 3.0 から編集した時
太字 <strong> <b>
イタリック <em> <i>
下線 <span style="text-decoration: underline;"> <u>
取り消し線 <span style="text-decoration: line-through;"> <s>
下付き文字 <sub> 指定できず
上付き文字 <sup> 指定できず
左揃え <div style="text-align: left;"> <div style="text-align: left;">
中央揃え <div style="text-align: center;"> <div style="text-align: center;">
右揃え <div style="text-align: right;"> <div style="text-align: right;">
両端揃え 指定できず <div style="text-align: justify;">
箇条書きリスト <ul><li> <ul><li>
番号付きリスト <ol><li> <ol><li>
インテンド <div style="padding-left: 30px;"> <blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;">
水平線 <hr/> <hr/>

戻る