PDF からテキストを抽出する Python コード例【pdftotext.exe】

PDF からテキストを抽出ちゅうしゅつする Python コードれいです。

Python から Xpdf toolsエックス ピーディーエフ ツールズpdftotext.exeピーディーエフ トゥ テキスト を呼び出して、テキストを抽出します。

pdftotext.exeピーディーエフ トゥ テキスト は、処理が速くて、大量の PDF を扱うときにとても有用ゆうようでした。

ところで、テキストの抽出ができない PDF は、『PDFを正規表現で検索する【Python】』の記事で紹介した『qpdf.exe』を使用すると、うまくいく場合がありました。

pdftotext.exe を取得 & 日本語設定

取得

『pdftotext.exe』は、Xpdf tools というコマンドラインツールに含まれていました。

Xpdf tools は、Windows 用の『Windows 32/64-bit』を使いました。

以下のページの『Download the Xpdf command line tools:』から取得します。

Xpdf tools ダウンロードページ
https://www.xpdfreader.com/download.html

自分が取得したときは、『xpdf-tools-win-4.02.zip』でした。

あわせて、日本語対応のための言語サポートパッケージも取得します

同じページにある『Download language support packages for Xpdf:』から取得します。

言語サポートパッケージは、『Japanese』を使いました。

自分が取得したときは、『xpdf-japanese.tar.gz』というファイルでした。

日本語設定

『Xpdf tools』と『言語サポートパッケージ』を、以下のようなフォルダ構成で解凍します。

インストーラーなどは無いので、好きなフォルダに配置してOKです。

バージョン番号などを削って短くしても大丈夫です。

Xpdf tools フォルダ(例)
F:\project\tools\xpdf-tools-win-4.02

言語サポートパッケージ フォルダ(例)
F:\project\tools\xpdf-tools-win-4.02\japanese

日本語設定の方法は、言語サポートパッケージ (xpdf-japanese.tar.gz) の中の『READMEリードミー』にっていました。

上記のフォルダ構成に合わせて要約ようやくすると、手順は以下の通りです。

(1. と 2. のリネームはしなくても動いたのですが、一応、READMEの内容に合わせてリネームします。重要なのは 3. の中身です。)

  1. 『xpdf-japanese』を『japanese』にリネーム。
  2. 『add-to-xpdfrc』を『F:\project\tools\xpdf-tools-win-4.02』にコピーして、『xpdfrc』にリネーム。
  3. 『xpdfrc』の中身を以下のように変更。

変更まえ

#----- begin Japanese support package (2011-sep-02)
cidToUnicode	Adobe-Japan1	/usr/local/share/xpdf/japanese/Adobe-Japan1.cidToUnicode
unicodeMap	ISO-2022-JP	/usr/local/share/xpdf/japanese/ISO-2022-JP.unicodeMap
unicodeMap	EUC-JP		/usr/local/share/xpdf/japanese/EUC-JP.unicodeMap
unicodeMap	Shift-JIS	/usr/local/share/xpdf/japanese/Shift-JIS.unicodeMap
cMapDir		Adobe-Japan1	/usr/local/share/xpdf/japanese/CMap
toUnicodeDir			/usr/local/share/xpdf/japanese/CMap
#fontFileCC	Adobe-Japan1	/usr/..../NotoSansCJKjp-Regular.otf
#----- end Japanese support package

変更

#----- begin Japanese support package (2011-sep-02)
cidToUnicode	Adobe-Japan1	"F:\project\tools\xpdf-tools-win-4.02\japanese\Adobe-Japan1.cidToUnicode"
unicodeMap	ISO-2022-JP	"F:\project\tools\xpdf-tools-win-4.02\japanese\ISO-2022-JP.unicodeMap"
unicodeMap	EUC-JP		"F:\project\tools\xpdf-tools-win-4.02\japanese\EUC-JP.unicodeMap"
unicodeMap	Shift-JIS	"F:\project\tools\xpdf-tools-win-4.02\japanese\Shift-JIS.unicodeMap"
cMapDir		Adobe-Japan1	"F:\project\tools\xpdf-tools-win-4.02\japanese\CMap"
toUnicodeDir			"F:\project\tools\xpdf-tools-win-4.02\japanese\CMap"
#fontFileCC	Adobe-Japan1	/usr/..../NotoSansCJKjp-Regular.otf
#----- end Japanese support package

シャープ『#』から始まる行は削っても大丈夫でした。

begin、fontFileCC、endの行がありますが、全て削除しても大丈夫です。

ファイルパスとフォルダパスは、すべて絶対ぜったいパスで指定します。

絶対ぜったいパスさえ合っていれば、途中のフォルダ名などは何でもOKでした。

そして、相対そうたいパスは使えないようです。色々試したのですが、うまく行かなかったです。

この『xpdfrc』へのファイルパスは、パイソンから呼び出すときのコマンドラインリストに追加します。

コード例

PDF からテキストを抽出する Python コード例です。

標準出力 (stdout) から、抽出結果を受け取っています。

"""
PDFからテキストを抽出するPythonコード例。
Python から Xpdf tools の pdftotext.exe を呼び出して抽出します。
"""

from pathlib import Path
from subprocess import run, PIPE

def main():
    """メイン関数"""

    # (1/7) PDF ファイルを決める
    pdf_file = Path(r'F:\project\sample.pdf')

    # (2/7) 実行ファイル pdftotext.exe のファイルパスを決める
    exe_file = Path(r'F:\project\tools\xpdf-tools-win-4.02\bin64\pdftotext.exe')

    # (3/7) 日本語サポートパッケージの xpdfrc のファイルパスを決める
    xpdfrc_file = Path(r'F:\project\tools\xpdf-tools-win-4.02\xpdfrc')

    # (4/7) コマンドラインの引数リストを作る(タプルでもOK)
    # 構文: pdftotext [options] [PDF-file [text-file]]
    # テキストを標準出力(stdout)に出すときは、
    # [text-file] にハイフン '-' を指定するとのこと。
    cmd = (
        exe_file,
        '-cfg', xpdfrc_file,
        '-enc', 'UTF-8', # テキストを出力する時のエンコーディング
        # '-q', # メッセージやエラーを表示しない
        '-nopgbrk', # '-nopgbrk': テキストに改ページを表す文字列を付けない
        pdf_file,
        '-', # テキストを標準出力(stdout)に出す
        )

    # (5/7) PDF からテキストを抽出する
    # cp は CompletedProcess の略です。
    cp = run(
        cmd,
        stdout=PIPE, # 標準出力からテキスト受け取るために PIPE を指定
        )

    # (6/7) もし pdftotext.exe がエラーを返したときは知らせる
    if cp.returncode == 0:
        # 正常に終了した。
        # ただし、壊れたPDFでも 0 が返る。その代わり、処理中に
        # Syntax Error (50): Illegal character <2f> in hex string
        # などのエラーメッセージが表示された。
        # エラーメッセージは '-q' のオプションで非表示にできた。
        print(f'ok - {cp.returncode} - {pdf_file.name}')
    else:
        # なんらかのエラー error を検出した。
        # (例) PDFが開けなかった、テキストの出力ファイルが開けなかった、
        # PDFのパーミッションに関するエラーでPDFが開けなかった、など。
        print(f'error - {cp.returncode} - {pdf_file.name}')

    # (7/7) 抽出したテキストデータを受け取る & デコードする
    text = cp.stdout.decode('utf-8')
    text = text.strip() # 先頭と末尾の空白や改行を除去する

    # (デバッグ情報)
    print(f'(デバッグ) exe_file: {exe_file}')
    print(f'(デバッグ) xpdfrc_file: {xpdfrc_file}')
    print(f'(デバッグ) pdf_file: {pdf_file}')
    print(f'(デバッグ) cp.returncode: {cp.returncode}')
    print(f"(デバッグ) cp.stdout.decode('utf-8'):『{text}』")

    # (終了)
    print('end')
    return

if __name__ == "__main__":
    main()

サンプル PDF

テキストの抽出に使用した PDF のスクリーンショットです (sample.pdf)。

実行結果

テキストの抽出結果です。

ok - 0 - sample.pdf
(デバッグ) exe_file: F:\project\tools\xpdf-tools-win-4.02\bin64\pdftotext.exe
(デバッグ) xpdfrc_file: F:\project\tools\xpdf-tools-win-4.02\xpdfrc
(デバッグ) pdf_file: F:\project\sample.pdf
(デバッグ) cp.returncode: 0
(デバッグ) cp.stdout.decode('utf-8'):『PDF からテキストを抽出する Python 
コード例 サンプル PDF (sample.pdf) あいうえお かきくけこ さしすせそ アイウエオ 
カキクケコ サシスセソ』
end

期待した通り、PDF ファイルから『テキストデータ』を取得することができました。

Python マニュアル

コード例で使用した機能のマニュアルです。

Python の subprocess.run() を使用して pdftotext.exe を呼び出しました。

サブプロセス ドット ラン
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)

PDF から抽出したテキストデータは、標準出力ひょうじゅんしゅつりょくから受け取ることができました。

pdftotext.exe の標準出力から、データを受け取る方法です。

stdout に subprocess.PIPE を指定したらできました。

サブプロセス ドット パイプ
subprocess.PIPE

subprocess.run() のもどの説明です。

サブプロセス ドット コンプリーテッド プロセス
class subprocess.CompletedProcess

テキストデータは、戻り値の .stdout に、バイナリデータとして入っていました。

.stdout.decode('utf-8') などと書くことで、普通の文字列に変換することができました。

デコードメソッド .decode()引数ひきすうには、pdftotext.exe の呼び出しオプションで指定したエンコーディングを使います。

pdftotext.exe のほうは、大文字と小文字を区別していました。

'UTF-8' なら 'UTF-8''Shift-JIS' なら 'Shift-JIS' しか受け付けませんでした。

大文字と小文字が間違っていた時は、以下のようなエラーが出ました。

Syntax Error: Couldn't find unicodeMap file for the 'SHIFT-JIS' encoding
Config Error: Couldn't get text encoding

pdftotext.exe マニュアル

pdftotext.exe のマニュアルの場所です。

XpdfReader – pdftotext(1)

PDF のテキストを標準出力に出す方法です。

マニュアルの DESCRIPTION のところに、やり方が載っていました。

If text-file is '-', the text is sent to stdout.

コード例で使用したオプションの説明です。

-cfg config-file
指定したコンフィグファイル (xpdfrc) を読み込む。

-enc encoding-name
テキストを出力するときのエンコーディング名。

Python とちがって、大文字と小文字が区別されます。

たとえば、'Shift-JIS''EUC-JP' などは、xpdfrc の中に書かれている通りに書くと動きました。

'shift-jis' などと書いたら、Syntax Error が表示されました。

-q
メッセージやエラーを表示しない。

-nopgbrk
ページとページの間に『改ページを表す文字列 (form feed characters)』を追加しない。

ほかにも色々なオプションがありました。

xpdfrc マニュアル

日本語サポートパッケージの『コンフィグファイル (xpdfrc)』のマニュアルの場所です。

XpdfReader – xpdfrc(5)

タイトルとURLをコピーしました