ノートコンテンツからタグを生成・付与するプログラムの実装(2)
ノートコンテンツからタグを生成する
ノートコンテンツからタグを生成する処理を見ていきます。
# 形態素解析器の初期化
_t = Tokenizer()
# ~中略~
def _generate_tag(content, tag_dict):
'''指定コンテンツからタグを生成する。
Args:
content: タグを生成する対象コンテンツ
tag_dict: タグとして抽出する文字列を格納した辞書。キーは小文字化した文字列
Returns:
生成したタグのSet
'''
# ENMLタグの除去(1)
notags = strip_enml(content)
u_notags = unicode(notags, encoding='utf-8')
# 形態素解析の結果から固有名詞リストの取得(2)
tokens = [token for token in _t.tokenize(u_notags) \
if token.part_of_speech.split(',')[1] == u'固有名詞']
tags = set()
for t in tokens:
word = t.surface
# 小文字化して比較
lower = word.lower()
# タグ辞書に存在する固有名詞のみを抽出(3)
if tag_dict.has_key(lower):
tags.add(tag_dict[lower])
return tags
def strip_enml(enml_str):
'''EvernoteノートコンテンツのXHTML (ENML) タグを除去する
Args:
enml_str : ENML文字列
Returns:
ENMLタグを除去した文字列
'''
tree = etree.fromstring(enml_str)
return etree.tostring(tree, encoding='utf8', method='text')
(1)strip_enml関数を呼び出してENMLのタグを除去します。strip_enml関数では、XML・HTML処理ライブラリlxmlを使って、ENMLをDOMツリー化してタグ以外のテキスト部分を取得することで、ENMLのタグを取り除いています。
(2)ENMLタグを除去したノートデータを、形態素解析した分割文字列から固有名詞のみを抽出します。_tはグローバル変数で初期化しています。
Janomeの形態素解析結果はTokenオブジェクトのリストで返されます。Janomeの仕様については公式サイトを参照してください。
| 属性 | 説明 |
|---|---|
| surface | 表層形 |
| part_of_speech | 品詞、品詞細分類1~3のカンマ区切り |
| infl_type | 活用型 |
| infl_form | 活用形 |
| base_form | 原形 |
| reading | 読み |
| phonetic | 発音 |
| node_type | ノードタイプ。システム辞書(SYS_DICT)、ユーザー辞書(USER_DICT)、不明(UNKNOWN)のいずれか |
(3)Qiitaタグ辞書に存在する固有名詞のみを抽出します。
生成したタグをノートに付与する
生成したタグファイルを読み込んで、ノートへタグを付与します。
def assign_tags(note_store, tag_fp):
'''指定ファイルのタグを使ってノートへタグを付与する。
Args:
note_store: Evernoteノートストア
tag_fp: 付与するタグを記録したファイル
'''
for line in tag_fp:
# ノートGUIDと付与するタグを取得する(1)
tags = json.loads(line)
# ノートを取得する(2)
n = note_store.getNote(tags['note_guid'], False, False, False, False)
# ノートに既存タグがある場合、重複しないタグのみを抽出する(3)
assign_tags = tags['tag_list']
if n.tagNames is not None:
assign_tags = set(n.tagNames.extend(assign_tags))
# ノートにタグを付与する(4)
n.tagNames = assign_tags
note_store.updateNote(n)
(1)タグファイルを1行ずつ読込み、JSON文字列をデコードします。
(2)タグファイルのノートGUIDをキーに、NoteStoreのgetNote()を使ってノートオブジェクトを取得します。ここではノートに付与されているタグリストのみが取得できればよいため、コンテンツや添付ファイル等を取得するかどうかを指定する第2引数以降は全てFalseを指定しています。
Types.Note getNote(Types.Guid guid,
bool withContent,
bool withResourcesData,
bool withResourcesRecognition,
bool withResourcesAlternateData)
throws Errors.EDAMUserException, Errors.EDAMSystemException, Errors.EDAMNotFoundException
(3)一度setオブジェクトに変換することで、既にノートに付与されているタグと重複しないタグのみを抽出しています。
(4)ノートにタグを設定し、NoteStoreのノート更新処理updateNote()を呼び出しています。ノートへのタグ付与はNote.tagNamesにリストをセットすることで可能です。Evernoteアカウント内で存在しないタグを指定した場合はタグが新規作成され、既に存在するタグは重複して作成されることはありません。
サンプルプログラムを実行してみよう
これで必要な関数が実装できました。実装した関数を呼び出すメイン関数を作って実行してみましょう。
# ノートへ付与するタグの一時保存先ファイル
TAG_FILE_PATH = 'note_tag.jsons'
# ~中略~
def main():
'''メイン関数。
Evernoteノートコンテンツからタグ情報を生成し、ファイルへ出力する。
ファイルを読み込んでノートへタグを付与する。
'''
try:
# Evernoteクライアントの初期化
client = EvernoteClient(token='Set your developers token')
note_store = client.get_note_store()
# ノートコンテンツからタグを生成し、ファイルへ出力する(1)
with open(TAG_FILE_PATH, 'w') as tag_fp:
generate_note_tag(note_store, tag_fp)
# !!注意!!
# 生成されたタグファイルが妥当であることを確認した上で
# 下記コードのコメントアウトを外してノートへのタグ付与を行ってください
# タグファイルを使ってノートへタグを付与する(2)
# with open(TAG_FILE_PATH, 'r') as tag_fp:
# assign_tags(note_store, tag_fp)
except Exception as e:
print('予期せぬエラーが発生しました。')
traceback.print_exc()
else:
print('finished!!')
if __name__ == '__main__':
main()
(1)Evernoteのノートコンテンツからタグを生成し、結果をファイル出力するgenerate_note_tag()関数を呼び出します。
(2)(1)で生成したタグファイルを使ってノートへタグを付与します。コメントにも記載している通り、最初はコメントアウトした状態で実行し、生成されたタグファイルの内容を確認してください。ノート内容に対して生成されているタグが問題なければ、コメントアウトを外して実行してください。
ノートの件数によっては処理時間がかかります。また、Evernote APIのレート制限にかかってエラーとなることがあります。APIのレート制限の問題については、エラーをハンドリングしてリトライする、プロキシオブジェクトを実装するといった対策が可能です。APIのレート制限エラーのハンドリングについては前述した公式サイトの情報を参照してください。
筆者のEvernoteアカウントで試した実行結果の一部です。
実行結果その1
ノート内容:※WikipediaのTensorFlowをWebクリッピングしたもの。
付与されたタグ:C,google,Python,Twitter,Ubuntu,iOS,Mobile,AI,Linux,TensorFlow,Android
※C++がCになっていました。この辺りはJanomeでユーザー定義辞書を使うといった対策が必要そうです。
実行結果その2
ノート内容:Hadoop運用管理ツールApache Ambariの調査メモ
付与されたタグ:Web,Windows,hadoop,rest,Kafka,api,UI,hive,HTTPS,Linux,Spark,SSH
まとめ
Evernote APIの基本的な使い方を解説し、ノート内容からタグを付与するプログラムを作りました。具体的な活用方法を通して、手軽に利用できることをイメージいただけたのではないでしょうか。
Evernote APIを使って用途に特化したアプリケーションやサービスを作ってみるのもよいですし、もっとハードルを下げて個人的なツールから作ってみるのも面白いと思います。APIを活用することですぐに動く実用的なものが作れるのは楽しいものです。プログラミング学習にもおすすめします。
