BeautiflSoup + SQLAlchemyを使ってEvernoteの全ノートのテキストを抽出してSQLiteに保存する
こんにちは。むさしです。 しばらく更新してませんでしたが再開していきます^^;
最近はゲーム開発は止まっていて、仕事の関係でpythonを触っています。
evernoteの全文を抽出する必要がありその時に使った方法を公開します。 一番初めに思いつくことはEvernoteAPIを使う方法ですが色々面倒ですよね。 そこで、全ノートをhtml形式で出力してBeautifulSoupでスクレイピングする方法を紹介していきます。
Evernoteの全ノートをhtml形式で出力する
まず、Command + A
で全ノートを選択します。そこからノートをエクスポートします。
出力する形式はhtmlを選択してください。
今回はこれをmynoteとしてデスクトップに保存します。
mynoteのindex.htmlには出力したファイル全てのノートの目次になっていて、各htmlファイルへのリンクがあるのでそれを利用します。
手順としては
- index.htmlから出力するノートのurlを抽出する。
- url先からテキストを抽出する。
- それをSQLiteに保存する。
というものです。
BeautifulSoupを使ってスクレイピングする
そもそもスクレイピングとはwebサイトから特定の情報を抽出したりする行為です。スクレイピングできるpythonのモジュールはいくつかありますが今回はBeautifulSoupというものを使っていきます。
まず、BeautifulSoupでインストールしましょう。
$ pip install beautifulsoup4
次にBeatifulSoupオブジェクトを作成しましょう。
import urllib2 from bs4 import BeautifulSoup html = urllib2.urlopen("http://~ ~ ~") soup = BeautifulSoup(html)
これでスクレイプする準備が出来ました。
あとは詳しくは公式ドキュメントをご覧ください。
日本語で訳されているのでとっつきやすいと思います。
今回使うのはsoup.get_text()
とsoup.find_all("a")
とnote_url.get("href")
のみです。
SQLAlchemyを使ってデータベースに保存する
SQLAlchemyとはORマッパーと言って、SQLで記述しなくてもデータベースとやりとりができる便利なやつです。 インストールはpipで行いましょう。
$ pip install sqlalchemy
全て説明すると長くなるのでこちらを確認ください。
また、こちらの日本語訳もありますがかなり古いのです。 ただ、英語よか読みやすいと思うのでこちらも参考にしてください。
http://omake.accense.com/static/doc-ja/sqlalchemy/ormtutorial.html
今回はメインはBeautiflSoupに関してなので後日分けて説明します。
Evernoteの文章を抽出する
これで準備は出来たのでスクレイピングしていきましょう。
まずはノートから文章のみを抽出して返す関数をつくります。
def scrape_evernote(url): tmp_url = "file:///(ノートのディレクトリ)" + url.encode('utf-8') html = urllib2.urlopen(tmp_url) soup = BeautifulSoup(html) all_items = soup.get_text() note = "" for word in all_items: note = note + word return note
最初の3行はBeautifulSoupオブジェクトを生成します。
all_items = soup.get_text()
でurl先の全文を取得します。
そのあとの
note = "" for word in all_items: note = note + word
という部分は、get_text()
で取得できる文字は一文字づつ配列に入っているので配列全てを結合させる必要があります。
抽出したテキストをSQLiteに保存する
次に抽出したテキストをSQLiteに保存する関数を作ります。
Base = sqlalchemy.ext.declarative.declarative_base() db_url = "sqlite+pysqlite:///evernote.sqlite3" engine = sqlalchemy.create_engine(db_url, echo=True) Base.metadata.create_all(engine) # セッションを作成 Session = sqlalchemy.orm.sessionmaker(bind=engine) session = Session() #evernoteのモデルクラス class Evernote(Base): __tablename__ = 'mynote' id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) title = sqlalchemy.Column(sqlalchemy.String) note = sqlalchemy.Column(sqlalchemy.String) #...(略)... def scrape(): #indexから全ノートのurlを取得する index_url = "file:///(ノートのディレクトリ)/index.html" index_html = urllib2.urlopen(index_url) index_soup = BeautifulSoup(index_html) all_url = index_soup.find_all("a") for note_url in all_url: title = note_url.get_text() note = scrape_evernote(note_url.get("href")) evernote = Evernote(title=title, note=note) session.add(evernote) session.commit()
初めにBase
を作ります。(あんまりよくわかっていません^^;)
そのあと、ノートのモデルを作成します。
class Evernote(Base): __tablename__ = 'mynote' id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) title = sqlalchemy.Column(sqlalchemy.String) note = sqlalchemy.Column(sqlalchemy.String)
今回はシンプルにノートのタイトルと内容だけ保存します。
db_url = "sqlite+pysqlite:///evernote.sqlite3" engine = sqlalchemy.create_engine(db_url, echo=True) Base.metadata.create_all(engine) # セッションを作成 Session = sqlalchemy.orm.sessionmaker(bind=engine) session = Session()
あとはSQLiteの保存場所をdb_url = "sqlite+pysqlite:///evernote.sqlite3"
で指定してセッションを作成します。
Base.metadata.create_all(engine)
はevernote.sqlite3
が存在しなかったら自動でevernote.sqlite3
を作ってくれるます。
また、モデルクラスがあれば自動でテーブルの作ってくれて大変便利です。
最後にはindex.html
から各ノートのタイトルとurlを取得します。
index.htmlの各ノートへのリンクは
<a href="ノートのurl">ノートのタイトル</a>
という構成になっているのでindex_soup.find_all("a")
で全部のaタグを取得します。
各タグはそれぞれ配列で格納しているので、取り出してaタグからリンク先のurlとタイトルを取得します。
そのurlから先ほど作ったscrape_evernote()
を使ってテキストを抽出します。
最後にコミットしてSQLiteに保存します。
これで抽出は完了です。
SQLiteで出力ではなくて例えばtxtデータに出力したい場合は
def scrape_txt(): file = open('evernote_text.txt', 'w') #indexから全ノートのurlを取得する index_url = "file:///(ノートのディレクトリ)/index.html" index_html = urllib2.urlopen(index_url) index_soup = BeautifulSoup(index_html) all_url = index_soup.find_all("a") for note_url in all_url: title = note_url.get_text() file.write(title) note = scrape_evernote(note_url.get("href")) file.write(note) file.close()
とすれば可能です。 もちろんcsv形式の出力も出来ます。
まとめ
初めの方にも書きましたが大まかの手順は
となっています。 今回はテキストのみ抽出しましたが、ノート内の画像がノートのタイトルと同じ名前のフォルダに保存されています。 これをうまく使えばevernote内の画像を全て抽出することも可能だと思います。
完成データをgitにあげています。 https://github.com/musashi13z/evernote-scrape