TechNote

事務屋のおぼえがき

【Python】PDFの表テーブル読込ライブラリ(pdf2txt、tabula-py)使い方・使用感

PDF読み込みの必要が生じたので使ってみたメモ。どちらも用途をうまく使い分けるとかなり使えそう。


1.pdf2txt.py

pdf2txt.pyはPDFをテキスト化してくれるもの。特にテーブル読み取り用というわけではないがテーブル内部の文字列も読み取ってくれるため、読み取り⇒空白をカンマへ変換⇒CSV保存のような使い方で表の読み込みにも使えそう。

インストール

pip install pdfminer.six

使い方

コマンドライン上で出力ファイル名(.txt)と入力ファイル名(.pdf)を指定することでpdfファイルをテキストファイルに書き出してくれる。

python pdf2txt.py [オプション] -o [出力ファイル名]  [入力ファイル名]

オプション値指定できるのは、文字間隔:M、単語間の間隔:W、行間隔:L、縦読み:V。パラメータを指定しなかったらデフォルト値としてM= 1.0、 W=0.2、L=0.3、横読みとなる。
MとLの値をうまく調整すればいい具合に引っ張ってくれるとのことだったがチューニングのコツはよくわからなかった。また別の機会に試したい。

実例

python pdf2txt.py -M 6.0 -L 10.0 -o d:\B9D00000.txt d:\B9D00000.pdf

詳しくはここ。
https://www.unixuser.org/~euske/python/pdfminer/

2.tabula-py

tabula-pyは表形式をテキスト化するのに特化したライブラリ。

インストール

pip install tabula-py

実はこれだけで使おうとしても以下のようなJavaNotFoundErrorが出て実行できない。tabula-pyはJavaのライブラリをラップしたものであるため、Javaをインストールしないと正常に動いてくれない。

JavaNotFoundError: 'java' command is not found from this Python process.

Windowsの場合はOracleのサイトから「jre-〇〇〇-windows-x64.exe」をダウンロードする必要がある。

ダウンロードしようとするとサインインが求めれらた。最近はJavaのインストールにOracleのアカウント登録が必要っぽい(※調べたらかなり前からっぽい)。なので登録をしてからあらためて上のやつをダウンロード。

使い方

コマンドライン上ではなくPythonスクリプト内で書いていく形になる。
読み込んだものをDataFrameに突っ込む例。

pdffile1 = 'd\:sample.pdf'

dfs = tabula.read_pdf(pdffile1, lattice=True , pages = 'all')

#すべてのリストを表示したい場合
for df in dfs:
    print(df)

    #ちなみに↑のfor文内で
    #df.to_csv("d:\xxx.csv",encoding="shift-jis", index=None)
    #としても各リストは出力されず、最後のリストしか出力されない?

#1つ目のみを表示
print(dfs[0])

オプション
lattice:表の罫線を認識してくれる
pages:ページを指定できる。'2,4'とか'all'とかで指定。

1つのPDF内に表がいくつか存在する場合は、上記のfor df in dfs:の書き方で下記のようにすべてのテーブルを表示してくれる。print(dfs[0])だと一番最初の表のみ。
ちなみに上記のfor文内で df.to_csv("d:\xxx.csv",encoding="shift-jis", index=None)などとしても一番最後の表しかcsvに出力してくれない。この辺はまだ正確な仕様を調べていない。

3.まとめ

ここには記載していないが、いろんな種類のPDFファイル読み込みを試してみた感想としては「PDFにもいろいろあり、一筋縄ではいかない」ということ。

存在するPDFごとに加工の仕方(スペースを除去するとか、カンマに変換するとか、全角を半角に変換するとか、ある決まった位置の値を取得するとか)を変える必要があるので、基本書き捨てコードを書くことになりそう。

ただ、業務などで毎月あるサイト等から定期取得するような決まった作りのPDFについては、あるひと月分に対して一度だけ「読み込み→加工」のスクリプトを作成したら毎月同じものでいけるはずなので、書き捨てにはならなそう。