Excel の重複行を見つけて確認用に分離する
4列すべての値が完全一致する行を見つけ、元の行番号とともに新しい Excel ファイルへまとめます。最初に出現した行も含め、重複グループごとに確認します。
複数の PDF を1つのファイルに結合し、指定した両端を含むページ範囲を2つ目のファイルとして抽出し、結果のページ数と順序を確認します。意図的に寸法を変えた空白ページの合成セットを使うため、結果を手作業でも確認できます。
この翻訳はAIで作成しました。コード、単位、数値は原文と併せて確認してください。各言語のネイティブ話者による校閲は、まだ完了していません。 English
対象読者元の文書を変更せずに PDF を結合したり、選択したページを抽出したりしたい人向けのガイドです。
この workflow では、3つの source PDFs を明示した順序で使用します: alpha.pdf, beta.pdf, gamma.pdf。それぞれの pages を1つの merged PDF に追加します。その後、通常の人間向けページ番号で最初のページを page 1 として、merged PDF の pages 2 through 5 を2つ目の output に抽出します。
Python sequences は zero-based indexes を使用しますが、この script では START_PAGE と END_PAGE を one-based inclusive page numbers として受け取ります。したがって pages 2 through 5 は Python slice positions 1 through 4 に対応し、merged_reader.pages[START_PAGE - 1:END_PAGE] として実装します。
以下の PDFs は合成データであり、この記事のために作成したものです。各 page は空白ですが、すべての page で width と height が異なります。これにより、別の PDF-generation package を使わなくても page order を独立して確認できます。
from pathlib import Path
from pypdf import PdfWriter
SOURCE_DIR = Path("outputs") / "pdf_merge_split_demo"
PDFS = {
"alpha.pdf": [(100, 200), (110, 210)],
"beta.pdf": [(120, 220)],
"gamma.pdf": [(130, 230), (140, 240), (150, 250)],
}
SOURCE_DIR.parent.mkdir(parents=True, exist_ok=True)
SOURCE_DIR.mkdir() # Stop if the synthetic source already exists.
for filename, page_sizes in PDFS.items():
writer = PdfWriter()
for width, height in page_sizes:
writer.add_blank_page(width=width, height=height)
target = SOURCE_DIR / filename
with target.open("xb") as stream:
writer.write(stream)
python create_pdf_demo.py| Source PDF | Pages | 順番ごとの page dimensions |
|---|---|---|
| alpha.pdf | 2 | 100×200, 110×210 |
| beta.pdf | 1 | 120×220 |
| gamma.pdf | 3 | 130×230, 140×240, 150×250 |
3つの source files には合計 6 pages があります: 2 + 1 + 3。dimensions は PDF user-space units で表しています。ここでの目的は、各合成 page に識別可能な signature を与えることだけです。
inputs は明示的に列挙しているため、merged PDF には最初に alpha の2 pages、その後 beta の page、最後に gamma の3 pages が入るはずです。したがって merged result は 6 pages になります。
| Merged page | Source | 想定 dimensions |
|---|---|---|
| 1 | alpha.pdf page 1 | 100×200 |
| 2 | alpha.pdf page 2 | 110×210 |
| 3 | beta.pdf page 1 | 120×220 |
| 4 | gamma.pdf page 1 | 130×230 |
| 5 | gamma.pdf page 2 | 140×240 |
| 6 | gamma.pdf page 3 | 150×250 |
したがって merged pages 2 through 5 を抽出すると、110×210, 120×220, 130×230, 140×240 の dimensions をこの順序で持つ正確に 4 pages が作成されるはずです。
次の script を pdf_merge_split.py として保存してください。各 input file を検証し、この簡単な例では encrypted PDFs を拒否し、すべての pages を結合し、merged output を再度開いて検証してから、指定した page-range file を作成します。
from pathlib import Path
from pypdf import PdfReader, PdfWriter
SOURCE_DIR = Path("outputs") / "pdf_merge_split_demo"
INPUTS = ("alpha.pdf", "beta.pdf", "gamma.pdf")
OUTPUT_DIR = Path("outputs") / "pdf_merge_split_result"
MERGED = OUTPUT_DIR / "merged.pdf"
EXTRACTED = OUTPUT_DIR / "pages_2_to_5.pdf"
START_PAGE = 2
END_PAGE = 5
def page_size(page) -> tuple[int, int]:
width = int(float(page.mediabox.width))
height = int(float(page.mediabox.height))
return width, height
def main() -> None:
source_root = SOURCE_DIR.resolve(strict=True)
if not source_root.is_dir():
raise ValueError("SOURCE_DIR must be a directory.")
if START_PAGE < 1 or END_PAGE < START_PAGE:
raise ValueError("Invalid page range.")
input_paths = [source_root / name for name in INPUTS]
for path in input_paths:
if not path.is_file():
raise FileNotFoundError(f"Missing input PDF: {path}")
OUTPUT_DIR.parent.mkdir(parents=True, exist_ok=True)
OUTPUT_DIR.mkdir() # Refuse to reuse an existing result folder.
expected_sizes = []
writer = PdfWriter()
for path in input_paths:
reader = PdfReader(path)
if reader.is_encrypted:
raise ValueError(f"Encrypted PDF is not supported here: {path.name}")
for page in reader.pages:
expected_sizes.append(page_size(page))
writer.add_page(page)
with MERGED.open("xb") as stream:
writer.write(stream)
merged_reader = PdfReader(MERGED)
if merged_reader.is_encrypted:
raise RuntimeError("Unexpected encrypted merged PDF.")
merged_sizes = [page_size(page) for page in merged_reader.pages]
if merged_sizes != expected_sizes:
raise RuntimeError("Merged page count or order does not match the inputs.")
if END_PAGE > len(merged_reader.pages):
raise ValueError(
f"Requested page {END_PAGE}, but merged PDF has only "
f"{len(merged_reader.pages)} pages."
)
selected_pages = merged_reader.pages[START_PAGE - 1:END_PAGE]
extracted_writer = PdfWriter()
expected_extract_sizes = []
for page in selected_pages:
expected_extract_sizes.append(page_size(page))
extracted_writer.add_page(page)
with EXTRACTED.open("xb") as stream:
extracted_writer.write(stream)
extracted_reader = PdfReader(EXTRACTED)
extracted_sizes = [page_size(page) for page in extracted_reader.pages]
if extracted_sizes != expected_extract_sizes:
raise RuntimeError("Extracted PDF does not match the selected pages.")
print(f"Merged {len(INPUTS)} PDFs into {len(merged_reader.pages)} pages.")
print(
f"Extracted pages {START_PAGE}-{END_PAGE}: "
f"{len(extracted_reader.pages)} pages."
)
print(f"Merged output: {MERGED.as_posix()}")
print(f"Extracted output: {EXTRACTED.as_posix()}")
if __name__ == "__main__":
main()
python pdf_merge_split.py最初の output である merged.pdf には 6 pages が含まれるはずです。2つ目の output である pages_2_to_5.pdf には 4 pages が含まれるはずです。script が人間向け page numbers を対応する Python slice に変換するため、抽出範囲は両端を含みます。
| Output | 想定 pages | 順番ごとの想定 dimensions |
|---|---|---|
| merged.pdf | 6 | 100×200, 110×210, 120×220, 130×230, 140×240, 150×250 |
| pages_2_to_5.pdf | 4 | 110×210, 120×220, 130×230, 140×240 |
以下の想定 console text は、合成 inputs と code から手作業で導出したものです。execution log ではありません。
Merged 3 PDFs into 6 pages.
Extracted pages 2-5: 4 pages.
Merged output: outputs/pdf_merge_split_result/merged.pdf
Extracted output: outputs/pdf_merge_split_result/pages_2_to_5.pdf実際の documents では、page content も目視で確認してください。counts が一致するだけでは、想定外の input order や、source PDF の page labels と physical page positions が異なる問題など、すべての問題を検出できません。
| 症状 | 確認すること |
|---|---|
| ModuleNotFoundError: No module named pypdf | python -m pip install pypdf を使い、同じ Python environment に pypdf をインストールします。 |
| FileNotFoundError | SOURCE_DIR, INPUTS, terminal の working directory を確認します。この例では先に synthetic setup script を実行してください。 |
| FileExistsError | result folder がすでに存在します。以前の outputs を確認し、上書きではなく新しい folder を選択します。 |
| Encrypted PDF is not supported here | 許可された decrypted copy を使用するか、documents に適した明示的な password-handling workflow を追加します。 |
| Requested page is beyond the merged PDF | merged page count と one-based START_PAGE, END_PAGE values を確認します。 |
| Merged or extracted verification mismatch | 生成 file を unverified として扱います。inputs を確認し、次の実行では新しい output folder を使用します。 |
OUTPUT_DIR 作成後に exception が発生すると、partial files が残る場合があります。script はそれらを自動削除しません。failed outputs は verified files と分けて保持してください。
この workflow が検証するのは physical page count と page dimensions であり、semantic content ではありません。rendered pixels, extracted text, annotations, forms, bookmarks, named destinations, attachments, signatures, accessibility structure は比較しません。
PDF page labels は physical page positions と異なる場合があります。document が roman numerals や custom labels を表示していても、pypdf は page objects を zero-based sequence position で扱います。この tutorial の START_PAGE と END_PAGE は printed page numbers ではなく physical sequence positions を指します。
複雑な PDFs には interactive forms, digital signatures, encrypted content, unusual object relationships など、より慎重な処理が必要な features が含まれる場合があります。digitally signed PDF を新しい document に merge しても、元の signature が新しい file 全体に対する署名として持っていた意味は保持されません。重要な records では、merged copy を original と同等として扱う前に、関連する PDF requirements を確認してください。
2026-09-20 · 手作業で確認した例 · 対象: Python 3.12 · pypdf 必須 · 未実行
説明と例は独自に作成しました。関連する動作や概念は、以下の公式資料で確認できます。