請求書と添付資料を一つにしたいときも、PDFの名前順が提出順とは限りません。入力するファイルと順番を明示し、元のPDFを残して別のファイルを作ります。
作業前に確認すること
pypdfを使えるPython環境を用意します。画像として取り込んだPDFを文字認識する処理とは別で、ここで扱うのはページの結合と取り出しです。機密資料は使ってよい保存場所と権限を確認してから扱います。
順番が重要なら、フォルダー内の全PDFを自動で拾うより、ファイル名を一覧にして確認します。作成済みの出力を次回の入力へ混ぜないことも、重複ページを防ぐ条件になります。
PDFを指定した順で結合する
次はa.pdfの後へb.pdfをつなぐ使用例です。公式資料のPdfWriter.appendを使います。merge_pdf.pyとして、二つのPDFと同じフォルダーへ保存します。
from pathlib import Path
from pypdf import PdfReader, PdfWriter
inputs = [Path("a.pdf"), Path("b.pdf")]
writer = PdfWriter()
for path in inputs:
reader = PdfReader(path)
if reader.is_encrypted:
raise ValueError(f"暗号化PDFは別途確認してください: {path.name}")
writer.append(reader)
with open("merged.pdf", "xb") as out:
writer.write(out)
writer.close()
たとえばa.pdfが2ページ、b.pdfが1ページなら、期待する出力はその順に3ページです。Python 3.12.14・pypdf 6.10.0の検証では空白ページのPDFを用意し、3ページへの結合と、後述する2ページ目だけの1ページへの取り出しを確認しました。業務資料の表示や署名の保持は未確認です。xbで開くため、同名の出力があると停止します。
必要なページを取り出す
次はinput.pdfの2ページ目だけを抜き出す使用例です。Pythonから指定する位置は0始まりなので、2ページ目はindexを1にします。
from pypdf import PdfReader, PdfWriter
reader = PdfReader("input.pdf")
if reader.is_encrypted:
raise ValueError("暗号化PDFは対象外です")
page_number = 2
if not 1 <= page_number <= len(reader.pages):
raise ValueError("指定ページがありません")
writer = PdfWriter()
writer.add_page(reader.pages[page_number - 1])
with open("page-2.pdf", "xb") as out:
writer.write(out)
writer.close()
連続するページ範囲を扱う場合も、画面で読む1始まりのページ番号と、Python側の位置を区別します。表紙を数えるか、紙面に印刷された番号を使うかも、依頼者と先に合わせます。
出力PDFの確認
結合後はページ数、最初と最後のページ、資料の境目を見ます。分割後は、取り出したページが依頼された内容かを確認します。文字化け、回転、用紙サイズ、リンクなど、業務で必要な要素も実際に開いて比べます。
署名付きのPDFや、入力フォームを持つPDFは、ページが見えることだけで元の性質を保てたとは判断しません。この例ではそれらの保持を確認していません。提出先の条件がある資料は、元ファイルを残し、必要な機能を確認してから使います。
元のPDFを削除したり、入力ファイルへ上書きしたりする処理は含めていません。出力を確認し、保管ルールに沿って整理するところまでを作業として決めておくと、後から書類を探し直しやすくなります。
関連する作業
PDFから文字を取り出す作業と、ツールを配布するときの説明は次の記事が関連します。
