PythonでPDFを操作する方法

PythonでPDFを操作する方法

Portable Document FormatまたはPDFは、オペレーティングシステム間でドキュメントを確実に表示および交換するために使用できるファイル形式です。 PDFは元々Adobeによって発明されましたが、現在は国際標準化機構(ISO)によって維持されているopen standardです。 PyPDF2パッケージを使用すると、Pythonで既存のPDFを操作できます。

PyPDF2は、さまざまな種類のPDF操作に使用できるpure-Pythonパッケージです。

この記事の終わりまでに、次の方法を理解できるようになります。

  • PythonでPDFからドキュメント情報を抽出する

  • ページを回転させる

  • PDFを結合する

  • PDFを分割する

  • 透かしを追加

  • PDFを暗号化する

始めましょう!

Free Bonus:Click here to get access to a chapter from Python Tricks: The Bookは、Pythonのベストプラクティスと、より美しい+ Pythonicコードをすぐに適用できる簡単な例を示しています。

pyPdfPyPDF2、およびPyPDF4の履歴

元のpyPdfパッケージは、2005年にリリースされました。 pyPdfの最後の公式リリースは2010年でした。 約1年が経過した後、Phasitという会社がPyPDF2というpyPdfのフォークを後援しました。 コードはオリジナルと後方互換性があるように書かれており、最後のリリースは2016年で、数年間非常によく機能しました。

PyPDF3と呼ばれるパッケージの短い一連のリリースがあり、その後、プロジェクトの名前がPyPDF4に変更されました。 これらのプロジェクトはすべてほぼ同じことを行いますが、pyPdfとPyPDF2 +の最大の違いは、後者のバージョンでPython3のサポートが追加されたことです。 元のpyPdf for Python 3の別のPython 3フォークがありますが、それは何年もの間維持されていません。

PyPDF2は最近放棄されましたが、新しいPyPDF4PyPDF2との完全な下位互換性がありません。 この記事のほとんどの例はPyPDF4で完全に正常に機能しますが、機能しないものもあります。そのため、この記事ではPyPDF4について詳しく説明していません。 PyPDF2のインポートをPyPDF4と交換して、どのように機能するかを確認してください。

pdfrw:代替

Patrick Maupinは、PyPDF2と同じことの多くを実行できるpdfrwというパッケージを作成しました。 暗号化を除いて、この記事でPyPDF2に対して行う方法を学習するのと同じ種類のタスクすべてに、pdfrwを使用できます。

pdfrwの最大の違いは、ReportLabパッケージと統合されているため、既存のPDFを取得し、既存のPDFの一部またはすべてを使用してReportLabで新しいPDFを作成できることです。

インストール

PyPDF2のインストールは、通常のPythonの代わりにAnacondaを使用している場合は、pipまたはcondaを使用して実行できます。

pipとともにPyPDF2をインストールする方法は次のとおりです。

$ pip install pypdf2

PyPDF2には依存関係がないため、インストールは非常に高速です。 パッケージをダウンロードする時間は、インストールする時間と同じくらいかかります。

次に、PDFから情報を抽出する方法を学びましょう。

PythonでPDFからドキュメント情報を抽出する方法

PyPDF2を使用して、PDFからメタデータと一部のテキストを抽出できます。 これは、既存のPDFファイルで特定の種類の自動化を行う場合に役立ちます。

以下は、抽出可能な現在のタイプのデータです。

  • 著者

  • クリエイター

  • プロデューサー

  • 件名

  • タイトル

  • ページ数

この例で使用するPDFを見つける必要があります。 マシンで手元にあるPDFを使用できます。 簡単にするために、Leanpubに移動して、この演習用に自分の本の1つのサンプルを入手しました。 ダウンロードするサンプルはreportlab-sample.pdfと呼ばれます。

そのPDFを使用してコードを記述し、これらの属性にアクセスする方法を学びましょう。

# extract_doc_info.py

from PyPDF2 import PdfFileReader

def extract_information(pdf_path):
    with open(pdf_path, 'rb') as f:
        pdf = PdfFileReader(f)
        information = pdf.getDocumentInfo()
        number_of_pages = pdf.getNumPages()

    txt = f"""
    Information about {pdf_path}:

    Author: {information.author}
    Creator: {information.creator}
    Producer: {information.producer}
    Subject: {information.subject}
    Title: {information.title}
    Number of pages: {number_of_pages}
    """

    print(txt)
    return information

if __name__ == '__main__':
    path = 'reportlab-sample.pdf'
    extract_information(path)

ここでは、PyPDF2パッケージからPdfFileReaderをインポートします。 PdfFileReaderは、PDFファイルを操作するためのいくつかのメソッドを持つクラスです。 この例では、.getDocumentInfo()を呼び出します。これにより、DocumentInformationのインスタンスが返されます。 これには、興味のある情報のほとんどが含まれています。 また、リーダーオブジェクトで.getNumPages()を呼び出します。これにより、ドキュメントのページ数が返されます。

Note:最後のコードブロックは、文字列のフォーマットにPython3の新しいf文字列を使用します。 詳細については、Python 3’s f-Strings: An Improved String Formatting Syntax (Guide)をご覧ください。

information変数には、ドキュメントから必要な残りのメタデータを取得するために使用できるいくつかのインスタンス属性があります。 その情報を印刷し、将来の使用に備えてそれを返します。

PyPDF2には.extractText()があり、これはページオブジェクト(この例には示されていません)で使用できますが、あまりうまく機能しません。 一部のPDFはテキストを返し、一部のPDFは空の文字列を返します。 PDFからテキストを抽出する場合は、代わりにPDFMinerプロジェクトを確認する必要があります。 PDFMinerははるかに堅牢で、PDFからテキストを抽出するために特別に設計されました。

これで、PDFページの回転について学ぶ準備ができました。

ページを回転させる方法

場合によっては、ポートレートモードではなくlandscape modeのページを含むPDFを受け取ることがあります。 または、逆さまになっている可能性もあります。 これは、誰かがドキュメントをスキャンしてPDFまたは電子メールに送信するときに発生する可能性があります。 ドキュメントを印刷して紙版を読むか、Pythonの力を使用して問題のあるページを回転させることができます。

この例では、実際のP​​ythonarticleを選択して、PDFに出力できます。

その記事のいくつかのページをPyPDF2で回転させる方法を学びましょう。

# rotate_pages.py

from PyPDF2 import PdfFileReader, PdfFileWriter

def rotate_pages(pdf_path):
    pdf_writer = PdfFileWriter()
    pdf_reader = PdfFileReader(path)
    # Rotate page 90 degrees to the right
    page_1 = pdf_reader.getPage(0).rotateClockwise(90)
    pdf_writer.addPage(page_1)
    # Rotate page 90 degrees to the left
    page_2 = pdf_reader.getPage(1).rotateCounterClockwise(90)
    pdf_writer.addPage(page_2)
    # Add a page in normal orientation
    pdf_writer.addPage(pdf_reader.getPage(2))

    with open('rotate_pages.pdf', 'wb') as fh:
        pdf_writer.write(fh)

if __name__ == '__main__':
    path = 'Jupyter_Notebook_An_Introduction.pdf'
    rotate_pages(path)

この例では、新しいPDFを書き出す必要があるため、PdfFileReaderに加えてPdfFileWriterをインポートする必要があります。 rotate_pages()は、変更するPDFへのパスを受け取ります。 その関数内で、pdf_writerという名前のライターオブジェクトとpdf_readerというリーダーオブジェクトを作成する必要があります。

次に、.GetPage()を使用して目的のページを取得できます。 ここでは、最初のページであるページゼロを取得します。 次に、ページオブジェクトの.rotateClockwise()メソッドを呼び出し、90度で渡します。 次に、2ページ目では、.rotateCounterClockwise()を呼び出して、90度も渡します。

Note:PyPDF2パッケージでは、ページを90度ずつ回転させることしかできません。 それ以外の場合は、AssertionErrorを受け取ります。

ローテーションメソッドを呼び出すたびに、.addPage()を呼び出します。 これにより、ページの回転バージョンがライターオブジェクトに追加されます。 ライターオブジェクトに追加する最後のページは、ページ3で、回転は行われていません。

最後に、.write()を使用して新しいPDFを書き出します。 パラメータとしてfile-like objectを取ります。 この新しいPDFには3つのページが含まれます。 最初の2つは互いに反対方向に回転し、横向きになりますが、3番目のページは通常のページです。

それでは、複数のPDFを1つにマージする方法を学びましょう。

PDFを結合する方法

2つ以上のPDFを取得し、それらを1つのPDFにマージする場合が多くあります。 たとえば、多くの種類のレポートに進む必要がある標準のカバーページがあるとします。 Pythonを使用して、そのようなことを行うことができます。

この例では、PDFを開き、ページを個別のPDFとして印刷できます。 その後、別のページを使用して再度実行します。 これにより、例として使用するための入力がいくつか得られます。

先に進んで、PDFを結合するために使用できるコードを作成しましょう。

# pdf_merging.py

from PyPDF2 import PdfFileReader, PdfFileWriter

def merge_pdfs(paths, output):
    pdf_writer = PdfFileWriter()

    for path in paths:
        pdf_reader = PdfFileReader(path)
        for page in range(pdf_reader.getNumPages()):
            # Add each page to the writer object
            pdf_writer.addPage(pdf_reader.getPage(page))

    # Write out the merged PDF
    with open(output, 'wb') as out:
        pdf_writer.write(out)

if __name__ == '__main__':
    paths = ['document1.pdf', 'document2.pdf']
    merge_pdfs(paths, output='merged.pdf')

マージするPDFのリストがある場合は、merge_pdfs()を使用できます。 また、結果を保存する場所を知る必要があるため、この関数は入力パスと出力パスのリストを取得します。

次に、入力をループ処理し、入力ごとにPDFリーダーオブジェクトを作成します。 次に、PDFファイル内のすべてのページを繰り返し処理し、.addPage()を使用してそれらの各ページをそれ自体に追加します。

リスト内のすべてのPDFのすべてのページを繰り返し処理し終わったら、最後に結果を書き出します。

私が指摘したい項目の1つは、各PDFのすべてのページをマージしたくない場合に、追加するページの範囲を追加することにより、このスクリプトを少し強化できることです。 チャレンジが必要な場合は、Pythonのargparseモジュールを使用してこの関数のコマンドラインインターフェースを作成することもできます。

マージの反対を行う方法を見つけましょう!

PDFを分割する方法

PDFを複数のPDFに分割する必要がある場合があります。 これは、スキャンされたコンテンツを多く含むPDFに特に当てはまりますが、PDFを分割したい理由はたくさんあります。

PyPDF2を使用してPDFを複数のファイルに分割する方法は次のとおりです。

# pdf_splitting.py

from PyPDF2 import PdfFileReader, PdfFileWriter

def split(path, name_of_split):
    pdf = PdfFileReader(path)
    for page in range(pdf.getNumPages()):
        pdf_writer = PdfFileWriter()
        pdf_writer.addPage(pdf.getPage(page))

        output = f'{name_of_split}{page}.pdf'
        with open(output, 'wb') as output_pdf:
            pdf_writer.write(output_pdf)

if __name__ == '__main__':
    path = 'Jupyter_Notebook_An_Introduction.pdf'
    split(path, 'jupyter_page')

この例では、もう一度PDFリーダーオブジェクトを作成し、そのページをループします。 PDFの各ページに対して、新しいPDFライターインスタンスを作成し、1つのページを追加します。 次に、そのページを一意の名前のファイルに書き込みます。 スクリプトの実行が終了したら、元のPDFの各ページを個別のPDFに分割する必要があります。

ここで、PDFに透かしを追加する方法を少し見てみましょう。

透かしを追加する方法

透かしは、印刷文書やデジタル文書の画像またはパターンを識別します。 一部の透かしは、特殊な照明条件でのみ見ることができます。 透かしが重要な理由は、画像やPDFなどの知的財産を保護できるためです。 透かしの別の用語はオーバーレイです。

PythonとPyPDF2を使用して、ドキュメントに透かしを入れることができます。 透かし画像またはテキストのみを含むPDFが必要です。

透かしを追加する方法を学びましょう。

# pdf_watermarker.py

from PyPDF2 import PdfFileWriter, PdfFileReader

def create_watermark(input_pdf, output, watermark):
    watermark_obj = PdfFileReader(watermark)
    watermark_page = watermark_obj.getPage(0)

    pdf_reader = PdfFileReader(input_pdf)
    pdf_writer = PdfFileWriter()

    # Watermark all the pages
    for page in range(pdf_reader.getNumPages()):
        page = pdf_reader.getPage(page)
        page.mergePage(watermark_page)
        pdf_writer.addPage(page)

    with open(output, 'wb') as out:
        pdf_writer.write(out)

if __name__ == '__main__':
    create_watermark(
        input_pdf='Jupyter_Notebook_An_Introduction.pdf',
        output='watermarked_notebook.pdf',
        watermark='watermark.pdf')

create_watermark()は、次の3つの引数を受け入れます。

  1. input_pdf:透かしを入れるPDFファイルパス

  2. output:透かし入りバージョンのPDFを保存するパス

  3. watermark:透かし画像またはテキストを含むPDF

このコードでは、ウォーターマークPDFを開き、ドキュメントの最初のページだけを取得します。これは、ウォーターマークが存在する場所です。 次に、透かし入りPDFを書き出すためのinput_pdfオブジェクトと汎用pdf_writerオブジェクトを使用してPDFリーダーオブジェクトを作成します。

次のステップは、input_pdfのページを反復処理することです。 これが魔法が起こるところです。 .mergePage()を呼び出して、watermark_pageを渡す必要があります。 これを行うと、現在のページの上にwatermark_pageがオーバーレイされます。 次に、新しくマージされたページをpdf_writerオブジェクトに追加します。

最後に、新しく透かしを入れたPDFをディスクに書き込み、完了です!

学習する最後のトピックは、PyPDF2が暗号化を処理する方法です。

PDFを暗号化する方法

PyPDF2は現在、既存のPDFへのユーザーパスワードと所有者パスワードの追加のみをサポートしています。 PDFの土地では、所有者パスワードにより、基本的にPDFに対する管理者権限が与えられ、ドキュメントに権限を設定できます。 一方、ユーザーパスワードでは、ドキュメントを開くことができます。

私の知る限り、PyPDF2では、所有者のパスワードを設定できますが、実際にはドキュメントに権限を設定することはできません。

とにかく、これはパスワードを追加する方法です。これにより、本質的にPDFも暗号化されます。

# pdf_encrypt.py

from PyPDF2 import PdfFileWriter, PdfFileReader

def add_encryption(input_pdf, output_pdf, password):
    pdf_writer = PdfFileWriter()
    pdf_reader = PdfFileReader(input_pdf)

    for page in range(pdf_reader.getNumPages()):
        pdf_writer.addPage(pdf_reader.getPage(page))

    pdf_writer.encrypt(user_pwd=password, owner_pwd=None,
                       use_128bit=True)

    with open(output_pdf, 'wb') as fh:
        pdf_writer.write(fh)

if __name__ == '__main__':
    add_encryption(input_pdf='reportlab-sample.pdf',
                   output_pdf='reportlab-encrypted.pdf',
                   password='twofish')

add_encryption()は、入力および出力PDFパスと、PDFに追加するパスワードを受け取ります。 次に、以前と同様にPDFライターとリーダーオブジェクトを開きます。 入力PDF全体を暗号化する必要があるため、すべてのページをループしてライターに追加する必要があります。

最後のステップは、.encrypt()を呼び出すことです。これは、ユーザーパスワード、所有者パスワード、および128ビット暗号化を追加する必要があるかどうかを取得します。 デフォルトでは、128ビット暗号化が有効になっています。 Falseに設定すると、代わりに40ビット暗号化が適用されます。

Note: PDF暗号化は、RC4またはAES(Advanced Encryption Standard)のいずれかを使用して、pdflib.comに従ってPDFを暗号化します。

PDFを暗号化したからといって、必ずしも安全であるとは限りません。 PDFからパスワードを削除するツールがあります。 詳細を知りたい場合は、カーネギーメロン大学に興味深いpaper on the topicがあります。

結論

PyPDF2パッケージは非常に便利で、通常はかなり高速です。 PyPDF2を使用して大規模なジョブを自動化し、その機能を活用してジョブをより適切に実行できます。

このチュートリアルでは、次のことを行う方法を学びました。

  • PDFからメタデータを抽出する

  • ページを回転させる

  • PDFの結合と分割

  • 透かしを追加

  • 暗号化を追加

また、新しいPyPDF4パッケージは、まもなくPyPDF2に置き換わる可能性があるため、注意してください。 また、pdfrwをチェックアウトすることもできます。これは、PyPDF2が実行できるのと同じことの多くを実行できます。

参考文献

PythonでPDFを操作する方法について詳しく知りたい場合は、次のリソースで詳細を確認してください。