※本記事にはPR(アフィリエイト広告)が含まれています。
こんにちは!「Python業務効率化」連載も第4回を迎えました。これまでの講座では、PDFファイルの読み込みやテキスト抽出、結合・分割といった基本操作を学んできました。今回のテーマは「大量のPDFファイルを一括リネーム・仕分けするバッチ処理」です。
経理書類、契約書、請求書など、業務では毎日のように大量のPDFファイルが発生します。それらを手作業でフォルダ分けしたり、ファイル名を統一したりするのは非常に骨が折れる作業です。本記事では、Pythonを使ってこの作業を自動化する方法を、初心者の方にもわかりやすく解説していきます。
なぜバッチ処理で業務効率化できるのか
「バッチ処理」とは、複数のファイルに対してまとめて同じ処理を実行することを指します。例えば以下のような作業は、バッチ処理の典型例です。
- フォルダ内の全PDFファイルに、日付や連番を付けてリネームする
- ファイル名や中身の内容に応じて、適切なフォルダに自動で振り分ける
- 処理済みファイルと未処理ファイルを分離する
これらを手動で行うと、100件のファイルがあれば100回同じ作業を繰り返すことになります。Pythonでスクリプト化しておけば、数秒〜数十秒で完了し、しかも人為的なミスも防げます。
今回使用する主なライブラリ
今回のバッチ処理では、以下の標準ライブラリを使用します。外部ライブラリのインストールは不要なので、気軽に試すことができます。
pathlib:ファイルパスの操作shutil:ファイルの移動・コピーre:ファイル名のパターンマッチングdatetime:日付情報の取得
PDFファイルを一括リネームする
まずは、フォルダ内のPDFファイルに対して、わかりやすい命名規則で一括リネームする方法を見ていきましょう。
ファイル名のルールを決める
リネームを行う前に、どのような命名規則にするかを決めておくことが重要です。今回は「処理日_連番.pdf」という形式(例:20240615_001.pdf)にリネームしてみます。
実装コード
from pathlib import Path
from datetime import datetime
def rename_pdfs(folder_path):
"""
指定フォルダ内のPDFファイルを
「処理日_連番.pdf」の形式で一括リネームする
"""
folder = Path(folder_path)
today = datetime.now().strftime("%Y%m%d")
# フォルダ内のPDFファイルを取得(更新日時順にソート)
pdf_files = sorted(folder.glob("*.pdf"), key=lambda f: f.stat().st_mtime)
for index, pdf_file in enumerate(pdf_files, start=1):
new_name = f"{today}_{index:03d}.pdf"
new_path = folder / new_name
# 同名ファイルが存在する場合はスキップ
if new_path.exists():
print(f"スキップ: {new_name} は既に存在します")
continue
pdf_file.rename(new_path)
print(f"リネーム完了: {pdf_file.name} → {new_name}")
# 実行例
rename_pdfs("./target_pdfs")
このスクリプトでは、連番を3桁のゼロ埋め(001, 002…)にすることで、ファイル一覧が綺麗に並ぶように工夫しています。実務では「請求書_20240615_001.pdf」のように、文書の種類を表す文字列を追加するとさらに管理しやすくなります。
条件に応じてPDFファイルを自動仕分けする
次に、ファイル名やファイルサイズなどの条件に応じて、PDFファイルを自動でフォルダ分けする処理を実装します。
フォルダ分類のロジックを考える
今回は、ファイル名に含まれるキーワードをもとに「請求書」「契約書」「その他」の3つのフォルダに振り分ける例を紹介します。実務では取引先名や部署名での分類にも応用できます。
実装コード
import shutil
from pathlib import Path
def sort_pdfs_by_keyword(source_folder, destination_folder):
"""
ファイル名のキーワードに基づいてPDFを仕分ける
"""
source = Path(source_folder)
destination = Path(destination_folder)
# 分類ルールを定義(キーワード:フォルダ名)
rules = {
"請求書": "invoices",
"契約書": "contracts",
}
# 出力先フォルダをあらかじめ作成
for folder_name in list(rules.values()) + ["others"]:
(destination / folder_name).mkdir(parents=True, exist_ok=True)
for pdf_file in source.glob("*.pdf"):
matched = False
for keyword, folder_name in rules.items():
if keyword in pdf_file.name:
shutil.move(str(pdf_file), str(destination / folder_name / pdf_file.name))
print(f"仕分け完了: {pdf_file.name} → {folder_name}")
matched = True
break
# どのキーワードにも一致しない場合は「others」へ
if not matched:
shutil.move(str(pdf_file), str(destination / "others" / pdf_file.name))
print(f"仕分け完了: {pdf_file.name} → others")
# 実行例
sort_pdfs_by_keyword("./target_pdfs", "./sorted_pdfs")
このように、辞書(dict)で分類ルールを管理しておくと、キーワードの追加や変更が簡単に行えます。業務内容に合わせてルールをカスタマイズしてみてください。
安全にバッチ処理を実行するための工夫
大量のファイルを一括操作するバッチ処理は便利な反面、一度実行すると元に戻すのが難しいというリスクもあります。ここでは、安全に運用するためのポイントを紹介します。
実行前に必ずバックアップを取る
リネームや移動処理を行う前に、対象フォルダをコピーしてバックアップを作成しておきましょう。shutil.copytree()を使えば、フォルダごと簡単にバックアップできます。
import shutil
# バックアップを作成
shutil.copytree("./target_pdfs", "./target_pdfs_backup")
ドライラン(お試し実行)機能を入れる
いきなり本番実行するのではなく、「実際には処理をせず、どう変更されるかだけを表示する」ドライラン機能を入れておくと安心です。
def rename_pdfs(folder_path, dry_run=True):
folder = Path(folder_path)
pdf_files = sorted(folder.glob("*.pdf"))
for index, pdf_file in enumerate(pdf_files, start=1):
new_name = f"file_{index:03d}.pdf"
if dry_run:
print(f"[確認] {pdf_file.name} → {new_name}")
else:
pdf_file.rename(folder / new_name)
print(f"[実行] {pdf_file.name} → {new_name}")
# まずはドライランで確認
rename_pdfs("./target_pdfs", dry_run=True)
# 問題なければ本番実行
# rename_pdfs("./target_pdfs", dry_run=False)
この一手間を入れておくだけで、「意図しないファイルが上書きされてしまった」「大事なファイルが消えてしまった」といったトラブルを未然に防ぐことができます。
まとめ
今回は、大量のPDFファイルを一括リネーム・仕分けするバッチ処理について解説しました。ポイントをおさらいしましょう。
pathlibを使えば、ファイルパスの操作が直感的に書ける- 命名規則や分類ルールを事前に決めておくことで、スクリプトがシンプルになる
shutilでファイルの移動・コピーが簡単に行える- バックアップとドライラン機能で、安全にバッチ処理を実行できる
一度スクリプトを作成してしまえば、毎回の定型作業が数秒で完了するようになります。最初は小さなフォルダで試しながら、少しずつ自分の業務に合わせてカスタマイズしていくのがおすすめです。
次回、第5回では「PDFからのテキスト抽出結果をExcelに自動集計する方法」について解説する予定です。お楽しみに!
Photo by Danial Igdery on Unsplash

