Py淡

Python, Python, Python! In the spirit of "import antigravity"

bibtexマネージャーを作ってみる。その1:BibtexParserを使う。


JabRefやCiteulikeを長く使ってきましたが、以下の機能が欲しいのでCiteulikeを補完するツールとして自分用bibtexマネージャーを作ってみようと思います。



欲しい機能

  • シンプルなJabRefのインターフェイスっぽいもの。
  • タブグループマネージャー機能。Bib managerから、いくつかの関連する文献をまとめて複数のタブとしてPDF Viewerで開いたり、グループを切り替えたりしたい。
  • ポータブルなアプリでDropboxに入れて置けると一番良い。
  • JabRefみたいに選択した論文をいろいろな雑誌のReferenceのフォーマットでワードに貼ればいいだけなリッチテキスト形式として出力したい。Citeulikeでは有料オプション
  • bibtexのインポートをサポート(当たり前)
  • フリー

 


まずはすでに条件を満たすPythonでできたツールがないかググるPythonを使ったものはコマンドラインツールばっかり見つかる。

biblio-py

yapbib: Yet Another Python BIBliography manager toolというコマンドラインツールがメインプログラム。bibextract.pyではLaTex中で引用した論文のリストとか得られるようだ。

BibtexManager-Python

https://github.com/MasterOdin/BibtexManager-Python
コマンドラインツール。bibtextエントリーをPretty printする感じ。

BibReview

f:id:i-namekawa:20150716180054p:plain

https://pypi.python.org/pypi/BibReview


やっと見つかったGtKアプリ。JabRefのインターフェイスとはかなり違う感じ。

Pybliographer

f:id:i-namekawa:20150716180055p:plain

 

http://pybliographer.org/Welcome

GNOMEがターゲットのようなのでLinuxオンリーか。Windowsに移植するのもつらそう。見た目は好きなんだけど。



結局なさそうなので自分で作る。

計画としては、


新しい論文を見つけた時はすでにウェブブラウザを開いてそのページを開いているわけで、これをCiteulikeに追加するまではCiteulikeのarticleインポーターが秀逸なので、これを使う。

ただし、Citeulikeインターフェイスはカスタマイズに限界があり自分好みにはできなかったので、JabRefっぽい使い勝手のフロントエンドGUIを慣れたwxPythonでサクッと最低限必要なものだけ作る。

やはり自分の好きなPDFビュワーで論文を開いて、蛍光ペンツールを使ったりしたいのが、ウェブアプリケーションだと読みたい論文のPDFをPDFビュワーで開く部分が難しい。あとは孫引きしたりされたりしている関連する論文も一緒に開く場合が多いので、これをグループにして登録し、まとめて開いたりしたい。ここまではやればできる。

欲を言えば、このグループの論文に対しての著者が同じとか、孫引きされているとかキーワードの相関が高いとかから関連性の順位を決定し、これでLibraryをソートできたりすると素晴らしい。Citeulike上のライブラリが大きくなってくるとすでに登録してある論文を見つけるのに苦労するので、この辺をできるようにするのが最大のモチベーション。

CiteulikeからBibTexを手動できれば自動でライブラリをインポートしてCiteulikeのフロントエンドとして使いたい。bibtexの読み込みはいろいろライブラリがあるので、いいのを選ぶ。

BibtexParser

https://bibtexparser.readthedocs.org/en/latest/

これをつかってJabRefやCiteulikeからインポートする計画。

pip install bibtexparser

Pure pythonモジュールっぽいし、pipでインストール。


チュートリアルを読むとbibtextの読み込みは簡単で、

import bibtexparser
with open('bibtex.bib') as bibtex_file:
    bib_database = bibtexparser.load(bibtex_file)


このbib_databaseオブジェクトをdumpしてbibtexファイルにエクスポートも簡単。

bibtex_str = bibtexparser.dumps(bib_database)


bib_databaseクラスのメソッドをみてみるとentriesで各論文エントリーのメタデータがdictになった要素をもつリストとして格納されているようだ。

しかし、エントリーをデータベースに追加したり削除、マージするAPIが用意されていない上、最終的にエクスポートするにはbib_databaseオブジェクトが必要なので編集できないのは困った。

しょうが無いのでbibdatabaseクラスを定義しているソースを覗き見するとクラスはえらく単純。

newBibDb = bibtexparser.bibdatabase.BibDatabase()

newBibDb.entries = sublist


という感じで、自分でエントリー追加・削除したリスト(sublist)をつくって、新しくインスタンス化したbibdetabaseクラスオブジェクトのself.entriesを上書きしてやればいいと見通しがついた。これでdumpでエクスポートできるはず。

この質問をみるとpybtexというライブラリもあって、こっちでは一応追加・削除とかできそうだが、http://pybtex.sourceforge.net/の方のドキュメンテーションが未完成かつ古いのでメンテイナーがどっか入ってしまったパターンかもしれないので、ドキュメンテーションがかっこいいbibtexparserで頑張ることにする。

ランチャー部分の実装


subprocessモジュールを使って簡単にグループタブを開く部分を実装してみる。

import subprocess
from time import sleep

def PDFopen(files, 
            libraryPath = 'C:\\Dropbox\\PathToYour\\PDFs'
            execPath = r'C:\Path2\PDF-XChangeViewerPortable.exe'
            ):
    
    if type(files) is not list:
        raise ValueError('The first arg should be a list containing more than one file path')
        return

    P = subprocess.Popen([execPath, files[0]])
    sleep(2) # wait until the instance is ready for more files

    for pdf in files[1:]:
        P = subprocess.Popen([execPath, pdf])


if __name__ == '__main__':

    files = [
    'Einstein1997.pdf',
    'Heisenberg2005.pdf',
    'Kandel2009.pdf',
    'Galileo1662.pdf',
    ]
    PDFopen(files, libraryPath)

こんなのでとりあえずやりたいことができた。ぶっちゃけこれだけあれば十分・・・。
さて、あとはGUIなので次回はwxPythonの話。