Claude CodeでPDFを操作する方法 ― 公式pdfスキルを実際に検証した
Claude CodeでPDF(見積書・契約書)を読み取り・抽出・生成する方法を公式pdfスキルで実際に検証。パスワード保護PDFのエラー対処、日本語PDF生成で文字化けする原因、崩れた表の抽出テクニックまで実例で整理した。
エンジニアのゆとです。
クライアントから届く見積書や契約書は、なぜかだいたいPDFで来る。しかも「品目・数量・単価・金額」が並んだ表があるのに罫線がなかったり、パスワードがかかっていて開けなかったり、スキャンしたやつをそのまま送ってきて文字が選択できなかったり。毎回手で転記するのが地味にしんどくて、「これClaude Codeに投げたら楽にならないか」と思って触ってみた。
先に断っておくと、この記事は前回書いたExcelの記事の延長線上にある。ExcelのときはAnthropic公式のxlsxスキルを検証したが、同じリポジトリにpdfスキルも公開されている。今回はそれを実際に使い、自分で崩れたPDFを作って抽出・生成・パスワード解除・OCRまで一通り試した結果をまとめる。
まず結論 — Claude.aiのPDFアップロードとは別物
検索すると「ClaudeはPDFを読める」という記事がたくさん出てくるが、そのほとんどはClaude.ai(ブラウザ版・アプリ版)にPDFをドラッグ&ドロップしてチャットで要約させる話だ。これはClaudeのビジョン機能でPDFのページを画像として読み取り、その場で質問に答える方式で、単発の「このPDFの内容を教えて」には強い。
一方Claude Codeは、PDFを直接「読む」機能を持っているわけではない。実体は「Pythonスクリプトを書いて実行し、結果を報告する」エージェントなので、PDFに対してもpypdfやpdfplumberといったライブラリ経由で処理する。その定石をあらかじめまとめてあるのが、Anthropic公式のpdfスキルという位置づけになる。
| 方法 | 実体 | 向いている場面 | 向いていない場面 |
|---|---|---|---|
| Claude.aiにPDFをアップロード | ビジョンでページ画像を読み取りチャット | 1回だけ内容を要約・質問したい | 大量ファイルの一括処理、決まった形式での抽出 |
| Claude Code + 公式pdfスキル | pypdf/pdfplumber/reportlab等をコードで実行 | 表の抽出、結合・分割、PDF生成、バッチ処理 | Excel感覚でセルを触りながら対話したい場合 |
自分のように「毎月似た形式の見積書・契約書が届いて、同じ処理を繰り返す」ケースなら、Claude Code + pdfスキルでコード化しておく方が圧倒的に楽になる。逆に1回だけの要約なら、わざわざCLIを開かずClaude.aiに投げた方が早い。
公式pdfスキルの中身
anthropics/skillsリポジトリのpdfスキルは、SKILL.mdを読むと守備範囲が明確に書かれている。
Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable.
中心になるライブラリは3つ。
pypdf— 結合・分割・回転・メタデータ・暗号化/復号など、ページ単位の操作pdfplumber— テキスト・表の抽出(座標情報付き)reportlab— 新規PDFの作成(請求書・レポート等)
導入はExcelのときと同じくプラグイン経由。
/plugin marketplace add anthropics/skills
/plugin install document-skills@anthropic-agent-skills
インストール後は「このPDFから表を抜き出して」のように頼むだけで、スキル側が上記ライブラリを使ったコードを組み立ててくれる。ここからは実際に自分で崩れたPDFを作って、スキルが想定している処理を自分の手でも再現しながら検証した内容になる。
実際にやってみた1 — 罫線のない見積書から表を抜き出す
まず、クライアントから届く見積書に近い形のPDFをreportlabで自作した。品目・数量・単価・金額の4列だが、罫線は引かず、座標を指定して文字を並べただけの「テキストベースの表」にした。実務でよくあるパターンで、Wordやパワポからそのまま書き出したPDFはだいたいこうなっている。
これをpdfplumberのextract_tables()にかけると、結果は空配列だった。
import pdfplumber
with pdfplumber.open("quote_sample.pdf") as pdf:
page = pdf.pages[0]
print(page.extract_tables()) # => []
extract_tables()は罫線(または明確な空白の区切り)を手がかりに表を検出する仕組みなので、線を引いていないPDFでは何も拾えない。extract_text()ならテキストは取れるが、行の中で列がバラバラに崩れて出てくる。
そこで使ったのが、extract_words()で1語ずつの座標(x0, top)を取得し、top(縦位置)でグループ化してからx0(横位置)でソートし直す方法だ。
from collections import defaultdict
with pdfplumber.open("quote_sample.pdf") as pdf:
words = pdf.pages[0].extract_words()
rows = defaultdict(list)
for w in words:
rows[round(w["top"])].append(w)
for top in sorted(rows.keys()):
line = sorted(rows[top], key=lambda w: w["x0"])
print([w["text"] for w in line])
実行結果はこうなった。
['品目', '数量', '単価', '金額']
['Webサイト保守作業', '1式', '80,000円', '80,000円']
['サーバー監視ツール導入', '3', '15000', '45000']
['緊急対応(休日込み)', '2.5h', '8,000円/h', '20,000円']
extract_tables()が空を返しても、行ごとの構造は座標さえ拾えば十分に復元できる。罫線のないPDFから表を抜きたいときは、この「座標クラスタリング」を選択肢として知っておくと詰まりにくい。
実際にやってみた2 — 日本語PDFを生成したら文字化けした
次にreportlabで日本語の見積書PDFを新規作成しようとしたところ、思わぬところでつまずいた。標準のHelveticaフォントで日本語テキストをdrawString()すると、生成自体はエラーなく成功するのに、pdfplumberで読み直すと文字が全部潰れている。
c.setFont("Helvetica", 10)
c.drawString(20*mm, y, "株式会社サンプル商事")
このPDFを読み直すと、extract_text()の結果はnnnnnnnnnnのような意味のない文字列になった。パスワードをかけてから復号した場合は■■■■■■■■■■と表示のされ方まで変わったが、原因は同じで、Helveticaが日本語のグリフを持っていないため表示・抽出の両方で情報が失われる。
対処法は、reportlabが標準で持っているCIDフォント(Adobe-Japan1準拠)を使うこと。フォントファイルを別途用意する必要がない。
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
pdfmetrics.registerFont(UnicodeCIDFont("HeiseiKakuGo-W5")) # ゴシック体
pdfmetrics.registerFont(UnicodeCIDFont("HeiseiMin-W3")) # 明朝体
c.setFont("HeiseiKakuGo-W5", 16)
c.drawString(20*mm, y, "御見積書")
これで生成したPDFを読み直すと、extract_text()は御見積書のように正しく返ってくる。Claude Codeに「請求書PDFを作って」と頼んだときに日本語が化けたら、まずフォント指定を疑うとよい。英語圏で書かれた情報がベースのライブラリなので、日本語対応はこちらから明示しないといけない場面がまだ多い。
実際にやってみた3 — パスワード保護PDFのエラーと解除
取引先から「パスワード付きでお送りします」というPDFが届くこともある。これを何も考えずにpypdfで読もうとすると、明確な例外が返ってくる。
from pypdf import PdfReader
reader = PdfReader("quote_sample_locked.pdf")
print(reader.is_encrypted) # True
reader.pages[0].extract_text() # FileNotDecryptedError: File has not been decrypted
is_encryptedで暗号化を検知した上で、decrypt()にパスワードを渡せば読めるようになる。
result = reader.decrypt("1234")
print(result) # 2 (ユーザーパスワードで復号成功)
text = reader.pages[0].extract_text()
decrypt()の戻り値は復号の種別を示す数値で、0が失敗、1がユーザーパスワードでの成功、2がオーナーパスワードでの成功を意味する。Claude Codeにパスワード付きPDFをそのまま渡すと、このエラーメッセージを読んで「パスワードを教えてください」と聞き返してくることが多い。パスワードが分かっているなら最初から伝えておいた方が手数が減る。
実際にやってみた4 — 結合とスキャンPDFのOCR
複数ページの見積書と契約条件のPDFを1つにまとめる作業はpypdfで数行で終わる。
from pypdf import PdfWriter, PdfReader
writer = PdfWriter()
for path in ["quote.pdf", "terms.pdf"]:
for page in PdfReader(path).pages:
writer.add_page(page)
with open("merged.pdf", "wb") as f:
writer.write(f)
もう1つ、スキャンしただけでテキスト情報を持たないPDF(いわゆる「画像PDF」)も試した。自作のPDFを一度画像化し、テキストレイヤーを持たない状態を再現してから、pdf2imageでページを画像に変換しpytesseractでOCRをかけた。
from pdf2image import convert_from_path
import pytesseract
images = convert_from_path("scanned.pdf", dpi=200)
text = pytesseract.image_to_string(images[0], lang="jpn")
結果は「読めるが完璧ではない」というのが正直な感触だった。御見積書や株式会社サンプル商事といった見出しは正確に拾えた一方、2026/09/20という日付が2026092の0に、2.5hが25nに化けるなど、数字や記号が混じる箇所で誤認識が出た。それとlang=“jpn”を明示しないと日本語部分がそのまま文字化けするので、tesseract --list-langsでjpnが入っているか事前に確認しておく必要がある(Homebrew版はbrew install tesseract-langで追加)。
金額や日付のような数字が命の情報をOCR任せにするのはリスクがあるので、スキャンPDFから数値を拾う場合は、OCR結果をそのまま信じずに元画像と突き合わせる工程を挟んだ方が安全だと感じた。
ハマりどころ早見表
| 症状 | 原因 | 対処 |
|---|---|---|
extract_tables()が空を返す | 罫線がないテキストベースの表 | extract_words()の座標でクラスタリングして復元 |
| 生成したPDFの日本語が文字化け/抽出できない | Helvetica等の標準フォントが日本語グリフ非対応 | UnicodeCIDFont(HeiseiKakuGo-W5等)を使う |
FileNotDecryptedError | パスワード保護PDFを復号せずに読もうとした | reader.decrypt(password)してから処理する |
| OCR結果の数字が微妙に違う | スキャン画質・フォントによる誤認識 | 元画像との突き合わせを必須にする、重要な数値は目視確認 |
| 日本語OCRが文字化けする | lang未指定でtesseractが英語モデルを使う | lang="jpn"を明示、tesseract-lang導入を確認 |
使い分けの早見表
- 1回だけPDFの内容を要約・質問したい → Claude.aiにアップロードして聞く
- 毎月似た形式の見積書・契約書が届いて同じ処理を繰り返す、複数PDFの結合/分割を自動化したい → Claude Code + 公式pdfスキル
- スキャンPDFから重要な数値を抜く必要がある → OCRは使いつつ、金額・日付は目視確認を挟む前提で設計する



よくある質問
Claude CodeでPDFを新規に生成できますか?
できる。reportlabを使えば請求書やレポートのようなレイアウトのPDFを新規作成できる。ただし日本語を使う場合は標準フォントでは文字化けするので、CIDフォントの指定を忘れないこと。
Claude CodeにPDFファイルをそのまま渡せますか?
渡すこと自体は可能だが、Claude Code自身がPDFの中身を画像として直接「見て」いるわけではない。実際にはコードを書いてpypdfやpdfplumberで開き、その実行結果を読んで応答している。表の位置関係や図表の詳細な読み取りが必要な場合は、精度に限界があることを踏まえておいた方がいい。
大きいPDFを渡すとどうなりますか?
数百ページ規模のPDFを丸ごとテキスト化すると出力が膨大になり、コンテキストを圧迫する。必要なページ範囲だけpdftotext -f 1 -l 5のように絞って渡す、あるいは目的のセクションだけをpypdfで抜き出してから渡す方が安定する。
崩れたPDFを直す作業は、崩れたExcelを直す作業とよく似ている。どちらも「人間が読む前提で作られたファイルを、機械可読な形に戻す」作業で、地味だが積み重なる。1回分の処理をスクリプトとして残しておけば、来月似たPDFが届いたときに同じ苦労をしなくて済む。