"BOKU"のITな日常

還暦越えの文系システムエンジニアの”BOKU”は新しいことが大好きです。

PDFからテキストデータを抜く・・を試してみました(pdfminer.six)/Python

PDF形式のデータを何か処理する時のインプットデータにしたい時があります。 

とりあえず、PDFからテキストくらい抜き出せないかな・・と思って試してみました。

f:id:arakan_no_boku:20180824234522j:plain

 

 

PDFは色々なバージョンがある

 

一口にPDFと言っても、様々なバージョンがありますし、暗号化もできます。 

そのへんの事は、Wikipediaにも乗ってます。

Portable Document Format - Wikipedia

 プログラミングでデータとして使うには、これだけでも面倒な形式ではあります。

でも、まあ試してみます。

 

PythonでPDFからテキストを抜くモジュール

 

pipでPDFをキーワードで検索すると、ヒットする数に驚きます。 

htmlをPDFに変換するとか、Markdown形式ファイルをPDF化するなど、特定の用途に適したものがいっぱいあります。 

テキストを抽出する用途で探すと、「pdfminer」が良さげでした。 

口コミを見る限り、かんたんにつかえて、テキスト抽出の精度も高そうです。

さっそく、試してみます。 

 

3種類のpdfminer

 

pdfminerと一口に言っても、種類があります。

pip search pdfminer で探すと、3つのバージョンがでてきます。

  • pdfminer   / python2.xx系
  • pdfminer3k  / python3.xx系
  • pdfminer.six  / python2/3系共通

 

でも、現在でも更新されているのは「pdfminer.six」だけみたいです。

github.com

 

pdfminer.sixをインストール

 

他のも使えるみたいですが、python2と3でコンパチブルなのも、pdfminer.sixだけだし、これを使わない理由が特に見当たりません。 

インストールするのは、pdfminer.sixです。

pip install pdfminer.six

 

付属のツールで動作確認

 

pdfminer.sixには、pdf2txt.py というツールが付属してます。 

インストールが正常に終了していれば、anacondaをインストールしたフォルダ(activateして仮想環境にしている場合はenvsの仮想環境名フォルダの下)のScriptsフォルダにインストールされてます。 

Linux環境なら、パスが通っているのでそのまま実行できます。

でも、windowsでは無理なので、カレントフォルダにコピーして使います。

サンプルにするPDFは、こういうものにします。

f:id:arakan_no_boku:20190223192039j:plain

これを「sample.pdf」として保存して、作業フォルダに置き、同じところに「pdf2txt.py」をコピーして、以下のようにします。

python pdf2txt.py sample.pdf

  抽出されたテキストはこんな感じでした。

キーワー ド:ビ ッグファイブパーソナリテ ィ 質問紙法 尺度構成 , 信頼性, 妥当性

問題

Openness to Experience (Openness; 開放性)で

ある 。

近年のパーソナリティ特性論において, もっと

日本における語裳研究は背木 ( 1971 ) の先駆的

も確固たる 知 見を積み重ねているのは. Big Five

な研究に始まり,その後も継続的に行われている

( ビッグファイブ; Goldberg, 1990, 1992 ) や Five

(柏木・辻・藤島・山田 2005 ;柏木 ・和田・ 青

Factor Model ( 5 因 子モデル; ~、1cCrae & Costa,

木 , 1993; 村 上, 2003; 和田, 1996 ) 。 また , 日

1987 ) である 。

 化けたりはしてませんが、改行や空白がランダムにはいっているので、テキストデータとして処理するには、ちょっとめんどくさいデータになってます。

 

空白・改行を詰めてテキストを抽出する関数を書いてみる

 

付属のツールをそのまま使うのでなく、pdfminerを使ってテキストを抽出するpythonプログラムを書きます。 

最後に、pdfminerでテキストを抽出後に正規表現を使って、半角空白・全角空白・改行・タブを除去します。 

 

ソース全文

 

# -*- coding: utf-8 -*-

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams
from pdfminer.pdfpage import PDFPage
from io import StringIO
import re 

def gettext(pdfname):
    # PDFファイル名が未指定の場合は、空文字列を返して終了
    if (pdfname == ''):
        return ''
    else:
        # 処理するPDFファイルを開く/開けなければ
        try:
            fp = open(pdfname, 'rb')
        except:
            return ''
        
    # リソースマネージャインスタンス
    rsrcmgr = PDFResourceManager()
    # 出力先インスタンス
    outfp = StringIO()
    # パラメータインスタンス
    laparams = LAParams()
    # 縦書き文字を横並びで出力する
    laparams.detect_vertical = True
    # デバイスの初期化
    device = TextConverter(rsrcmgr, outfp, codec='utf-8', laparams=laparams)
    # テキスト抽出インタプリタインスタンス
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    # 対象ページを読み、テキスト抽出する。(maxpages:0は全ページ)
    for page in PDFPage.get_pages(fp, pagenos=None, maxpages=0, password=None,caching=True, check_extractable=True):
        interpreter.process_page(page)
    #取得したテキストをすべて読みだす
    ret = outfp.getvalue()
    # 後始末をしておく    
    fp.close()
    device.close()
    outfp.close()
    # 空白と改行をとりさり一塊のテキストとして返す
    return re.sub(r"\s| ",'',ret)

この関数の使い方

 

テキストに出力するときは、こうします。

import pdf2text as pt

ret = pt.gettext('C:\\myWork\\00_python\\workspace\\src\\proc\\sample.pdf')
print(ret)

 

PDFサンプル

 

さっきの一段組みのサンプルで試すと、まあまあの結果でした。

今回はさらに難易度をあげて、動作確認用のPDFを2段組のちょっと複雑なものにしてみます。

こういう感じのものです。

f:id:arakan_no_boku:20180103145351j:plain

 

 

出力結果です。

 

キーワード:ビッグファイブパーソナリティ質問紙法尺度構成,信頼性,妥当性問題OpennesstoExperience(Openness;開放性)である。近年のパーソナリティ特性論において,もっと日本における語裳研究は背木(1971)の先駆的も確固たる知見を積み重ねているのは.BigFiveな研究に始まり,その後も継続的に行われている(ビッグファイブ;Goldberg,1990,1992)やFive(柏木・辻・藤島・山田2005;柏木・和田・青Model(5因子モデル;~、1cCrae&Costa,rotcaF木,1993;村上,2003;和田,1996)。また,日1987)である。

 

ざっくり、見たときは良さげだったのですが、よーく見ると、二段組の処理ができてなくて、左と右の文章が混じってしまってますけどね。 

まあ。

当然でしょうね。

ここまでの結果として、段組みとかの複雑な文章は、文字数カウントや単語分割して分析するような用途ならなんとかなっても、きちんとした文章としてとりだすのは難しいとしか言えません。

 

うまく行くものもあったけど

 

上記のpythonプログラムで色々なPDFファイルから、テキストを抽出してみました。 

うまく行ったものは、もちろんありましたが、自分の手持ちのPDFだと、うまくいかないものが多いですね。 

テキストに見えていても画像がはりついていて、抽出できないとか。 

ファイルが暗号化されていて読めないとか。 

読めて、テキストが抽出できても、2バイト文字が化けるとか。 

特に最後の文字化けはかなりうざいです。 

PDFで見ていると同じように見えるのに、テキストを抽出してみると、例えば、以下のように表示されたりします。

蜘蛛(cid:12506)糸芥川龍之介(cid:13268)(cid:10187)(cid:13269)(cid:13268)(cid:10186)(cid:13269)一(cid:12680)(cid:12695)(cid:12765)(cid:12681)(cid:12693)(cid:12734)

(cid:12506)というのはアドビ社のCIDフォントに割り振られている番号です。

まあ、それがそのまま出力されている=一致する2バイト文字を見つけられなかった・・ということなのでしょう。 

 

やってみた結論

 

PDFからのテキストの抜き出しは、「やってみないと、上手く行くかどうかわからない」ものだということが良くわかりまいした。 

プログラム他で 加工や解析をするインプットデータとして受け取る形式としては、PDFファイルは適切ではないなと思いますね。

個人的には・・ですけど。

ではでは。