PythonとPyMuPDFでPDFを「爆速」処理:シンプルなスクリプトからプロダクション環境まで

Python tutorial - IT technology blog
Python tutorial - IT technology blog

CodeによるPDF処理:なぜPyMuPDFなのか?

CodeでPDFを処理するのは、ツール選びを間違えると悪夢になりがちです。以前、私はPyPDF2やPDFMinerで苦労したことがあります。その結果は?プロジェクトで1日5,000枚の請求書を処理する必要が生じた際、システムはメモリを大量に消費し、頻繁にクラッシュしてしまいました。

倉庫管理システムの運用を6ヶ月経験した後、確信を持って言えるのは、PyMuPDF (fitz ライブラリ) が現在「最強」の選択肢であるということです。MuPDFのCエンジンをベースに構築されているため、純粋なPythonライブラリよりも5〜10倍高速です。読み取り、編集、ページの削除からグラフィックスの描画まで、すべてをこなせます。

私のスクリプトも最初はわずか200行でしたが、今では様々な特殊ケースに対応するために2,000行を超えています。ここでは、私が凝縮した最も実践的な経験を共有します。

インストールと内容の読み取り:5分で完了

pip経由で非常に簡単にインストールできます。一つ奇妙な点があります。パッケージ名は pymupdf ですが、コード内では import fitz と記述する必要があります。これはこのライブラリの歴史的な経緯によるものなので、深く考えずにそのまま使いましょう。

pip install pymupdf

最も基本的な内容を読み取るコードを試してみましょう:

import fitz  # PyMuPDFをインポート

# 1行のコマンドでファイルを開く
doc = fitz.open("document.pdf")

# 最初のページにアクセス(インデックスは0から開始)
page = doc[0]
text = page.get_text()

print(f"1ページ目の内容:\n{text}")
doc.close()

スムーズに動きますね。しかし、実際のプロジェクトはこれほど単純ではありません。

実践テクニック:PDFの抽出と結合

1. 構造化テキストの抽出 (Blocks)

通常の get_text() を使用すると、PDFの構造が複雑なために文字の順序がバラバラになることがあります。私の解決策は "blocks" パラメータを使用することです。これにより、テキストブロックごとにデータを取得でき、上から下への読み取りロジックを維持できます。

doc = fitz.open("report.pdf")
for page in doc:
    # 座標と内容を含むタプルのリストを返す
    blocks = page.get_text("blocks")
    for b in blocks:
        print(f"位置: {b[:4]} | 内容: {b[4]}")

2. 複数のPDFファイルの結合 (Merge)

月末の請求書をまとめるツールを作っていた際、insert_pdf 機能が非常に気に入りました。フォーマットや添付リンクを失うことなく、ファイルAから特定のページを正確に取り出してファイルBに入れることができます。

def merge_pdfs(file_list, output_name):
    result = fitz.open()
    for file in file_list:
        with fitz.open(file) as m_file:
            result.insert_pdf(m_file)
    result.save(output_name)
    result.close()

merge_pdfs(["part1.pdf", "part2.pdf"], "final_report.pdf")

プロフェッショナルなウォーターマーク追加とセキュリティ

「全ページに薄く『CONFIDENTIAL』という文字を入れておいて」。上司からそう頼まれても心配いりません。PyMuPDFを使えば、手作業で何時間もかける代わりに、わずか数行のコードで完了します。

def add_watermark(input_pdf, output_pdf, text):
    doc = fitz.open(input_pdf)
    for page in doc:
        # 座標 (100, 100) に45度傾いた文字を挿入
        page.insert_text((100, 100), text, 
                         fontsize=60, 
                         rotate=45, 
                         color=(0.8, 0.8, 0.8), 
                         fill_opacity=0.3)
    doc.save(output_pdf)
    doc.close()

会社のロゴを挿入したいですか? insert_textinsert_image に変更し、希望の座標範囲 (Rect) を指定するだけです。

プロダクション環境で学んだ教訓

エラーのあるPDFファイルで何度も苦労した末に、覚えておくべき注意点は以下の通りです:

  • メモリの解放: doc.close() を決して忘れないでください。数千の大きなファイルを処理する場合、ファイルを閉じないと数分でサーバーのメモリが枯渇します。with fitz.open(...) as doc: を使うのがベストです。
  • 出力ファイルの圧縮: 編集後のPDFファイルはサイズが大きくなりがちです。doc.save(filename, garbage=4, deflate=True) を使用して不要なデータを取り除き、圧縮しましょう。ファイルサイズを30〜50%削減できる場合があります。
  • フォントエラーの処理: 抽出結果が文字化け(豆腐文字)する場合、フォントが正しく埋め込まれていないことが原因です。この場合、純粋なテキスト読み取りの代わりに、OCR(Tesseractなど)を組み合わせて画像をスキャンする必要があります。
  • 座標系: 座標 (0,0) は常にページの左上隅にあることを忘れないでください。右下隅に何かを挿入したい場合は、ページの幅と高さから余白を引く必要があります。

要するに、PyMuPDFは高速で強力、かつ非常に安定した真の「モンスター」です。ドキュメント自動化システムを構築しているなら、今日から使い始めましょう。あなたのプロジェクトの成功を祈っています!

Share: