43号線を西へ東へ

フリーランスの備忘録、アウトプットの実験場

ファイル名のわからないPDFファイルのリネームを行う

このブログはプロモーションリンクを含むときがあります


昔から資料の整理が上手ではありません。メインPCをMacに戻してから、PCや各種のクラウドに散らばったファイルの整理を進めています。

人力でやると時間がかかる作業です。仕事に支障が出るので、なるべく省力化したいところ。いつものようににChatGPTにお願いして、Pythonのコードを書いてもらいました。

比較的負担が少なくなるように環境を整えています。

今日は、PDFの内容を見に行ってタイトルを付け直してくれるPythonコードを書いてもらいました。

仕事関係のPDF資料を大量にダウンロードすると、タイトルの日本語部分が文字化けしていたり、タイトルがページ番号になっていたりと、どのファイルか判別するのが面倒なことがあります。

その場でタイトルを付け直せばいいのですが、優先する仕事が入るとそのまま調査したものが、埋もれてしまう事の繰り返しです。

せめて名前の判別が出来るような形にはしておいて、検索に引っかかるようにせねばいけません。

ということで、PDFの内のタイトルを自動的にタイトルに付け替えてくれるようなアプリを作りました。

困るファイル達

困るファイル達の一覧です。ChatGPTとの会話をPDF化してダウンロードすると日本語部分がこのように文字化けします。

文字化け

文献やデータシートなどは、型番だったりページ番号が振られています。ダウンロードしたときは内容までわかっているのですが、2〜3日経つと何のファイルだったかすっかり忘れています。名前をつけておかないと。

数字や記号で内容がわからないファイル

ターミナルで起動するPythonコード

プロンプト画面にアレルギーがあったので大学生協で大幅値引きで売られていたMac(IIvx)を購入した文系の私ですが、なぜか最近はプロンプト画面で作業をすることが多くなっています。

コードファイルが置いてある場所に移動して、プログラムを立ち上げます。

pycloudとは私が設定したエイリアスで、iCloudドライブ上のPythonコード置き場です。

cd PDF PDF関連のコードのディレクトリ(フォルダ)に移動

Mac-pdf-renamer.pyというファイルをpy(python)で実行する流れです

選択ダイアログから、リネームしたいファイルを選ぶ

ファイルを選択した後は、自動的にファイル名のリネームと元ファイルのゴミ箱への移動を行います。

▶ クリックするとコードが展開します。

import os
import shutil
import tkinter as tk
from tkinter import filedialog
from datetime import datetime
import re
import logging
from pypdf import PdfReader
from send2trash import send2trash  # ← 追加:ゴミ箱に移動するためのライブラリ

# --- 設定項目 ---
DESTINATION_DIR = os.path.expanduser("~/Documents/RenamedPDFs")
FILENAME_FORMAT = "{date}-{title}.pdf"
# ----------------

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


def pick_pdf_file():
    """
    PDFファイル選択ダイアログ(macOS用)
    """
    root = tk.Tk()
    root.withdraw()
    return filedialog.askopenfilename(
        title="PDFファイルを選択してください",
        filetypes=[("PDF files", "*.pdf")]
    )


def extract_title_and_date(pdf_path):
    """
    PDFからタイトルと作成日を抽出
    """
    try:
        reader = PdfReader(pdf_path)
        metadata = reader.metadata

        title = metadata.title if metadata and metadata.title else None
        if not title or title.strip() == "":
            logging.info("タイトルがメタデータに無いため本文から抽出します。")
            try:
                text = reader.pages[0].extract_text()
                lines = [line.strip() for line in text.split('\n') if line.strip()]
                title = lines[0] if lines else "無題"
            except Exception as e:
                logging.warning(f"本文からの抽出に失敗: {e}")
                title = "無題"

        date_str = datetime.now().strftime('%Y%m%d')
        if metadata and metadata.creation_date:
            try:
                date_str = metadata.creation_date.strftime('%Y%m%d')
            except Exception as e:
                logging.warning(f"作成日の取得に失敗: {e}")

        return title, date_str
    except Exception as e:
        logging.error(f"PDF読み込み中にエラー: {e}")
        return None, None


def sanitize_filename(title):
    """
    ファイル名に使えない文字を置換
    """
    sanitized = re.sub(r'[\\/:*?"<>|]', '_', title)
    return sanitized[:50]


def main():
    logging.info("📂 PDFリネームツールを開始します。")

    pdf_path = pick_pdf_file()
    if not pdf_path:
        logging.info("ファイルが選択されませんでした。処理を終了します。")
        return

    logging.info(f"選択されたファイル: {os.path.basename(pdf_path)}")

    title, date_str = extract_title_and_date(pdf_path)
    if not title:
        logging.error("タイトル抽出に失敗しました。処理を中断します。")
        return

    safe_title = sanitize_filename(title)
    new_filename = FILENAME_FORMAT.format(date=date_str, title=safe_title)

    if not os.path.exists(DESTINATION_DIR):
        os.makedirs(DESTINATION_DIR)
        logging.info(f"保存先フォルダを作成しました: {DESTINATION_DIR}")

    destination_path = os.path.join(DESTINATION_DIR, new_filename)

    # 重複回避:同名ファイルがあれば末尾に番号を付加
    counter = 1
    base, ext = os.path.splitext(destination_path)
    while os.path.exists(destination_path):
        destination_path = f"{base}_{counter}{ext}"
        counter += 1

    try:
        # PDFを新しい場所にコピー
        shutil.copy2(pdf_path, destination_path)
        logging.info(f"✅ PDFを移動しました: {destination_path}")

        # 元のPDFをゴミ箱に移動(安全な削除)
        send2trash(pdf_path)
        logging.info("🗑️ 元のファイルはゴミ箱に移動しました。")

    except Exception as e:
        logging.error(f"ファイルの処理に失敗: {e}")


if __name__ == '__main__':
    main()

最後に

昔から整理整頓が苦手なので、資料の山に埋もれがちでした。PCの中をきちんと整理していこうと思う。まずはPDFから。

しかし、Macを使いはじめたのはフォルダやデスクトップのメタファーに感動したからだった。文系の私にコンピューターへの敷居を下げてくれたグラフィックインターフェイスだったが、今ではマウスを動かすのが面倒に感じるようになっている。

どんどんエイリアスを登録して、ターミナルで作業をするようになっているのだから、人生わからないものだ。