最新のPyPDF2のモジュールを利用してPDFからテキストデータを取り込み方についてまとめたいと思います。 まず、単一PDFファイルの内容をテキストファイルに書き出しについてまとめます。

次に、glob を使ったフォルダ配下の複数のPDFファイルのテキスト情報をひとつにまとめる方法を後半でご紹介します。 さらに、各々のテキスト化の最初にファイル名を挿入しています。テキスト化の参考になれば幸いです。


PyPDF2 をインストールする

PyPDF2を利用します。 通常のPIPコマンド pip install PyPDF2 でインストールできます。
今回は以下の環境で記事を書いています。

  • PyPDF2 3.0.1
  • python 3.9.13
  • Windows 10

サンプルコードでテキストデータを抽出するPDFは下図のとおりです。

2page_pdf_sample

サンプルPDFには以下のような特徴があります。

  1. 複数のページ(今回は2ページ)から構成されている
  2. 縦書きと横書きが混在する。
  3. 日本語(全角)と記号(半角)が混在する

Input 及び Output file

サンプルコードでは、PDF(サンプル文書.pdf )をプログラムと同じディレクトリ配下に配置しています。 PDFから抽出したtxtファイル(サンプル文書.txt)も同じフォルダ配下に書き出すこととします。


サンプルコード

以下がサンプルコードになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PyPDF2 import PdfReader

reader = PdfReader("サンプル文書.pdf")

all_text = []

number_of_pages = len(reader.pages)

for i in range(number_of_pages):
    page = reader.pages[i]
    output = page.extract_text()
    all_text.append(output)
    
s = ''.join(all_text)
with open("サンプル文書.txt", "w", encoding ="utf_8", errors="ignore") as f:
    f.write(s)

各ステップの説明

For ループで各ページ毎にテキストデータを抽出します。抽出した内容は、[‘page1’, ‘page2’, ,,,,’pageEnd’]という リスト形式で格納します。

  1. PyPDF2 からPdfReader をインポートします。 PyPDF2を予めPIPコマンドでインストールしておく必要があります。
  2. PdfReader を使ってターゲットの”サンプル文書.pdf”を読み込み、reader というオブジェクトに格納します。
  3. PDFの各ページのテキストデータをページ毎にall_text というリスト形式に格納するため、初期化します。
  4. ページ数を len(reader.page)で求め、その値(今回は2)を変数 number_of_pagesに格納します。
  5. 変数 iでページ数までのFor ループを宣言し、各ページについて以下の事を行います。
    1. reader.page[i] :最初のページから1ページずつpage というオブジェクトに格納します。
    2. page オブジェクトからテキストを抽出して、output という変数に格納します。
    3. output (pdf のテキスト)を all_textappend でリストの要素を追加します。
    4. [‘page1’, ‘page2’, ,,,,’pageEnd’] という感じで all_text が出来上がります。今回は2ページです。
  6. s = ''.join(all_text) でリスト形式で追加された all_text をひとつにまとめてその変数をsとします。
  7. with open で”サンプル文書.txt”というテキストファイルを定義して、オプション 'w' ファイルを上書き作成します。

抽出したテキストファイル

抽出したテキストファイルをWindowsのメモ帳で開け時の内容が以下のとおりです。

2page_pdf_sample

[ここがポイント!<その1>]

  1. ワードで作成された縦書きなどの文字には各文字に 改行キーを入れて実現しているため、テキストのみを抽出した場合、文字ごとに改行がついた状態になります。
  2. [‘page1’, ‘page2’, ,,,,’pageEnd’] というリスト形式でのテキスト化では、改行キー\nがテキストとして出現し、改行されません。
  3. コード例のようにs = ''.join(all_text)でひとつにまとめると改行キーで改行されて見やすくなります。
  4. いずれにしても、縦書きのテキストファイル化は避けたいところです。

Globを使ってディレクトリ配下の複数PDFを順次読み込み、テキスト化する

前半のCode ではファイル名を指定し、そのPDFファイルをテキスト化する内容でした。 しかし、複数のファイルを順次読み込み、都度テキスト化する方が 効率的です。また、ファイル名を指定しない分,手間も省けますす。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from PyPDF2 import PdfReader
import os, glob, sys
file_path = 'C:\\Users\\your_directory_to_text'
files = glob.glob(os.path.join(file_path,'*.pdf'))

for file in files:
    reader = PdfReader(file)
    count = len(reader.pages)
    all_text = []
    for i in range(count):
        page = reader.pages[i]
        all_text.append(page.extract_text())
        newoutput = ''.join(all_text)
    with open("example0221.txt", "a", encoding = "utf-8") as f:
        f.write( "\n" + "\n" +"***********  " + file + "  *************" + "\n" + "\n" + newoutput)
  1. PyPDF2 からPdfReader をインポートします。
  2. os, glob, sys をインポートします。これらは、標準ライブラリですので、pip でインストール不要です。
  3. file_path という変数名でテキスト化したいPdfが設置されているディレクトリを指定します。
  4. files という変数に拡張子が pdf のファイルのみ順次読み込みます。
  5. for file in filesfiles で読み込まれたそれぞれの pdf file であるfileに対してfor ループ処理をします。
  6. PdfReader を使ってターゲットの”サンプル文書.pdf”を読み込み、reader というオブジェクトに格納します(前半と同じですね)
  7. ページ数を len(reader.page)で求め、その値(今回は2)を変数 countに格納します (前半のコードと変数名変えています!)
  8. PDFの各ページのテキストデータをページ毎にall_text というリスト形式に格納するため、まず初期化します。
  9. 変数 iでページ数までのFor ループを宣言し、各ページについて以下の事を行います。
    1. reader.page[i] :最初のページから1ページずつpage というオブジェクトに格納します。
    2. page オブジェクトからテキストを抽出して、output という変数に格納します。
    3. output (pdf のテキスト)を all_textappend でリストの要素を追加します。
    4. [‘page1’, ‘page2’, ,,,,’pageEnd’] という感じで all_text 出来上がります。今回はいずれも2ページです。
  10. newoutput = ''.join(all_text) でリスト形式で追加された all_text をひとつにまとめてその変数をnewoutputとします。
  11. with open で”サンプル文書.txt”というテキストファイルを定義して、オプション"a" でファイルに追加し行きます。
  12. ファイルに書き込むにあたり、改行と**** を前後に付けてファイル名を代入しています。これでどのファイルをテキスト化したかが容易に判別できます。

テキスト抽出結果を確認する

テキスト抽出結果は、example0221.txtというファイル名で格納されますので、メモ帳で開きます。

2page_pdf_sample

[ここがポイント!<その2>]

  1. For ループを二つ入れ子(いわゆる多重ループ)で回しています。Glob でファイルの順次読み込みをしたら、そのファイルに対して各ページも順に読み込みテキスト化します
  2. 多重ループなのか、単純にFor ループは二つそれぞれあるかを区別させるため、Python ではインデントで識別しています
  3. 今回は多重ループなので、インデントが二つ奥に入り込んでいます
  4. 一方、ファイルの書き込みはfor file in files 単位で行うので、最初のインデントで実行しています。
  5. 書き込みオプション 'a' で追記するようにして、ファイル書き込みで複数のファイルの書き込みを実現しています。

参照ページ一覧

このブログを作成するにあたり、以下のページを参考にしています。併せてご覧ください。

1) PyPDF2
2) KH Coder で複合語をコントロールしてWordCloudを作成する
3) globによるファイルの順次読み込みと特定文字列のカウント