このメモについて
もういまは Evernote から別の環境に乗り換えてしまったけど・・・
2022年1月頃、Evernote から他に乗り換えるためにノートのデータをテキスト化することを検討していた。
そのときのメモ。
もう使えるかわからないし、情報の正しさもいまさら検証していないけど、ここに置いておく。
データファイル仕様調査
Evernote からエクスポートした HTML は「単一のWebページ」も「複数のWebページ」もほぼ同じ HTML 構造。
ノート1つ分のデータは <div class="html-note"> に入っている。
タイトルは <meta itemprop="title" content="2022/01/30"> に。
ノート本文は en-note 要素の中。
ノートの本文は en-note 要素に入ってる。
<div class="html-note">
<meta itemprop="title" content="2022/01/30">
<meta itemprop="created" content="20220129T231052Z">
<meta itemprop="updated" content="20220129T231654Z">
<meta itemprop="tag" content="WriteNote">
<note-attributes>
</note-attributes>
<h1
style="font-family: Source Sans Pro,-apple-system,system-ui,Segoe UI,Roboto,
Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;
overflow-wrap: break-word;
page-break-inside: avoid;
">
2022/01/30
</h1>
<en-note class="peso">
<div class="para">Hello, World.</div>
<div class="para">こんにちは、世界。</div>
<div class="para">🐱🍣</div>
<div class="para">[01:01]</div>
<div class="para"><br></div>
<div class="para">CSV (カンマセパレーティッドバリュー)</div>
<div class="para">123,abc,あいう</div>
<div class="para">"123","abc","あいう"</div>
<div class="para"><br></div>
<div class="para">HTML風に書いたテキスト</div>
<div class="para"><div></div>
<div class="para"> <div></div>
<div class="para"> <span>HTML風</span></div>
<div class="para"> </div></div>
<div class="para"></div></div>
<div class="para"><br></div>
<div class="para">Markdown風に書いたテキスト</div>
<div class="para">```</div>
<div class="para">4.times {</div>
<div class="para"> puts 'Markdown風'</div>
<div class="para">}</div>
<div class="para">```</div>
<div class="para"><br></div>
<div class="para">タブ</div>
<div class="para">TAB-BEFORE TAB-AFTER</div>
<div class="para">TAB-BEFORE TAB-AFTER</div>
<div class="para"><br></div>
<div class="para">空白2文字</div>
<div class="para">TWO-SPACES-B TWO-SPACES-A</div>
<div class="para">TWO-SPACES-B TWO-SPACES-A</div>
<div class="para">[08:10:51]</div>
<div class="para"><br></div>
</en-note>
</div>
Evernote から enex 形式でエクスポートしたものは
ノート1つ分のデータは <note> 要素に入っている。
タイトルは <title>2022/01/30</title> 要素に。
ノート本文は <content> 要素の中に <![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?> で埋め込み。
<title>2022/01/30</title>
<created>20220129T231052Z</created>
<updated>20220129T231654Z</updated>
<tag>WriteNote</tag>
<note-attributes>
</note-attributes>
<content>
<![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note>
<div>Hello, World.</div>
<div>こんにちは、世界。</div>
<div>🐱🍣</div>
<div>[01:01]</div>
<div><br /></div>
<div>CSV (カンマセパレーティッドバリュー)</div>
<div>123,abc,あいう</div>
<div>"123","abc","あいう"</div>
<div><br /></div>
<div>HTML風に書いたテキスト</div>
<div><div></div>
<div> <div></div>
<div> <span>HTML風</span></div>
<div> </div></div>
<div></div></div>
<div><br /></div>
<div>Markdown風に書いたテキスト</div>
<div>```</div>
<div>4.times {</div>
<div> puts 'Markdown風'</div>
<div>}</div>
<div>```</div>
<div><br /></div>
<div>タブ</div>
<div>TAB-BEFORE TAB-AFTER</div>
<div>TAB-BEFORE TAB-AFTER</div>
<div><br /></div>
<div>空白2文字</div>
<div>TWO-SPACES-B TWO-SPACES-A</div>
<div>TWO-SPACES-B TWO-SPACES-A</div>
<div></div>
<div>[08:10:51]</div>
<div><br /></div></en-note> ]]>
</content>
</note>
データファイルからテキストを抽出する Python スクリプト
import sys
import os
import re
from html.parser import HTMLParser
from bs4 import BeautifulSoup
from bs4.element import ResultSet, Tag
# Evernote からエクスポートした HTML ファイル (複数のノート要素を含む HTML に対応) を
# ノート要素 (<div class="html-note">) のリスト (ResultSet) で返す
def get_html_note_list(input_html_file: str) -> ResultSet:
with open(input_html_file, mode='rt', encoding='utf-8') as file:
soup = BeautifulSoup(file, 'html.parser')
return soup.find_all('div', {'class': 'html-note'})
# en-note 要素をテキスト化するクラス
# e.g. <en-note class="peso"><div class="para">Hello</div><div class="para"><br></div></en-note>
class EnNoteElementToText(HTMLParser): # HTMLParser を継承
text: str = '' # テキスト化した文字列を溜め込む
def handle_endtag(self, tag): # div 要素の終了タグが来たら改行を入れる
if tag == 'div':
self.text += '\n'
def handle_data(self, data): # 要素内のテキストを溜め込む
self.text += data.replace('\xa0', ' ') # が来たら半角スペースに置き換える
# ノート1つを表すクラス
class Note:
def __init__(self, html_note: Tag):
# タイトルを抜き出す
# e.g. <div class="html-note"><meta itemprop="title" content="2022/01/30">
itemprop_title = html_note.find('meta', {'itemprop': 'title'})
self.title: str = itemprop_title['content'] # タイトル
# 本文をテキスト化する
en_note = html_note.find('en-note')
en_note_html = str(en_note)
parser = EnNoteElementToText()
parser.feed(en_note_html) # en-note 要素をテキスト化
parser.close()
self.content: str = parser.text # テキスト化した本文
# ノート情報を標準出力へ出力
def print_note(note: Note) -> None:
print('-------------------------------------------------------------------')
print('Title: ' + note.title)
print('-------------------------------------------------------------------')
print(note.content, end='')
print('-------------------------------------------------------------------')
print()
# 出力ファイル名を決める
def get_text_file_name(note: Note) -> str:
return re.sub(r'[¥\\/:*?"<>|@.]', '', note.title) + '.txt' # ファイル名に使いたくない文字を削る
# ノート情報をテキストファイルへ出力
def note_to_textfile(note: Note, output_file: str) -> None:
with open(output_file, mode='xt', encoding='utf-8') as file: # すでに存在している場合は FileExistsError
file.write(note.title + '\n')
file.write('\n')
file.write(note.content)
file.write('\n')
# メイン処理
input_html_file = sys.argv[1] # Evernote からエクスポートした HTML ファイルのパス
html_note_list = get_html_note_list(input_html_file) # HTML ファイルを <div class="html-note"> 毎に分割してリスト化
print('ノートの件数: ' + str(len(html_note_list)))
print()
for html_note in html_note_list: # ノートを1つずつ処理
note = Note(html_note) # <div class="html-note"> 要素からタイトルと本文をテキスト化
print_note(note) # ノート情報を標準出力へ出力
output_text_file = get_text_file_name(note) # 出力ファイル名を決める
note_to_textfile(note, output_text_file) # ノート情報をテキストファイルへ出力
print('出力ファイル名: ' + output_text_file)
tags: evernote python
Posted by NI-Lab. (@nilab)