PyPDF2を使ってPythonでPDFに付与されたパスワード(AES暗号)を解除する

当サイトではアフィリエイト広告を利用しています

先日povo2.0へ携帯回線を切り替えたのですが、明細としてメールで送られてくるPDFが暗号化されていました。

毎回パスワードを入力して確認するのは手間なので、ローカルでパスワードを解除して管理することにしました。

利用したライブラリはPyPDF2とそのAES暗号化対応プラグインになります。

ソフトウェア環境

  • python: 3.11.3
  • pypdf2: 3.0.1
  • pycryptodome: 3.17

ライブラリのインストール

pipでインストールを行います。

pip install PyPDF2 PyPDF2[crypto]

conda installだとPyPDF2はインストールできるのですが、AES暗号に対応したPyPDF2[crypto]がインストールできなかったのでpip経由でインストールしています。

PyPDF2公式ドキュメントにパスワード付与・解除について記載がありますので、少し使いやすいように修正しながら記述しています。

パスワード解除スクリプト

単独PDFファイルのパスワードを解除するスクリプトは以下のようになります。

暗号化フラグがOnの場合のみ解除するようにしています。

また、パスワードや入力・出力ファイルは定数として与えています。

from PyPDF2 import PdfReader, PdfWriter

FNAME_IN = "2023_04.pdf"
FNAME_OUT = "2023_04_out.pdf"
PASSWORD = "xxxxxxxxx"

def remove_pass(fname_in, fname_out, password):
    reader = PdfReader(fname_in)

    if reader.is_encrypted:
        print(f"{fname_in}: is encrypted...", end="")
        reader.decrypt(password)

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

        with open(fname_out, "wb") as f:
            writer.write(f)
        print("decrypted!")
    else:
        print(f"{fname_in} is not encrypted")

if __name__ == "__main__":
    remove_pass(FNAME_IN, FNAME_OUT, PASSWORD)

Globで再帰的にPDFのパスワード解除を行うスクリプト

上記にglobを追加して再帰的にPDFの暗号化をチェックして、暗号化されていれば復号して上書きするスクリプトが以下になります。

import glob
from PyPDF2 import PdfReader, PdfWriter

PASSWORD = "xxxxxxxxx"
GLOB_PATTERN = "**/*.pdf"

def remove_pass(fname_in, fname_out, password):
    reader = PdfReader(fname_in)

    if reader.is_encrypted:
        print(f"{fname_in}: is encrypted...", end="")
        reader.decrypt(password)

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

        with open(fname_out, "wb") as f:
            writer.write(f)
        print("decrypted!")
    else:
        print(f"{fname_in} is not encrypted")

def remove_recur(glob_pattern, password):
    for p in glob.glob(glob_pattern, recursive=True):
        remove_pass(p, p, password)

if __name__ == "__main__":
    remove_recur(GLOB_PATTERN, PASSWORD)

まとめ

  • PyPDF2を使ってPDFのパスワード解除を行った