python PDF | 60歳を迎えて、思うこと。

60歳を迎えて、思うこと。

いつの間にか、「60」という年月が経ちました。
残り少ないか多いか?わかりませんが。
じじぃ~の「ひとりごと」を細々と続けられれば。。。

python PDF
#ファイル整理

#python

#PDF


ファイル整理

がんばったり
なまけたり

でんでん虫 の 歩みである;;

さて

PDF ふぁいる!

なんちゃら.pdf

だぶるくりっく!
開けね~~~

なんでやねん!

【Gemini】様に

開けない pdfファイルの 一括処理
すくりぷと を つくって いただいた


# ==== 【Gemini】様

import os
import shutil
from pypdf import PdfReader

# ==========================================
# 設定項目
# ==========================================
TARGET_DIR = r"E:\__WORK"
NG_DEST_DIR = r"E:\__WORK-PDF-NG"
LOG_FILE_PATH = os.path.join(NG_DEST_DIR, "pdf_check_log.txt") # ログの保存先

def check_pdf_status(file_path):
    """
    PDFファイルの状態をチェックする関数
    戻り値: (判定結果True/False, 理由のメッセージ)
    """
    try:
        # 【ステップ1】マジックナンバーのチェック(偽装対策)
        with open(file_path, "rb") as f:
            header = f.read(4)
            if header != b"%PDF":
                # 実際のヘッダーを文字として読める形式にしてログに残す
                readable_header = header.hex()
                return False, f"【拡張子偽装】ファイル先頭が %PDF ではありません(データ: 0x{readable_header})"
        
        # 【ステップ2】pypdfによる構造チェック(破損対策)
        reader = PdfReader(file_path)
        _ = len(reader.pages) # ページ数を読めるかテスト
        
        return True, "正常"
        
    except Exception as e:
        # 発生したエラーメッセージ(英語)をそのまま理由として返す
        error_msg = str(e) if str(e) else "ファイルが完全に壊れているか、空っぽです。"
        return False, f"【ファイル破損】PDF構造エラー(詳細: {error_msg})"

def main():
    if not os.path.exists(NG_DEST_DIR):
        os.makedirs(NG_DEST_DIR)

    success_count = 0
    ng_count = 0
    
    # ログ記録用のリスト
    log_lines = ["=== PDF判定 NG理由ログ ===", ""]

    print("PDFのチェック(原因ログ記録モード)を開始します...")
    print("-" * 50)

    for root, dirs, files in os.walk(TARGET_DIR):
        if os.path.commonpath([root, NG_DEST_DIR]) == os.path.normpath(NG_DEST_DIR):
            continue

        for file in files:
            if not file.lower().endswith(".pdf"):
                continue
            
            # ログファイル自体を検索しないようにスキップ
            if file == "pdf_check_log.txt":
                continue
                
            file_path = os.path.join(root, file)
            
            # チェック実行(判定結果と理由を取得)
            is_valid, reason = check_pdf_status(file_path)
            
            if is_valid:
                success_count += 1
            else:
                ng_count += 1
                dest_path = os.path.join(NG_DEST_DIR, file)
                
                if os.path.exists(dest_path):
                    base, ext = os.path.splitext(file)
                    dest_path = os.path.join(NG_DEST_DIR, f"{base}_duplicated{ext}")
                
                # ログに記録する文章を作成
                log_entry = f"【ファイル】: {file_path}\n【理由】: {reason}\n"
                log_lines.append(log_entry)
                
                # 画面にもリアルタイムで表示
                print(f"![NG] {file}")
                print(f"  └ 理由: {reason}")
                
                try:
                    shutil.move(file_path, dest_path)
                except Exception as e:
                    print(f"【エラー】移動失敗: {e}")

    # 最後にログファイルにまとめて書き出し
    log_lines.append("-" * 50)
    log_lines.append(f"正常: {success_count} 件 / 異常: {ng_count} 件")
    
    with open(LOG_FILE_PATH, "w", encoding="utf-8") as log_file:
        log_file.write("\n".join(log_lines))

    print("-" * 50)
    print("チェックが完了しました。")
    print(f"正常(そのまま): {success_count} 件")
    print(f"異常(NGへ移動): {ng_count} 件")
    print(f"NGの原因ログを保存しました: {LOG_FILE_PATH}")

if __name__ == "__main__":
    main()

# ==============================