手作業の PDF 読解が奪う時間
ビジネスの現場では、契約書・レポート・論文など大量の PDF を扱う機会が頻繁にあります。これらを手作業で読み込み、要約し、必要な情報を抽出するのは膨大な時間がかかります。
Claude API の Vision 機能と Extended Thinking を組み合わせることで、PDF のページ画像を直接解析し、深い推論を経た高品質な要約を自動生成するアプリケーションを構築できます。Python を使って実用的な PDF 解析・要約パイプラインを一から構築する方法を順を追って整理していきます。
Claude API の基本的な使い方についてはClaude API チャットボット構築 完全ガイドを、Extended Thinking の仕組みについては Extended Thinking 解説を参照してください。
前提知識と環境準備
必要なもの
- Python 3.10 以上
- Anthropic API キー(console.anthropic.com で取得)
anthropicPython SDK(v0.40 以上)pdf2image(PDF → 画像変換用)- Poppler(pdf2image の依存ライブラリ)
環境セットアップ
# 必要なパッケージをインストール
pip install anthropic pdf2image Pillow
# macOS の場合、Poppler もインストール
brew install poppler
# Ubuntu/Debian の場合
# sudo apt-get install poppler-utilsアーキテクチャの全体像
このアプリケーションは、以下の3つのステップで動作します。
- PDF → 画像変換:
pdf2imageで PDF の各ページを PNG 画像に変換 - Vision 解析: Claude API の Vision 機能で各ページの内容をテキスト化
- Extended Thinking 要約: 抽出したテキストを Extended Thinking で深く分析し、構造化された要約を生成
この設計により、スキャンされた PDF や図表を含む PDF にも対応でき、テキスト抽出ライブラリでは取りこぼしやすい視覚的な情報も正確に捉えることができます。
ステップ 1:PDF を画像に変換する
まず、PDF の各ページを画像として取得する関数を作成します。
import base64
from io import BytesIO
from pdf2image import convert_from_path
from PIL import Image
def pdf_to_base64_images(pdf_path: str, dpi: int = 200) -> list[str]:
"""
PDF の各ページを base64 エンコードされた PNG 画像に変換する。
Args:
pdf_path: PDF ファイルのパス
dpi: 画像の解像度(デフォルト: 200)
Returns:
base64 エンコードされた画像文字列のリスト
"""
# PDF を画像リストに変換
pages = convert_from_path(pdf_path, dpi=dpi)
base64_images = []
for page in pages:
# 画像をバイトストリームに変換
buffer = BytesIO()
page.save(buffer, format="PNG")
buffer.seek(0)
# base64 エンコード
img_base64 = base64.b64encode(buffer.read()).decode("utf-8")
base64_images.append(img_base64)
return base64_images
# 使用例
# images = pdf_to_base64_images("report.pdf")
# print(f"ページ数: {len(images)}")
# 期待する出力: ページ数: 12DPI を 200 に設定することで、テキストの読み取り精度と画像サイズのバランスを取っています。グラフや細かい表が多い PDF の場合は 300 に上げるとよいでしょう。
ステップ 2:Vision でページ内容を抽出する
次に、各ページの画像を Claude API の Vision 機能で解析します。
import anthropic
client = anthropic.Anthropic() # ANTHROPIC_API_KEY 環境変数を使用
def extract_page_content(base64_image: str, page_number: int) -> str:
"""
Claude Vision API で PDF ページの内容をテキストとして抽出する。
Args:
base64_image: base64 エンコードされた画像
page_number: ページ番号(ログ出力用)
Returns:
抽出されたテキスト
"""
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=4096,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": base64_image,
},
},
{
"type": "text",
"text": (
f"このPDFのページ {page_number} の内容を正確に抽出してください。"
"テキスト、表、図のキャプション、数式などすべての情報を含めてください。"
"表はMarkdown形式で再現してください。"
"図やグラフは内容を説明してください。"
),
},
],
}
],
)
return response.content[0].text
def extract_all_pages(base64_images: list[str]) -> list[dict]:
"""全ページの内容を抽出する。"""
results = []
for i, img in enumerate(base64_images, start=1):
print(f"ページ {i}/{len(base64_images)} を処理中...")
text = extract_page_content(img, i)
results.append({"page": i, "content": text})
return results
# 使用例
# pages = extract_all_pages(images)
# print(pages[0]["content"][:200])Sonnet 4.6 は Vision タスクにおいてコストパフォーマンスが優れています。精度を最優先する場合は claude-opus-4-6 に切り替えることもできます。
ステップ 3:Extended Thinking で深い要約を生成する
抽出したテキストを統合し、Extended Thinking を使って高品質な要約を生成します。
def summarize_with_extended_thinking(
pages: list[dict],
thinking_budget: int = 10000,
summary_language: str = "ja",
) -> dict:
"""
Extended Thinking を使って PDF 全体の要約を生成する。
Args:
pages: ページごとの抽出テキスト
thinking_budget: thinking トークン上限
summary_language: 要約の言語("ja" or "en")
Returns:
{"thinking": str, "summary": str} の辞書
"""
# 全ページのテキストを結合
full_text = "\n\n".join(
f"--- ページ {p['page']} ---\n{p['content']}" for p in pages
)
lang_instruction = (
"日本語で要約してください。" if summary_language == "ja"
else "Summarize in English."
)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=16000,
thinking={
"type": "enabled",
"budget_tokens": thinking_budget,
},
messages=[
{
"role": "user",
"content": (
f"以下はPDF文書(全{len(pages)}ページ)の内容です。\n\n"
f"{full_text}\n\n"
"この文書について以下の形式で要約を作成してください。"
f"{lang_instruction}\n\n"
"1. **概要**(3〜5文で文書全体の要点)\n"
"2. **主要なポイント**(箇条書きで5〜10項目)\n"
"3. **重要な数値・データ**(表や数値の抜粋)\n"
"4. **結論・提言**(文書の結論部分)\n"
"5. **注意点・制約事項**(見落としやすい点)"
),
}
],
)
thinking_text = ""
summary_text = ""
for block in response.content:
if block.type == "thinking":
thinking_text = block.thinking
elif block.type == "text":
summary_text = block.text
return {"thinking": thinking_text, "summary": summary_text}
# 使用例
# result = summarize_with_extended_thinking(pages, thinking_budget=10000)
# print(result["summary"])thinking_budget を 10,000 トークンに設定することで、複雑な文書でも十分な推論時間を確保できます。論文のような高度な文書の場合は 20,000 まで引き上げると、分析の深さが向上します。
完成版:PDF 解析パイプライン
上記の関数を統合した、実用的なスクリプトの全体像です。
import sys
import json
from pathlib import Path
def analyze_pdf(pdf_path: str, output_path: str = None) -> dict:
"""
PDF ファイルを解析し、構造化された要約を生成する。
Args:
pdf_path: 解析対象の PDF パス
output_path: 結果の保存先(省略時は標準出力)
Returns:
解析結果の辞書
"""
print(f"📄 PDF を読み込み中: {pdf_path}")
# Step 1: PDF → 画像
images = pdf_to_base64_images(pdf_path)
print(f"✅ {len(images)} ページを画像に変換しました")
# Step 2: Vision でテキスト抽出
pages = extract_all_pages(images)
print(f"✅ 全ページのテキスト抽出が完了しました")
# Step 3: Extended Thinking で要約生成
result = summarize_with_extended_thinking(pages)
print(f"✅ 要約の生成が完了しました")
# 結果を構成
output = {
"source": pdf_path,
"total_pages": len(pages),
"pages": pages,
"summary": result["summary"],
"thinking_process": result["thinking"],
}
# ファイルに保存
if output_path:
Path(output_path).write_text(
json.dumps(output, ensure_ascii=False, indent=2),
encoding="utf-8",
)
print(f"💾 結果を保存しました: {output_path}")
return output
if __name__ == "__main__":
pdf_file = sys.argv[1] if len(sys.argv) > 1 else "document.pdf"
analyze_pdf(pdf_file, output_path="analysis_result.json")実行方法
# 環境変数に API キーを設定
export ANTHROPIC_API_KEY="YOUR_API_KEY"
# PDF を解析
python pdf_analyzer.py quarterly_report.pdf
# 期待する出力:
# 📄 PDF を読み込み中: quarterly_report.pdf
# ✅ 12 ページを画像に変換しました
# ページ 1/12 を処理中...
# ...
# ✅ 全ページのテキスト抽出が完了しました
# ✅ 要約の生成が完了しました
# 💾 結果を保存しました: analysis_result.jsonよくあるエラーと対処法
Poppler が見つからないエラー
pdf2image.exceptions.PDFInfoNotInstalledError
Poppler がインストールされていない場合に発生します。brew install poppler(macOS)または apt-get install poppler-utils(Ubuntu)でインストールしてください。
画像サイズが大きすぎるエラー
Claude API には画像サイズの制限があります。DPI を下げるか、画像をリサイズするロジックを追加してください。
def resize_if_needed(image: Image.Image, max_size: int = 2048) -> Image.Image:
"""画像が大きすぎる場合にリサイズする。"""
w, h = image.size
if max(w, h) > max_size:
ratio = max_size / max(w, h)
new_size = (int(w * ratio), int(h * ratio))
return image.resize(new_size, Image.LANCZOS)
return imageExtended Thinking のトークン制限
thinking_budget を超えると思考が途中で打ち切られます。要約の品質が低いと感じたら、budget を増やしてください。ただし、コストも比例して増加する点に注意が必要です。
まとめ
ここではClaude API の Vision 機能と Extended Thinking を活用して、PDF 解析・要約アプリケーションを構築する方法を解説しました。テキスト抽出が困難なスキャン PDF や図表を含む複雑な文書でも、Vision ベースのアプローチにより高精度な情報抽出が可能です。
Extended Thinking を組み合わせることで、単なるテキスト変換にとどまらない、文書の構造や論点を深く理解した質の高い要約を生成できます。ぜひ自社のドキュメント管理や情報収集のワークフローに組み込んでみてください。
API 設計の