Pay money To my Life

Spend time for myself, and you... "Knowledge was the only way to remember that your past is true"

PythonでPDFを読み込むメモ(decrypt有)

はじめに

 ネット上にはPDF化されたファイルが多いが、そのデータを読み込むには一癖必要である。帳票や授業で撮ったノートなんかを画像からPDFに変換した時だったり、オフィシャルなPDFファイルだったり。
 そんなPDFファイルからPythonで文字データを抽出するにはどうすれば良いか?というメモ

環境

  • macOS Catalina 10.15.4
  • Python==3.7.4 on Anaconda==1.7.2 (conda==4.8.3)
  • pip==19.2.3
  • PyPDF2==1.26.0
  • pikepdf==1.13.0

参考URL

なお、参考にしたURLはこちらに先に示しておく。

対象としているPDFファイル

本記事で対象としているPDFファイルは、

  • 英語/数字で記述
  • ロックの有無(decrypted/encrypted)は問わない

である。日本語のPDFに関しては、本記事では試していないので、読者らで試してみて欲しい(なんなら所感をコメントに残してほしいです

PythonにおけるPDF reader

こちらの記事に纏まっているので、詳細(詳細というレベルで記述されている記事ではないが)を知りたければそちらを。PythonでPDFを読み込むために使用できるpackageは、以下のようなものがある。

Package 対象 install command
PyPDF2 英語 pip install PyPDF2
pdfminer.six 日本語 pip install pdfminer.six
Apache Tika 日本語 pip install tika
Tesseract OCR 画像データのPDFや帳票PDF pip install pyocr

今回私が使用するのは、英語を対象としているためPyPDF2である。なお、こちらに関しては、すでにPyPDF3が開発されている(PyPDF2を開発していた人らが開発を中断してしまったが、こちらのソフトが如何せん有用だったため有志で開発が進められている(しかしそこまで活発ではないし、現状はPyPDF2で十分だろう))。

pypi.org

なお、フォントに依存して読み込めないものも存在することには留意しよう。

復号化(Decrypt)の必要性

読み込ませたいPDFファイルが、例えばネット上から拾ってきたものであったり、自分配布用に作成したものであったりすると、大抵はロックがかけられているだろう(第三者に編集させないようにするため)。その状態のものをPyPDF2で読み込ませようとすると、以下のようなエラーを吐く。

import PyPDF2
with open("hogehoge.pdf", mode='rb') as f:
    reader = PyPDF2.PdfFileReader(f)
    print(f"Number of pages: {reader.getNumPages()}")

>>> PdfReadError: File has not been decrypted

これは、「暗号化されているため復号化してくださいね」というエラーである。

PyPDF2上における復号化

もし、そのPDFにかけられているロックのパスワードが既知("fugafuga")である場合、PyPDF2上でアンロックする(decrypt)ことが可能である。

import PyPDF2
with open("hogehoge.pdf", mode='rb') as f:
    reader = PyPDF2.PdfFileReader(f)
    if reader.isEncrypted:
        reader.decrypt("fugafuga")
    print(f"Number of pages: {reader.getNumPages()}")

if reader.isEncrypted:と、ロックされているかどうか(復号化の必要があるか)を確認できる。これでもロックを解除することができない場合には、

NotImplementedError: only algorithm code 1 and 2 are supported

というエラーを吐くことがある。その際には、qpdfと呼ばれるツールを使用することを推奨している記事が多数見受けられる(NotImplimentedErrorが、そもそもその復号化処理をPyPDF2で担うことができないということに起因するので、復号化処理だけqpdfに担ってもらおうという考え方)が、これもまたパスワードが既知であるPDFファイルにしか対応できない。現実問題、そんなにパスワードが分かっている、それを読み込みたいなんていう状況があるだろうか?(それなら普通にword形式でもデータを持っておけよという話

パスワードがわからない場合の復号化 (pikepdf)

 さて、ではパスワードがわからない時にはどうするか。その中でも最もスマートな解が、stackoverflowに上がっていた。簡単にいうと、pikepdfを使おうというものである。pikepdfは、以下のコマンドでインストール可能である。

pip install pikepdf

あとの使い方は簡単で、

import pikepdf

pdf = pikepdf.open("unextractable.pdf")
pdf.save("extractable.pdf")

とすれば良い。ここで保存したPDFファイルを、PyPDF2を使って読み込むだけである。

終わりに

 英語のPDFを読み込む必要が出てきたので、対応しているツール周りを簡単に調査した。1時間足らずでここまで調査・実行できるので、そこまで知見が転がっていない話ではないのでだろう。。。現場、問題は起きていないが、また問題が発生した場合にはこちらに追記していこう。



緊急事態宣言もついに終わりを迎えた、1日目の朝。
ってことで、今回はこちらの曲を聞いてお別れです。

(せーのっ)

\\\ 朝は来る ///

Amelie「朝は来る」Music Video