環境
Windows 10 (Mac・Linuxについては詳しくないのでサポートできません)
python 3.7
目次
- 動機と概要
- ディレクトリ構造とファイル内容
- 依存パッケージ
- 解説
- 実際の使用方法
- Tips
- 注意事項
- まとめ
- 参考文献
動機と概要
コロナウイルスの影響で、オンライン授業が大学では多数行われていると思います。
その為の授業資料を、学内のサービスを使用して配布されることがほとんどだと思いますが、たまにパスワードをかけられる先生がいます。そりゃ再配布しちゃうのはまずいし、履修生以外の閲覧をはじきたいのでしょうが、、こちらとしては開くたびにパスワードを入力するのはかなりめんどくさいわけです。
そこでパスワード解除したPDFを作成してしまおうというわけです。
「PDF パスワード解除」などと検索すれば色々出てきますが、今回はPDFをドラッグアンドドロップだけで解除します。
というわけで二段階のプロセスを踏みます。
- batファイルとpythonファイルを連携させる
- PDFのパスワードを(既知の場合)解除する
python単体でも実現は可能ですが、ドラッグアンドドロップだけでパスワード解除するにはbatが必要かなぁと思います。
というわけでpython駆使してPDFのパスワードを解除しましょう。
ディレクトリ構造とファイル内容
最初にディレクトリ構造と実装したファイル内容を示します。
classフォルダは授業の資料を置いているフォルダと解釈してください。
root/
├ main.py
└ decoder.bat
class/
├ password.txt
└ target.pdf
※または
class/
├ password.txt
└ 0605/
└ target.pdf
のようになっていても大丈夫です。
import sys, pathlib
from pikepdf import Pdf
def get_password(folder):
passfile = None
found : bool = False
# まず同一フォルダ内を探索する
for f in folder.glob("*"):
if "password" == f.stem:
passfile = f
found = True
# 同一階層になかった場合は更にもう一つ上の階層を探索
if not found:
folder = folder.parent
for f in folder.glob("*"):
if "password" == f.stem:
passfile = f
# 一つ上の階層にもpasswordファイルがない場合
if not found:
return None
# ファイルからパスワードを取り出す
with open(passfile, mode="r", encoding="utf-8") as f:
password = f.read()
return password
def main():
# batから起動時
try:
path = sys.argv[1]
# pyファイル単体で動かすとき
except:
print("input target path")
path = input()
path = pathlib.Path(path)
# PDFファイル以外をリジェクト
if path.suffix != ".pdf":
print("Only PDF file accept.")
sys.exit()
password = get_password(folder=path.parent)
# passwordファイルがない場合
if password == None:
print("No password file. input password = ", end="")
password = input()
try:
pdf = Pdf.open(path, password=password)
except: # passwordが間違っている場合
print("failed to open PDF. check password.")
sys.exit()
pdf_unlock = Pdf.new()
pdf_unlock.pages.extend(pdf.pages)
# 元のPDFと同階層に保存
newname = f"{path.parent / path.stem}-unlocked.pdf"
pdf_unlock.save(newname)
if __name__ == '__main__':
main()
@echo off
rem classの部分をclassフォルダのフルパスで書き換えてください
cd "class"
"main.py" %*
依存パッケージ
pipできます。ラクラク。
pip install pikepdf
pikepdf というライブラリを使用して、PDFのパスワードを解除します。
参考文献[1]により存在をしりました。こちらでもサンプルプログラムが公開されていますから、参考にしてください。
解説
batファイルとpythonの連携について
batファイルに対して画像ファイル等のファイルをドラッグアンドドロップして開くと、コマンドプロンプトでは
C:\Users\user> decoder.bat (ファイルのフルパス)
のようになります。この引数はbatファイル内では %* で受け取ることができます。
(本当は%0の方がいいですね・・)(細かいことは参考文献[2])
この引数をそのままpythonへと渡します。
pythonではコマンドライン引数を sys で受け取ることができます。
参考文献[3]に最低限のことが書かれています。
というわけで、sys.argv[1]に今回batファイルから渡された引数(ファイルのパス)がはいっています。
PDFのパスワードを解除する
基本的に以下のステップです。変数名は全てmain.pyと同じです
- パスワードを使ってPDFファイルを開く
pdf = Pdf.open(path, password=password)
- 新しいPDFファイルを用意する
pdf_unlock = Pdf.new()
- 新しいPDFに、予め開いておいたPDFをコピーする
pdf_unlock.pages.extend(pdf.pages)
- 新しいPDFを保存する
pdf_unlock.save(newname)
実際に使用してみる
- 1. パスワードを準備します。
-
ディレクトリ構造の図のpassword.txtには、target.pdfのパスワードを書き込んでおきます。
この時注意点として、改行してはいけません。
大体の先生のかけるパスワードって毎回同じなので、パスワードファイルを準備しておく仕組みを採用しました。
用意しなくてもコマンドプロンプトに打ち込めるので、毎回パスワードが違っていたらpassword.txtは作らずに実行時に打ち込みます。 - 2. ショートカット作成
- decoder.batのショートカットをデスクトップなりに置くとよいでしょう。デスクトップから実行できた方が便利そうなので。別に必須ではありません。
- 3. 実行
-
2で作成したショートカットに、PDFファイルをドラッグアンドドロップします。するとコマンドプロンプトが(一瞬)立ち上がり、パスワード解除されたPDFファイルが元々のファイルと同じ場所に保存されています。
パスワードファイルを作っていない場合は、コマンドプロンプトで入力を求められます。入力してください。
Tips
pythonファイル単体での動作
main.pyだけでも動作します。その場合はPDFの存在する(絶対)パスの入力を求められます。
この時にPDFファイルをコマンドプロンプトにドラッグアンドドロップしても動きます。
password.txtについて
以下のように二つ用意した場合は、PDFファイルに近い方が優先されます。
class/
├ password.txt
└ 0605/
├ password.txt
└ target.pdf
日によってパスワードを変えるような先生だと、その日ごとのフォルダにpassword.txtを作るとよいかもしれませんね。
注意事項
- パスワードを解除PDFファイルを先生方に無断で再配布することは絶対にやめましょう
- パスワードを他者に教えることもやめましょう。
追記
パスワードに全角文字が入っていると動作しないっぽいです。
まとめ
- pythonって便利ですね!!!
- いいねしてくれると喜びます
参考文献
[1] 【Python】pdfファイルのパスワードを解除しよう!
[2] バッチファイル実行時に引数を渡す
[3] Python: コマンドライン引数とは?