跳至主要內容
找不到符合條件的結果
  • 技術筆記
  • 工具庫
小豬日常
  • 技術筆記
  • 工具庫
小豬日常
首頁 技術筆記 使用 Python 批量修正 PDF Metadata Title 為檔名

使用 Python 批量修正 PDF Metadata Title 為檔名

  • 小豬
  • 2025-12-10
  • 技術筆記

內容目錄

Toggle
  • 前言
  • 使用 pypdf 讀寫 PDF Metadata
    • 讀取與複製 PDF 頁面
    • 修改 Metadata 中的 Title
  • 備份原始檔案與覆寫
  • 遞迴走訪資料夾
  • 實際應用與延伸
  • 常見問題與注意事項
  • 完整程式碼

前言

在處理大量 PDF 文件時,常會遇到檔案內嵌的 Metadata Title 與實際檔名不符的問題,這會影響文件管理與搜尋效率。本文示範如何利用純 Python 的 pypdf 套件,自動走訪指定資料夾(含子資料夾)內所有 PDF,將其 Metadata 中的 Title 欄位批量更新為檔名(不含副檔名),同時保留其他 Metadata,並備份原始檔案。適合需要批量整理 PDF 檔案屬性的工程師與自學者。

使用 pypdf 讀寫 PDF Metadata

pypdf 是一個純 Python 的 PDF 操作套件,能讀取與修改 PDF 的內容與屬性。本文重點在修改 PDF 的 Metadata,特別是 /Title 欄位。

讀取與複製 PDF 頁面

為了保留 PDF 內容,先使用 PdfReader 讀取原始 PDF,再用 PdfWriter 複製所有頁面:

reader = PdfReader(str(src_for_edit))
writer = PdfWriter()
for page in reader.pages:
    writer.add_page(page)

這樣做是為了在不破壞內容的前提下,更新 Metadata。

修改 Metadata 中的 Title

原始 Metadata 透過 reader.metadata 取得,是一個字典。為避免遺失其他欄位,先複製除了 /Title 以外的欄位,並將值轉成字串:

orig_meta = reader.metadata or {}
new_meta = {}
for key, value in orig_meta.items():
    if key == "/Title":
        continue
    if value is None:
        continue
    new_meta[key] = str(value)

接著設定新的 Title 為檔名(不含副檔名):

new_meta["/Title"] = pdf_path.stem
writer.add_metadata(new_meta)

這樣可以確保只改 Title,其他 Metadata 保持不變。

備份原始檔案與覆寫

為防止資料遺失,程式會先建立備份檔案(檔名加上 .bak),如果備份已存在,則直接使用原檔:

backup_path = pdf_path.with_suffix(pdf_path.suffix + ".bak")
if not backup_path.exists():
    shutil.copy2(pdf_path, backup_path)
    src_for_edit = backup_path
else:
    src_for_edit = pdf_path

最後將修改後的 PDF 直接覆寫原始檔案。

遞迴走訪資料夾

利用 pathlib 的 rglob 方法,可以遞迴搜尋指定資料夾底下所有 .pdf 檔案,並過濾掉備份檔:

for path in root.rglob("*.pdf"):
    if path.name.endswith(".pdf.bak"):
        continue
    fix_pdf_title(path)

實際應用與延伸

此工具適合用於資料整理、文件管理系統,或是需要統一 PDF Metadata 的場景。未來可擴充功能,例如修改其他 Metadata 欄位、支援多種檔案格式,或加入多線程提升處理效率。

常見問題與注意事項

  • 確保執行環境有安裝 pypdf 套件。
  • 備份機制避免資料遺失,但仍建議先手動備份重要檔案。
  • 修改 Metadata 不會改變 PDF 內容,但部分 PDF 可能因加密或損毀導致處理失敗。

完整程式碼

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
批量修正 PDF Metadata Title(使用 pypdf,純 Python,不需編譯)

功能:
- 走訪指定資料夾(含子資料夾)所有 .pdf
- 把 PDF 內嵌的 /Title 改成「檔名(不含 .pdf)」
- 原檔先備份成 xxx.pdf.bak
"""

import sys
from pathlib import Path
import shutil

from pypdf import PdfReader, PdfWriter

def fix_pdf_title(pdf_path: Path):
    """把單一 PDF 的 Title 改成檔名(不含副檔名)"""
    try:
        print(f"處理:{pdf_path}")

        # 建立備份:xxx.pdf.bak(如果已存在就略過)
        backup_path = pdf_path.with_suffix(pdf_path.suffix + ".bak")
        if not backup_path.exists():
            shutil.copy2(pdf_path, backup_path)
            src_for_edit = backup_path  # 從備份讀
        else:
            src_for_edit = pdf_path     # 已備份過就直接用目前檔案

        # 讀 PDF
        reader = PdfReader(str(src_for_edit))
        writer = PdfWriter()

        # 複製所有頁
        for page in reader.pages:
            writer.add_page(page)

        # 讀取原有 metadata
        orig_meta = reader.metadata or {}
        new_meta = {}

        # 保留其他欄位,只改 /Title
        for key, value in orig_meta.items():
            if key == "/Title":
                continue
            if value is None:
                continue
            new_meta[key] = str(value)

        # 設定新的 Title = 檔名(不含 .pdf)
        new_title = pdf_path.stem
        new_meta["/Title"] = new_title

        writer.add_metadata(new_meta)

        # 寫回原本檔名(覆蓋)
        with open(pdf_path, "wb") as f_out:
            writer.write(f_out)

        print(f"  ✅ 已更新 Title 為:{new_title}\n")

    except Exception as e:
        print(f"  ❌ 發生錯誤:{e}\n")

def scan_folder(root: Path):
    """走訪資料夾底下所有 .pdf"""
    for path in root.rglob("*.pdf"):
        # 跳過備份檔
        if path.name.endswith(".pdf.bak"):
            continue
        fix_pdf_title(path)

def main():
    if len(sys.argv) >= 2:
        target_dir = Path(sys.argv[1]).expanduser().resolve()
    else:
        # 沒帶參數就用目前工作目錄
        target_dir = Path.cwd()

    if not target_dir.exists() or not target_dir.is_dir():
        print(f"找不到資料夾:{target_dir}")
        sys.exit(1)

    print(f"開始處理資料夾:{target_dir}\n")
    scan_folder(target_dir)
    print("全部處理完成 🎉")

if __name__ == "__main__":
    main()
標籤
# PDF Metadata# pypdf# Python# 數字動畫
分享
在 Facebook 分享 在 X (Twitter) 分享 在 Line 分享 在 Threads 分享
上一 文章 使用純 JavaScript 實作語言切換下拉選單的開關功能
下一 文章 WordPress 單篇文章瀏覽次數計數器實作

相關文章

WordPress 會員中心新增追蹤文章清單功能實作

  • 2025-12-14

使用 PHP 與 DOMDocument 自動產生 WordPress 文章預覽內容

  • 2025-12-13

利用短碼控制內容顯示:結合 MemberPress 權限判斷的實作範例

  • 2025-12-12
© 2025 PigLife.tw 版權所有。