PythonでPDFをWord文書に変換する実践ガイド

PDFからWordへの変換は、業務効率化のための代表的な自動化タスクです。しかし、PDFの種類によって最適なアプローチが異なります。本稿では、「テキスト埋込型PDF」と「スキャン画像型PDF」の2種類に対応したPython実装を、技術的背景と実装の意図を含めて解説します。

PDFの二つの性質

PDFは見た目が同じでも内部構造が大きく異なります。

  • テキスト埋込型PDF:Wordやブラウザから直接出力されたもので、文字情報がベクタ形式で保持されています。OCR不要でテキスト抽出が可能です。
  • スキャン画像型PDF:スキャナやスマートフォン撮影で生成されたもので、実際にはページごとのラスタ画像(JPEG/PNG相当)です。文字認識(OCR)が必要です。

テキスト埋込型PDF → Word変換

このケースでは、pdf2docxライブラリを活用します。PDF内のレイアウト情報を可能な限り維持しつつ、段落・表・フォントスタイルを再現します。

from pdf2docx import Converter
import os

def convert_text_pdf_to_docx(
    input_path: str,
    output_path: str,
    start_page_index: int = 0,
    end_page_index: int = None
) -> bool:
    """
    テキストベースのPDFを.docx形式に変換
    
    Args:
        input_path: 入力PDFファイルパス
        output_path: 出力Wordファイルパス
        start_page_index: 変換開始ページインデックス(0始まり)
        end_page_index: 変換終了ページインデックス(含む、Noneで全ページ)
    
    Returns:
        成功時はTrue、失敗時はFalse
    """
    if not os.path.exists(input_path):
        print(f"エラー: 入力ファイルが見つかりません → {input_path}")
        return False

    try:
        converter = Converter(input_path)
        
        # インデックス補正(pdf2docxは0始まり)
        actual_start = max(0, start_page_index)
        actual_end = end_page_index + 1 if end_page_index is not None else None

        converter.convert(output_path, start=actual_start, end=actual_end)
        converter.close()
        print(f"✅ 変換完了: {output_path}")
        return True
    except Exception as error:
        print(f"❌ 変換失敗: {error}")
        return False

スキャン画像型PDF → Word変換(OCR統合)

ここでは、PDFを高解像度画像に分解し、tesserocrによるOCR処理を経て、結果をWordドキュメントに整形します。信頼度フィルタリングと段落単位の構造化を実装しています。

from pathlib import Path
import fitz  # PyMuPDF
from PIL import Image
from docx import Document
from tesserocr import PyTessBaseAPI, PSM, OEM
import numpy as np

def ocr_scan_pdf_to_docx(
    pdf_path: str,
    docx_path: str,
    confidence_threshold: float = 65.0,
    dpi: int = 300,
    lang_code: str = "chi_sim+eng",
    tessdata_dir: str = "./tessdata"
) -> bool:
    """
    スキャンPDFをOCRでテキスト化し、Word文書へ出力
    
    Args:
        pdf_path: 入力PDFパス
        docx_path: 出力DOCXパス
        confidence_threshold: OCR信頼度下限(0–100)
        dpi: OCR用画像解像度
        lang_code: 言語コード(例: "chi_sim+eng")
        tessdata_dir: .traineddataファイル格納ディレクトリ
    
    Returns:
        成功時True
    """
    if not Path(pdf_path).is_file():
        print("❌ PDFファイルが存在しません")
        return False

    doc = Document()
    pdf_doc = fitz.open(pdf_path)

    # 各ページを高品質画像に変換
    image_list = []
    zoom = dpi / 72.0
    mat = fitz.Matrix(zoom, zoom)
    
    for page_num in range(len(pdf_doc)):
        page = pdf_doc[page_num]
        pix = page.get_pixmap(matrix=mat, alpha=False)
        img = Image.frombytes("RGB", (pix.width, pix.height), pix.samples)
        image_list.append(img)

    # OCR実行(LSTMエンジン+自動レイアウト検出)
    with PyTessBaseAPI(
        path=tessdata_dir,
        lang=lang_code,
        psm=PSM.AUTO,
        oem=OEM.LSTM_ONLY
    ) as api:
        for idx, img in enumerate(image_list):
            api.SetImage(img)
            text = api.GetUTF8Text()
            
            # 信頼度に基づくフィルタリング(簡易版)
            confidences = api.AllWordConfidences()
            words = text.split()
            filtered_words = [
                w for w, c in zip(words, confidences)
                if c >= confidence_threshold
            ]
            
            paragraph_text = " ".join(filtered_words).strip()
            if paragraph_text:
                doc.add_paragraph(paragraph_text)

    try:
        doc.save(docx_path)
        print(f"✅ OCR変換完了: {docx_path}")
        return True
    except Exception as e:
        print(f"❌ DOCX保存失敗: {e}")
        return False

環境構築の要点

tesserocrを利用する際の注意点:

  • tesseractバイナリ不要:conda/pip経由でtesserocrをインストールすれば、組み込みのOCRエンジンが利用可能(Windows/macOS/Linux共通)。
  • tessdataの配置:必要な言語モデル(例:chi_sim.traineddata, eng.traineddata)を任意ディレクトリに配置し、path引数で明示的に指定します。
  • 推奨インストール方法conda install -c conda-forge tesserocr(安定性・互換性が最も高い)。

OCRパラメータの選択指針

パラメータ 推奨値 用途
PSM PSM.AUTO(=3) 汎用的レイアウト検出(多言語・複雑配置対応)
OEM OEM.LSTM_ONLY(=1) 手書き風・低解像度・複雑フォントにも強い
lang "chi_sim+eng" 中英混在文書向け(必要に応じて追加)

タグ: Python pdf2docx tesserocr OCR fitz

7月10日 19:47 投稿