はじめに:PDF パースのつらい現実

開発者なら、PDF 文書を扱う場面は必ず訪れます。請求書の解析、契約書の抽出、論文のクロール、データアーカイブ——ほぼすべてのバックエンドプロジェクトでぶつかる壁です。でも、PDF パースは長い間こんな悩みを抱えてきました:

  • OCR サービスは高い:クラウド OCR API を呼ぶたびに1ページ数十円。量が増えるとコストが跳ね上がる
  • オープンソースは遅い:PyMuPDF4LLM で200文書処理すると17秒、MarkItDown で16秒かかる
  • フォーマットが崩れる:従来の抽出ツールはプレーンテキストしか吐き出さない。見出しの階層、表構造、コードブロックが全部消える
  • インテリジェントなルーティングがない:スキャン済みPDFとネイティブテキストPDFを自動判別できず、OCR不要な文書にもOCRをかけてしまう

2026年7月、Webスクレイピングプラットフォームとして知られる Firecrawl が、Rust製のPDFパースライブラリ pdf-inspector をオープンソース化。リリースからわずか数週間で 7,900超えのStar を獲得し、GitHub Trending 日間ランキングでトップ3入りを果たしました。このライブラリは 200ms以内でローカルのPDF分類とテキスト抽出を完了 し、自動でフォーマット付きMarkdownを出力——OCRも外部サービスも不要です。

今日はこのプロジェクトを深く掘り下げて、なぜ主流ツールを性能で凌駕できるのかを見ていきましょう。

pdf-inspector とは?

pdf-inspector は Firecrawl チームが Rust で開発した PDF 分類・テキスト抽出ライブラリです。コア機能は以下の通り:

  1. スマート分類 — 10〜50msでPDFの種類を判定:ネイティブテキスト(TextBased)、スキャン済み(Scanned)、画像中心(ImageBased)、混合型(Mixed)。信頼度とページ単位のOCRルーティング提案を返す
  2. テキスト抽出 — 位置情報付きのテキスト抽出。フォント情報、X/Y座標、自動マルチカラムの読書順序を保持
  3. Markdown変換 — H1〜H4の見出し、リスト、コードブロック(等幅フォント検出)、表、太字・斜体、URLリンク、ページ区切りを自動認識
  4. 表検出 — デュアルモードの表検出(PDF描画オペレーションに基づく矩形検出 + テキストアライメントに基づくヒューリスティック検出)。財務レポートやページ跨ぎの表も完璧に処理
  5. CIDフォントサポート — ToUnicode CMap デコード。Type0/Identity-H フォント、UTF-16BE、UTF-8、Latin-1 エンコーディングに対応
  6. マルチ言語バインディング — Python、Node.js、ブラウザ WebAssembly バインディングを提供

なぜ Rust なのか? Rustのゼロコスト抽象化とメモリ安全性により、pdf-inspector は ML モデルや外部サービスに依存せず、極限の解析速度を実現しています。外部依存は lopdf(Rust PDF パースライブラリ)のみです。

性能比較

公式の Apple M4 Pro におけるベンチマーク結果(200文書、opendataloader-bench コーパス):

エンジン 総合スコア 読書順序 表認識 見出し認識 200文書の処理時間
pdf-inspector 0.875 0.915 0.814 0.788 0.470秒
LiteParse 0.873 0.913 0.693 0.811 0.750秒
OpenDataLoader 0.831 0.902 0.489 0.739 2.569秒
PyMuPDF4LLM 0.735 0.886 0.401 0.424 17.169秒
MarkItDown 0.589 0.844 0.273 0.000 16.117秒

pdf-inspector は総合スコア、読書順序、表認識、速度のすべてで全面リード。処理時間は PyMuPDF4LLM の 約1/36、MarkItDown の 約1/34 です。

インストール

pdf-inspector は Rust、Python、Node.js、ブラウザ環境をカバーする複数のインストール方法に対応しています。

Rust(ネイティブ)

Cargo.toml に依存を追加:

TOML
[dependencies]
pdf-inspector = "0.2"

または cargo コマンドでインストール:

BASH
cargo add pdf-inspector

Python

pdf-inspector は maturin を通じて Python バインディングを提供しています:

BASH
pip install maturin
git clone https://github.com/firecrawl/pdf-inspector.git
cd pdf-inspector
maturin develop --release

💡 ヒント: 現時点では PDF-inspector はまだ PyPI に公開されていません。ソースからコンパイルしてインストールする必要があります。Firecrawl チームは安定版になったら PyPI パッケージを公開する予定です。

Node.js

BASH
npm install @firecrawl/pdf-inspector

ブラウザ WebAssembly

BASH
npm install @firecrawl/pdf-inspector-wasm

Wasm 版は完全な Rust パーサーをブラウザに組み込み、Web Worker で動作します。サーバーとの往復は不要です。

クイックスタート

Python での使用例

インストールが完了したら、使い方はとても簡単——関数を1つ呼ぶだけ:

PYTHON
import pdf_inspector

# 単一PDFファイルを処理
result = pdf_inspector.process_pdf("document.pdf")

# PDFタイプの分類を確認
print(f"PDF タイプ: {result.pdf_type}")
# 出力: "text_based", "scanned", "image_based", または "mixed"

# Markdown 出力を取得
if result.markdown:
    print(result.markdown)

これだけです。1行のコードで、分類 + 抽出 + Markdown 変換が完了します。

Node.js での使用例

JAVASCRIPT
const { processPdf } = require('@firecrawl/pdf-inspector');
const fs = require('fs');

async function analyzePdf(filePath) {
  const pdfBuffer = fs.readFileSync(filePath);
  const result = await processPdf(pdfBuffer);

  console.log('PDF タイプ:', result.pdfType);
  console.log('信頼度:', result.confidence);
  console.log('--- Markdown 出力 ---');
  console.log(result.markdown);
}

analyzePdf('report.pdf');

Rust ネイティブでの使用例

RUST
use pdf_inspector::{PdfInspector, ProcessPdfResult};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let inspector = PdfInspector::new();
    let result: ProcessPdfResult = inspector.process_pdf_path("document.pdf")?;

    println!("PDF タイプ: {:?}", result.pdf_type);
    println!("信頼度: {:.2}", result.confidence);

    if let Some(markdown) = result.markdown {
        println!("Markdown:\n{}", markdown);
    }

    Ok(())
}

コア機能详解

1. スマート分類:不要な OCR オーバーヘッドを回避

pdf-inspector の最も実用的な機能の1つが自動分類です。PDF コンテンツストリームをサンプリングすることで、10〜50ms でドキュメントのタイプを判定します:

タイプ 説明 推奨処理戦略
text_based ネイティブテキストPDF。抽出可能なテキストコンテンツストリームを含む pdf-inspector でそのまま抽出。OCR はスキップ
scanned スキャン済みPDF(画像ページ) OCR サービスが必要
image_based 画像中心のPDF(スクリーンショット集など) OCR または画像処理が必要
mixed 混合型(一部ページにテキスト、一部はスキャン済み) ページ単位で決定:テキストページは直接抽出、スキャンページはOCR呼び出し

実践シナリオ:スマート PDF 処理パイプラインの構築

PYTHON
import pdf_inspector
# 独自の OCR 関数がある前提
def smart_pdf_pipeline(pdf_path, ocr_function):
    result = pdf_inspector.process_pdf(pdf_path)

    if result.pdf_type == "text_based":
        # ネイティブテキスト、直接抽出——高速、無料、正確
        print("✅ ネイティブテキストPDF、直接抽出")
        return result.markdown

    elif result.pdf_type == "scanned":
        # スキャン済み、OCR を呼び出し
        print("🔍 スキャン済みPDF、OCR を呼び出し")
        return ocr_function(pdf_path)

    elif result.pdf_type == "mixed":
        # 混合型——ページ単位で処理
        print("📄 混合型PDF、ページ単位でルーティング")
        pages = []
        for page_info in result.page_results:
            if page_info.needs_ocr:
                pages.append(ocr_function_for_page(pdf_path, page_info.page_number))
            else:
                pages.append(page_info.markdown)
        return "\n\n".join(pages)

    else:
        # 純画像型、テキスト抽出不可
        print("❌ 画像型PDF、テキスト抽出不可")
        return None

このパイプラインを使うと、約 54% のPDF(ネイティブテキスト型)で OCR を完全にスキップ でき、処理コストと遅延を大幅に削減できます。

2. Markdown 変換:ドキュメント構造を保持

pdf-inspector の Markdown 出力は単なるプレーンテキストではありません。ドキュメントの構造情報をインテリジェントに認識して保持します:

  • 見出し階層(H1〜H4):フォントサイズの比率から自動推定
  • リスト:箇条書きリスト、番号付きリスト、アルファベット番号リストを自動認識
  • コードブロック:等幅フォント検出で自動的にコードブロックとしてマーク
  • 表:矩形検出とヒューリスティック検出をサポート。財務レポートやページ跨ぎの表も処理
  • 太字・斜体:ボールドとイタリックのフォーマットを保持
  • URLリンク:自動認識して Markdown リンク形式に変換
  • ページ区切り:--- で異なるページを区切る

実際の効果を見てみましょう。学術論文の PDF があるとします:

MARKDOWN
# Deep Learning Approaches for Natural Language Processing

## 1. Introduction

Natural language processing (NLP) has seen remarkable progress in recent years...

### 1.1 Background

The transformer architecture, introduced by Vaswani et al., has become...

## 2. Methodology

| Model | BLEU Score | Training Time |
|-------|-----------|---------------|
| Transformer | 38.2 | 12 hours |
| BERT | 41.0 | 24 hours |
| GPT-4 | 45.7 | 72 hours |

## 3. Results

The experimental results demonstrate...

> **Note:** All experiments were conducted on...

見出し階層、表、引用ブロックがすべて完全に保持されています。これは、従来の PDF 抽出ツールがプレーンテキストしか出力できないのと比べて大幅に優れています。

3. マルチカラムと読書順序の検出

多くの PDF(論文、新聞、雑誌など)はマルチカラムレイアウトを採用しています。pdf-inspector はカラム構造を自動検出し、正しい読書順序で抽出します:

PYTHON
result = pdf_inspector.process_pdf("newspaper.pdf")

# pdf-inspector が 2カラム/3カラムレイアウトを自動検出
# 上から下、左から右の正しい順序で出力
print(result.markdown)

同時に RTL(右から左)テキスト にも対応。アラビア語やヘブライ語の文書も処理できます。

4. CIDフォントとエンコーディング問題の検出

中国語、日本語、韓国語の PDF を扱う際、フォントエンコーディングの問題は頻繁に発生します。pdf-inspector は ToUnicode CMap デコード をサポートし、以下を正しく処理できます:

  • Type0 / Identity-H フォント
  • UTF-16BE、UTF-8、Latin-1 エンコーディング
  • 壊れたフォントエンコーディングの自動マーキング

つまり、CJK 言語の PDF を処理する際、どのページに文字化けのリスクがあるかを教えてくれるので、OCR へのフォールバックを事前に判断できます。

実践:PDF 処理サービスの構築

pdf-inspector のスマート分類機能を統合した、完全な PDF 処理マイクロサービスを構築してみましょう。

シナリオ:ドキュメントアーカイブシステム

企業内のドキュメントアーカイブシステムを構築しているとします。毎日数百の PDF(契約書、請求書、レポートなど)を処理する必要があります:

PYTHON
# pdf_service.py
import os
import json
from datetime import datetime
import pdf_inspector

class PdfProcessingService:
    def __init__(self, output_dir="./processed"):
        self.output_dir = output_dir
        os.makedirs(output_dir, exist_ok=True)

    def process_batch(self, pdf_files):
        """PDF ファイルを一括処理"""
        results = []
        for pdf_path in pdf_files:
            result = self.process_single(pdf_path)
            results.append(result)
        return results

    def process_single(self, pdf_path):
        """単一 PDF ファイルを処理"""
        filename = os.path.basename(pdf_path)
        pdf_result = pdf_inspector.process_pdf(pdf_path)

        # メタ情報を抽出
        metadata = {
            "filename": filename,
            "pdf_type": pdf_result.pdf_type,
            "confidence": pdf_result.confidence,
            "processed_at": datetime.now().isoformat(),
            "pages_count": len(pdf_result.page_results) if hasattr(pdf_result, 'page_results') else 0,
            "needs_ocr": pdf_result.pdf_type in ("scanned", "image_based"),
        }

        # Markdown 出力を保存
        if pdf_result.markdown:
            md_filename = filename.replace(".pdf", ".md")
            md_path = os.path.join(self.output_dir, md_filename)
            with open(md_path, "w", encoding="utf-8") as f:
                f.write(pdf_result.markdown)
            metadata["markdown_path"] = md_path

        # メタ情報を保存
        meta_path = os.path.join(
            self.output_dir,
            filename.replace(".pdf", ".meta.json")
        )
        with open(meta_path, "w", encoding="utf-8") as f:
            json.dump(metadata, f, ensure_ascii=False, indent=2)

        return metadata

# 使用例
service = PdfProcessingService(output_dir="./output")

# 一括処理
pdf_files = [
    "contracts/contract_2026_001.pdf",
    "invoices/invoice_aug_2026.pdf",
    "reports/q2_financial_report.pdf",
]

results = service.process_batch(pdf_files)
for r in results:
    status = "OCR 必要" if r["needs_ocr"] else "直接抽出済み"
    print(f"{r['filename']}: {r['pdf_type']} ({status})")

シナリオ:LLM ドキュメント分析パイプラインとの統合

pdf-inspector が出力する高品質な Markdown は、LLM による分析に直接渡すことができます:

PYTHON
import pdf_inspector
# OpenAI 互換 API を使用すると仮定
from openai import OpenAI

def analyze_pdf_with_llm(pdf_path, prompt="このドキュメントの主要内容をまとめて"):
    """LLM で PDF コンテンツを分析"""
    # 1. pdf-inspector で Markdown を抽出
    result = pdf_inspector.process_pdf(pdf_path)

    if not result.markdown:
        return "テキストコンテンツを抽出できませんでした。OCR が必要な可能性があります"

    # 2. ドキュメントが長い場合、最初の 8000 文字に切り取り
    markdown_content = result.markdown[:8000]

    # 3. LLM を呼び出して分析
    client = OpenAI(api_key="YOUR_API_KEY")
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": "あなたはドキュメント分析アシスタントです。"},
            {"role": "user", "content": f"以下のドキュメントコンテンツに基づいて{prompt}:\n\n{markdown_content}"}
        ]
    )

    return response.choices[0].message.content

# 使用例
summary = analyze_pdf_with_llm("annual_report.pdf", "主要な財務指標を抽出して")
print(summary)

このパイプラインは RAG(検索拡張生成)システムで特に有用です。まず pdf-inspector で構造化テキストを高速に抽出し、ベクトル化してナレッジベースに保存します。

他のツールとの比較

pdf-inspector vs PyMuPDF4LLM

項目 pdf-inspector PyMuPDF4LLM
言語 Rust Python(C バインディング)
総合スコア 0.875 0.735
表認識 0.814 0.401
速度(200文書) 0.47秒 17.169秒
Markdown 構造 ✅ 完全保持 ⚠️ 一部欠落
スマート分類 ✅ 組み込み ❌ なし
ブラウザ Wasm ✅ サポート ❌ 非サポート

pdf-inspector vs MarkItDown(Microsoft)

項目 pdf-inspector MarkItDown
総合スコア 0.875 0.589
見出し認識 0.788 0.000
速度(200文書) 0.47秒 16.117秒
マルチ言語バインディング Python/Node/Wasm Python
フォーカス PDF パースに特化 汎用ドキュメント変換

いつ pdf-inspector を使い、いつ OCR を使うべきか?

  • pdf-inspector を使う:ネイティブテキストPDF、レポート、論文、契約書、請求書など、テキストコンテンツストリームを含むドキュメント
  • OCR を使う:スキャン済みPDF、純画像PDF、手書き文書
  • 併用する:まず pdf-inspector で分類。text_based は直接抽出、scanned/image_based は OCR にルーティング——これこそが pdf-inspector が設計したルーティング戦略です

プロジェクト情報とコミュニティ

  • GitHub:firecrawl/pdf-inspector
  • Stars:7,900超え(2026年7月リリース、勢いのある伸び)
  • License:Apache-2.0(ビジネスフレンドリー)
  • 言語:Rust
  • エコシステム:Firecrawl 製(Webスクレイピングプラットフォームとして知られ、firecrawl クローラーエンジンもオープンソース化)

インストールチャネル

プラットフォーム インストール方法
Rust crates.io/crates/pdf-inspector
Python ソースコンパイル(maturin develop --release)
Node.js npm install @firecrawl/pdf-inspector
ブラウザ npm install @firecrawl/pdf-inspector-wasm

まとめ

pdf-inspector の登場は重要な空白を埋めるものです——軽量、高速、ローカライズされた PDF パースソリューション。ML モデルも外部サービスも不要。純粋な Rust 実装で、高精度を保ちながら同类ツールを遥かに超える速度を実現しています。

コア优势のまとめ:

  1. 🚀 圧倒的な速度——200ms レベルの解析。PyMuPDF4LLM の 36 倍高速
  2. 🧠 スマート分類——テキスト/スキャン/画像型 PDF を自動判別。OCR ルーティングを最適化
  3. 📐 構造保持——見出し、表、コードブロック、リストを完全に Markdown として保持
  4. 🔒 純ローカル——外部依存なし、API 呼び出しなし。データはマシン外に出ない
  5. 🌐 マルチプラットフォーム——Rust/Python/Node.js/ブラウザ Wasm をフルカバー

ドキュメント処理パイプライン、RAG システム、PDF パースが必要なアプリケーションを構築しているなら、pdf-inspector はあなたの技術スタックに追加する価値があります。特にネイティブテキストPDF が中心のシナリオでは、OCR のコストと遅延を大幅に削減できます。

🔗 関連リンク - GitHub: firecrawl/pdf-inspector - Python ドキュメント: docs/python.md - ベンチマーク: opendataloader-bench - Firecrawl: firecrawl.dev