PythonでPDFを扱う際に「ページごとに分割したい」と感じたことはありませんか?
業務レポートの一部だけを抜き出したい、講義資料を問題別に分割したい、あるいは機能を限定した PDF を作りたい。そんなニーズに応えるのが、PDF 分割ライブラリです。
ここでは、Python で最もポピュラーな 3 つのライブラリ pypdf、PyMuPDF、PDFMiner を使い、実際に PDF を分割する手順を詳細に解説します。
- それぞれのライブラリが得意とする場面
- インストールから実装、そして注意点
- コード例とその解説
ぜひ「PDF 分割 失敗」や「PDF からページを拾う」といった疑問がある読者の参考になれば幸いです。
(実行前に pip install で必要パッケージをインストールしておくようにしてください)
pypdf (旧 PyPDF2) でシンプルに分割
pypdf は「PyPDF2」の後継プロジェクトで、純粋な Python で PDF 操作を行う代表的ライブラリです。
特に「ページ単位の抽出」「ページの結合」「ページの回転」など、典型的な操作は非常にシンプルに書くことができます。
1. インストール
pip install pypdf
2. 基本的な分割手順
-
PdfReaderで元ファイルを読み込む -
PdfWriterで新しい PDF を作成 -
add_pageで必要なページだけ追加 -
PdfWriter.write()でファイルへ書き出し
例:1 ページおきにペアで分割
from pypdf import PdfReader, PdfWriter
def split_every_two(source_path, output_dir):
reader = PdfReader(source_path)
total_pages = len(reader.pages)
for i in range(0, total_pages, 2):
writer = PdfWriter()
# ページ1
writer.add_page(reader.pages[i])
# ページ2 が存在すれば追加
if i + 1 < total_pages:
writer.add_page(reader.pages[i + 1])
out_path = f"{output_dir}/part_{i//2 + 1}.pdf"
with open(out_path, "wb") as f_out:
writer.write(f_out)
print(f"Generated: {out_path}")
# 使い方
split_every_two("large_document.pdf", "output_parts")
3. メリットとデメリット
| 観点 | メリット | デメリット |
|---|---|---|
| コードの可読性 | 単純な API で書きやすい | 大量ページ時にメモリをかなり消費 |
| 速度 | 1 ページ単位なら高速 | ライブラリ内部で全ページをオブジェクト化 |
| 依存性 | 追加パッケージ不要 | 画像やアンカーブックマークの扱いが限定的 |
pypdf は「純粋に PDF のページ構造をそのまま扱いたい」ケースに最適です。
ただ、元ファイルに多くの画像や特殊なフォントが埋め込まれていると、読み込みに時間がかかる場合があります。
PyMuPDF (fitz) で高速・多機能に分割
PyMuPDF(公式名:fitz)は、MuPDF という高速 C ライブラリを Python バインディングしたものです。
ページ内容をそのまま抽出したり、高品質な PDF 出力が必要な場合に有力です。
画像の埋め込みや、注釈(annotation)の保持なども得意範囲です。
1. インストール
pip install PyMuPDF
2. 分割サンプル
PyMuPDF では「ページをレンダリングして画像化」する手段も選べます。
以下では「ページ単位で分割し、注釈もそのまま保持」する例を示します。
import fitz # PyMuPDF
def split_by_page(source_path, output_dir):
doc = fitz.open(source_path)
for i, page in enumerate(doc, start=1):
# 1 ページずつ新規 PDF へ
new_doc = fitz.open()
new_doc.insert_pdf(doc, from_page=i-1, to_page=i-1)
out_path = f"{output_dir}/page_{i}.pdf"
new_doc.save(out_path, deflate=True, garbage=4)
new_doc.close()
print(f"Saved: {out_path}")
# 実行
split_by_page("example.pdf", "pages")
画像化したい時(JPEG で保存)
def page_to_image(source_path, output_dir, zoom=2, fmt="png"):
doc = fitz.open(source_path)
for i, page in enumerate(doc, start=1):
pix = page.get_pixmap(matrix=fitz.Matrix(zoom, zoom))
out_path = f"{output_dir}/page_{i}.{fmt}"
pix.save(out_path)
print(f"Image: {out_path}")
3. 利点・注意点
| 観点 | 利点 | 注意点 |
|---|---|---|
| 速度 | MuPDF の C 実装で高速、メモリ使用量抑制 | 画像化時は高解像度でメモリ消費が増える |
| 機能 | 注釈やフォーム要素、暗号化ファイルも扱える | 版画や特定のフォントでの描画差異が出ることがある |
| 互換性 | PDF 4 以上を完全サポート | 旧版 PDF(1.3)で一部機能が使えないことがある |
PyMuPDF は「画像化を伴う分割」や「注釈付きでそのまま分割」など、より高機能が必要な場面におすすめです。
PDFMiner.six でテキスト抽出重視の分割
PDFMiner.six は元々「テキスト抽出」専門のライブラリです。
ページごとの「テキスト」「レイアウト情報」を取得したい場合に優れています。
実際に「PDF から特定要素を抽出して新しい PDF を作る」シナリオに適しています。
1. インストール
pip install pdfminer.six
2. テキストで分割する例
以下では、10 ページごとに PDF を分割しつつ、抽出したテキストを併せて保存します。
このサンプルでは、PDFPage.get_pages() でページ番号を取得し、PDFPageInterpreter と LAParams でテキストを取得します。
from pdfminer.high_level import extract_text
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from PDFMiner.layout import LAParams
from pdfminer.converter import TextConverter
import io
def paginate_and_extract(source_path, out_dir, chunk=10):
# 1. 合計ページ数取得
with open(source_path, 'rb') as fp:
page_count = sum(1 for _ in PDFPage.get_pages(fp))
# 2. 分割
for start in range(1, page_count + 1, chunk):
end = min(start + chunk - 1, page_count)
# PDFMiner でページ単位のレンダリング
output_pdf = fitz.open()
input_pdf = fitz.open(source_path)
output_pdf.insert_pdf(input_pdf, from_page=start-1, to_page=end-1)
out_path = f"{out_dir}/chunk_{start}_to_{end}.pdf"
output_pdf.save(out_path)
output_pdf.close()
input_pdf.close()
print(f"Chunk PDF: {out_path}")
# 3. テキスト抽出
text = extract_text(source_path, page_numbers=list(range(start-1, end)))
text_path = f"{out_dir}/chunk_{start}_to_{end}.txt"
with open(text_path, "w", encoding="utf-8") as f:
f.write(text)
print(f"Text: {text_path}")
# 実行
paginate_and_extract("full_report.pdf", "chunks", chunk=10)
ポイント
extract_textはページ番号を 0 ベースで指定する必要があります。- PDF を分割した際は、
fitzを併用することで高速に分割できます。
3. メリット・デメリット
| 観点 | メリット | デメリット |
|---|---|---|
| テキスト抽出 | レイアウト保持(行・列)で正確な抽出 | 画像化 PDF ではテキストが見つからない場合が多い |
| 使い方 | 文書解析、機械学習前処理に最適 | PDF の元構造(画像、図形)は取得できない |
| 速度 | 低レベルで最適化されている | 大量ページ/大ファイルだと時間が掛かる |
PDFMiner は「文書内テキストの抽出」や「検索/索引作成」など、テキスト処理を軸にした分割に用いると発揮します。
実務で選ぶ 3 つの分割手段
| 要件 | 推奨ライブラリ |
|---|---|
| ① シンプル(単純ページ抜き取り) | pypdf |
| ② 注釈・画像付きで高速かつ高品質 | PyMuPDF |
| ③ テキスト抽出が主目的 | PDFMiner.six |
| ④ 既存の PDF 標準機能(ページ削除・回転等)を全うしたい | pypdf または PyMuPDF |
選択フロー例
-
「ページ単純分割」 →
pypdf -
「画像・注釈を保持」 →
PyMuPDF -
「本文テキストを大量抽出」 →
PDFMiner.six+PyMuPDF
よくある問題とその対策
| 問題 | 原因 | 対策 |
|---|---|---|
| 「ページが読み込めない」 | フォントが埋め込まれていない、または暗号化 | pypdf で decrypt(key) や、PyMuPDF の open(filename, filetype="pdf", fileobj=... ) を試す |
| **「分割後にページが欠落」 | PyMuPDF の insert_pdf するときに to_page を 0 ベースにしない |
from_page=i-1, to_page=i-1 のように 0 ベースに統一 |
| 「大容量 PDF でメモリが逼迫」 | すべてのページを一度に読み込んでいる | fitz.open(...).select で必要ページだけ読み込む、または PDFPage.get_pages() で 1 ページずつ処理 |
| 「抽出したテキストに余計な改行が入る」 | PDF 版画が横断線で改行として認識される | LAParams() で all_texts=True を設定し、テキスト結合方法を調整 |
| 「ページを JPEG で出力したい」 | fitz.Matrix のスケーリングが不十分 |
zoom_x = zoom_y = 2.0 など解像度を上げる |
まとめ
- pypdf は「シンプルなページ操作」に最適。コードが読みやすく、軽量化が容易。
- PyMuPDF は「高品質・高速」。注釈保持や画像化も可能で、ビギナーからプロフェッショナルまで幅広く使える。
- PDFMiner.six は「テキスト抽出重視」。解析やデータ取得のステップとして PDF を読むのに最適。
それぞれのライブラリには特性があり、プロジェクトに合わせて使い分けることで、PDF 分割作業をスムーズに行えます。実際の業務や開発環境に合わせて、ぜひ試してみてくださいね。


コメント