結論
PythonでPDFから文字を取り出せても、必要な順序で出ているとは限りません。 同じ見た目の自作PDFを比べると、文字数が同じ38文字でも、通常の抽出では並び順が違いました。
PDFテキスト抽出元ページと抽出された文字を比べる登録なしで使えます開く
自動集計へつなぐ前に、文字数だけでなく項目名と数字の対応を確認することが要点です。今回の例はPython 3.12.10・pypdf 6.16.1の既存環境で測っています。VBAやOCRの結果ではありません。
ページ単位で通常抽出と配置を比べる
最初の検算では、ページごとの出力を分けると元の資料へ戻りやすくなります。 pypdfのPdfReaderはpagesの説明で、次の操作に触れています。
下はpypdfが利用できる環境で、手元のsample.pdfを読み、通常抽出とlayoutの結果を表示する例です。原本PDFや出力ファイルを書き換えず、文字列の確認だけを行います。 検証用の自作PDFで、このコードも実行しています。
```python from pypdf import PdfReader
reader = PdfReader("sample.pdf") try: for page_no, page in enumerate(reader.pages, start=1): plain = page.extract_text() or "" layout = page.extract_text( extraction_mode="layout", layout_mode_space_vertically=False, ) or "" print(page_no, len(plain), len(layout)) print(repr(plain)) print(repr(layout)) finally: reader.close() ```
reprは改行や空白の存在を確認するための表示です。lenの値には改行・空白も含みます。 この短い例は、破損ファイルや暗号化ファイルの処理を組み込んだ一括運用プログラムではありません。
公式のlayoutの例は、出力を一次資料の節に引用したとおり表現しています。
layoutは配置を意識した固定幅の文字列であり、取引先と金額の対応を理解した表データではありません。 以下の自作例でも、この違いを分けています。
見た目が同じ3ファイルを抽出した
2026-10-01、左右に取引先名と金額を置いたn=3ファイルを測りました。 左列はCLIENT AとTOTAL 100、右列はCLIENT BとTOTAL 200です。英数字4片の文字を列順に保存したもの、行順に保存したもの、その見た目を画像だけにしたものを用意しました。
同じ条件で3ファイルを描画すると、全画素が一致しました。 そのうえで通常抽出とlayoutを実行しています。
| 自作PDFの内部 | 通常抽出の並び | 通常の文字数 | layoutの文字数 |
|---|---|---|---|
| 列順に文字を配置 | A → 100 → B → 200 | 38 | 94 |
| 行順に文字を配置 | A → B → 100 → 200 | 38 | 94 |
| 同じ見た目の画像だけ | 文字列は空 | 0 | 0 |
表の並びは、名前と金額の部分だけを短く表したものです。通常抽出の実際の出力にはCLIENTやTOTAL、改行も含まれます。
文字版2つの通常抽出は、同じ文字数でも内容の順序が一致しませんでした。 4つの文字片が過不足なく含まれることも別に照合したため、文字が欠けたことによる差ではありません。
一方、layoutでは文字版2つとも、上段にCLIENT AとCLIENT B、下段にTOTAL 100とTOTAL 200が空白で離れて並び、結果が一致しました。94文字へ増えた理由は配置を示す空白などであり、情報が増えたという意味ではありません。
空の結果と、文字の対応が正しい結果は別
画像だけの入力から0文字だったことは、PDFが壊れているという意味ではありません。 同じページを描画できても、文字データがない場合があります。pypdfの資料にも次の説明があります。
今回の画像版にはOCRの文字層を付けていません。layoutへ切り替えても画像の中の文字は増えず、どちらも空でした。
反対に、文字が出た場合も順序と意味を分ける必要があります。今回のlayoutのように上段の名前が横に並ぶ出力では、空白をすべて削除すると列の関係を失うことがあります。取引先名の次の行を無条件に金額として扱う、といった処理はこの比較では検証していません。
元ページと結果を対応付けたまま、必要な項目名や数字を照合する余地を残せます。38文字という合計だけでは、表のどちらの相手に100が属するかは判定できません。
一次資料
本文で参照した一次資料の引用と出典をまとめます。
“get a page or a range of pages”
— pypdf 6.16.1「The PdfReader Class」、pages https://pypdf.readthedocs.io/en/6.16.1/modules/PdfReader.html(2026-10-01 到達)
“a fixed width format”
— pypdf 6.16.1「Extract Text from a PDF」、layoutのコード例 https://pypdf.readthedocs.io/en/6.16.1/user/extract-text.html(2026-10-01 到達)
“pypdf is not OCR software.”
— pypdf 6.16.1「Extract Text from a PDF」、OCR vs. Text Extraction https://pypdf.readthedocs.io/en/6.16.1/user/extract-text.html(2026-10-01 到達)
測っていないこと・ここから先は推論
日本語・縦書き・複雑な表・OCR済みの文字層・大量一括処理は測っていません。 検証は自作の英数字2列、各1ページの3ファイルです。暗号化・破損・複雑なフォントや、別バージョンのpypdfも対象外です。抽出精度の一般的な成功率や、他ライブラリーの優劣を示したものではありません。
次の1手
自動化したい帳票の少数の見本で、必要な名前・数字・ページを先に照合すると、文字数だけでは見落とす違いを確認できます。単発で文字だけを取り出す場合も、元ページと並べて読む点は共通します。