pdf PDFを処理するためのさまざまな実用的なコード:PyPDF2、PDFMiner、pdfplumber

人生のアレンジ方法がわからない場合は、必要なことをアレンジするのを手伝ってくれる人がたくさんいます。

特に次の2つのシナリオでは、PDFファイルをよく使用します。

  • さまざまなレポートやドキュメントなどの参考資料をダウンロードする

    読み取り専用情報を共有して、ソースファイルを保持しながら配布を容易にします

シーンとモジュール

したがって、PDFファイルの場合、2つの一般的な要件があります。

  1. ファイル自体の処理は、PDFページのマージ/分割、暗号化/復号化、透かしなど、ファイルのページレベルの操作に属します。

    ファイルコンテンツの処理は、テキスト、テーブルデータ、グラフの抽出などのコンテンツレベルの操作に属します。

現在、PythonがPDFを処理するために使用する3つの主要なモジュールがあります。

  • PyPDF2:モジュールは成熟しており、最後の更新は2年前であり、ページレベルの操作に適しており、テキスト抽出効果は不十分です。

    PDFMiner:テキスト抽出が得意です。現在、メインブランチはメンテナンスを停止しており、pdfminer.sixに置き換えられています。

    pdfplumber:pdfminer.sixに基づくテキストコンテンツ抽出ツールで、テーブル抽出のサポートなど、使用の障壁が低くなっています。

実際の戦闘では、要件の種類に応じてモジュールを選択できます。ページレベルの操作の場合は、PyPDF2を使用します。コンテンツの抽出が必要な場合は、最初にpdfplumberを使用します。

対応するモジュールのインストール:

  pip install pypdf2

  pip install pdfminer.six

  pip install pdfplumber



以下は、使用シナリオに応じた3つのモジュールの使用のデモンストレーションです。

PyPDF2

PyPDF2の主な機能は、次のようなページレベルで動作します。

  • PDFドキュメントの基本情報を取得する

    PDFの分割とマージ

    PDFの回転と並べ替え

    PDF透かしを追加し、透かしを削除します

    PDFの暗号化と復号化

PyPDF2のコア2クラスは、PDFファイルの読み取りおよび書き込み操作を完了するPdfFileReaderとPdfFileWriterです。

PDFドキュメントの基本情報を取得する

import pathlib
from PyPDF2 import PdfFileReader
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
with open(f_path, 'rb') as f:
    pdf = PdfFileReader(f)
    info = pdf.getDocumentInfo()
    cnt_page = pdf.getNumPages()
    is_encrypt = pdf.getIsEncrypted()
print(f'''
作者: {info.author}
创建者: {info.creator}
制作者: {info.producer}
主题: {info.subject}
标题: {info.title}
总页数: {cnt_page}
是否加密: {is_encrypt}
''')


PDFの分割とマージ

import pathlib
from PyPDF2 import PdfFileReader, PdfFileWriter
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
out_path = path.joinpath('002pdf_split_merge.pdf')
out_path_1 = path.joinpath('002pdf_split_half_front.pdf')
out_path_2 = path.joinpath('002pdf_split_half_back.pdf')
# 把文件分为两半
with open(f_path, 'rb') as f, open(out_path_1, 'wb') as f_out1, open(out_path_2, 'wb') as f_out2:
    pdf = PdfFileReader(f)
    pdf_out1 = PdfFileWriter()
    pdf_out2 = PdfFileWriter()
    cnt_pages = pdf.getNumPages()
    print(f'共 {cnt_pages} 页')
    for i in range(cnt_pages):
        if i <= cnt_pages //2:
            pdf_out1.addPage(pdf.getPage(i))
        else:
            pdf_out2.addPage(pdf.getPage(i))
    pdf_out1.write(f_out1)
    pdf_out2.write(f_out2)
# 再把后半个文件与前半个文件合并,后半个文件在前
with open(out_path, 'wb') as f_out:
    cnt_f, cnt_b = pdf_out1.getNumPages(), pdf_out2.getNumPages()
    pdf_out = PdfFileWriter()
    for i in range(cnt_b):
        pdf_out.addPage(pdf_out2.getPage(i))
    for i in range(cnt_f):
        pdf_out.addPage(pdf_out1.getPage(i))
    pdf_out.write(f_out)


PDFの回転と並べ替え

import pathlib
from PyPDF2 import PdfFileReader, PdfFileWriter
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
out_path = path.joinpath('002pdf_rotate.pdf')
with open(f_path, 'rb') as f, open(out_path, 'wb') as f_out:
    pdf = PdfFileReader(f)
    pdf_out = PdfFileWriter()
    page = pdf.getPage(0).rotateClockwise(90)
    pdf_out.addPage(page)
    # 把第二页放到前面
    pdf_out.addPage(pdf.getPage(2))
    page = pdf.getPage(1).rotateCounterClockwise(90)
    pdf_out.addPage(page)
    pdf_out.write(f_out)


PDF透かしを追加し、透かしを削除します

画像透かしの追加とは、実際には背景が透明な画像をページに追加することです。これは、ページのmergePageメソッドで完了できます。

import pathlib
from PyPDF2 import PdfFileReader, PdfFileWriter
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
wm_path = path.joinpath('watermark.pdf')
en_path = path.joinpath('002pdf_with_watermark_en.pdf')
out_path = path.joinpath('002pdf_with_watermark.pdf')
with open(f_path, 'rb') as f, open(wm_path, 'rb') as f_wm, open(out_path, 'wb') as f_out:
    pdf = PdfFileReader(f)
    pdf_wm = PdfFileReader(f_wm)
    pdf_out = PdfFileWriter()
    wm_cn_page = pdf_wm.getPage(0)
    wm_en_page = pdf_wm.getPage(1)
    cnt_pages = pdf.getNumPages()
    for i in range(cnt_pages):
        page = pdf.getPage(i)
        page.mergePage(wm_cn_page)
        pdf_out.addPage(page)
    pdf_out.write(f_out)


透かしの除去はより複雑であり、さまざまな状況に応じて特定の分析が必要です。透かしはテキスト、画像、またはさまざまな組み合わせである可能性があるため、重要なのは特徴を識別することです。

透かし除去の3つの一般的なアイデア:

  • 特徴的な単語を見つけたら、英語のドキュメントには適していますが、中国語などのCJK文字には適していません。

    PDFページを画像に変換した後、画像アルゴリズムを使用して透かしを削除しますが、これによりファイルの元の情報構造が破壊されます。

    透かしのサイズと場所の特性に応じて、すべての要素が検出され、削除されます。これがより推奨される方法です。

3番目の方法が最適ですが、複雑なドキュメントの透かしに遭遇した場合は、忍耐力をテストします。

操作コマンドを1つずつ特定し、透かしが正常に削除されるまで置き換えながら効果を確認する必要があります。

ただし、このPDFは複数の人によって透かしが入れられており、すでに複数の透かし入れ方法が含まれている可能性があるため、残りのすべてのページを同じ機能モードで削除できるわけではありません。

したがって、透かしを入れるための100%安全で効果的な(情報を削除するのは悪くない)そして普遍的な方法はありません。

透かしの追加と削除は、本質的に攻撃的および防御的な戦略です。

たとえば、一部のツールでは透かしの削除機能が導入されています。公開されると、透かしの関係者はその削除方法を識別して回避できます。

最後に、著作権の尊重はすべての人の態度です。

学習に加えて、正式な使用では、コンテンツ作成者のルールに従う必要があります。

PDFの暗号化と復号化

PDFのパスワードは、ユーザーパスワードと所有者パスワードに分けられます。

PyPDF2は、基本的な暗号化機能である「悪役ではなく紳士からの保護」を提供します。

PDFファイルを開いた後に新しいファイルがコピーされた場合、新しいファイルは所有者のパスワードによる制限を受けず、変更できます。

import pathlib
from PyPDF2 import PdfFileReader, PdfFileWriter
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
out_path_encrypt = path.joinpath('002pdf_encrypt.pdf')
out_path_decrypt = path.joinpath('002pdf_decrypt.pdf')
with open(f_path, 'rb') as f, open(out_path_encrypt, 'wb') as f_out:
    pdf = PdfFileReader(f)
    pdf_out = PdfFileWriter()
    cnt_pages = pdf.getNumPages()
    for i in range(cnt_pages):
        page = pdf.getPage(i)
        pdf_out.addPage(page)
    pdf_out.encrypt('123456', owner_pwd='654321')
    pdf_out.write(f_out)
# 重新读取加密文件并生成解密文件
with open(out_path_encrypt, 'rb') as f, open(out_path_decrypt, 'wb') as f_out:
    pdf = PdfFileReader(f)
    if not pdf.isEncrypted:
        print('文件未被加密')
    else:
        success = pdf.decrypt('123456')
        # if not success:
        pdf_out = PdfFileWriter()
        pdf_out.appendPagesFromReader(pdf)
        pdf_out.write(f_out)


pdfminer.six

PDFMinerの動作しきい値は比較的高く、複雑なコンテンツ処理ツールのカスタマイズされた開発に適したPDFのドキュメント構造モデルを部分的に理解する必要があります。

PDFMinerを直接使用することは比較的まれです。ここでは、基本的なドキュメントコンテンツ操作のみを示します。

import pathlib
from pdfminer.pdfparser import PDFParser
from pdfminer.pdfdocument import PDFDocument
from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import PDFResourceManager
from pdfminer.pdfinterp import PDFPageInterpreter
from pdfminer.pdfdevice import PDFDevice
from pdfminer.layout import LAParams, LTTextBox, LTFigure, LTImage
from pdfminer.converter import PDFPageAggregator
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
with open(f_path, 'rb') as f:
    parser = PDFParser(f)
    doc = PDFDocument(parser)
    rsrcmgr = PDFResourceManager()
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)
    for page in PDFPage.create_pages(doc):
        interpreter.process_page(page)
        layout = device.get_result()
        for x in layout:
            # 获取文本对象
            if isinstance(x, LTTextBox):
                print(x.get_text().strip())
            # 获取图片对象
            if isinstance(x,LTImage):
                print('这里获取到一张图片')
            # 获取 figure 对象
            if isinstance(x,LTFigure):
                print('这里获取到一个 figure 对象')


pdfminerを使用するためのしきい値は高いですが、複雑な状況に遭遇した場合は、最終的に使用する必要があります。現在のオープンソースモジュールの中で、PDFを最も包括的にサポートする必要があります。

次のpdfplumberは、pdfminer.sixに基づいて開発されたモジュールであり、使用のしきい値を減らします。

pdfplumber

pdfminer.sixと比較して、pdfplumberはより便利なPDFコンテンツ抽出インターフェースを提供します。

次のような日常業務の一般的な操作:

  • PDFコンテンツを抽出し、txtファイルに保存します

    PDF形式のテーブルをExcelに抽出

    PDFから画像を抽出する

    PDFでチャートを抽出する

PDFコンテンツを抽出し、txtファイルに保存します

import pathlib
import pdfplumber
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
out_path = path.joinpath('002pdf_out.txt')
with pdfplumber.open(f_path) as pdf, open(out_path ,'a') as txt:
    for page in pdf.pages:
        textdata = page.extract_text()
        txt.write(textdata)


PDF形式のテーブルをExcelに抽出

import pathlib
import pdfplumber
from openpyxl import Workbook
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
out_path = path.joinpath('002pdf_excel.xlsx')
wb = Workbook()
sheet = wb.active
with pdfplumber.open(f_path) as pdf:
    for i in range(19, 22):
        page = pdf.pages[i]
        table = page.extract_table()
        for row in table:
            sheet.append(row)
wb.save(out_path)

上記はopenpyxlの関数を使用してExcelファイルを作成しますが、別の記事で後で紹介します。

PDFから画像を抽出する

import pathlib
import pdfplumber
from PIL import Image
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-疫情影响下的中国社区趋势研究-艾瑞.pdf')
out_path = path.joinpath('002pdf_images.png')
with pdfplumber.open(f_path) as pdf, open(out_path, 'wb') as fout:
    page = pdf.pages[10]
    # for img in page.images:
    im = page.to_image()
    im.save(out_path, format='PNG')
    imgs = page.images
    for i, img in enumerate(imgs):
        size = img['width'], img['height']
        data = img['stream'].get_data()
        out_path = path.joinpath(f'002pdf_images_{i}.png')
        with open(out_path, 'wb') as fimg_out:
            fimg_out.write(data)

PIL(Pillow)関数は、上の画像を処理するために使用されます。

PDFでチャートを抽出する

グラフは画像とは異なり、ヒストグラムや円グラフなどのデータ生成グラフを参照します。

import pathlib
import pdfplumber
from PIL import Image
path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/002pdf')
f_path = path.joinpath('2020-新冠肺炎疫情对中国连锁餐饮行业的影响调研报告-中国连锁经营协会.pdf')
out_path = path.joinpath('002pdf_figures.png')
with pdfplumber.open(f_path) as pdf, open(out_path, 'wb') as fout:
    page = pdf.pages[7]
    im = page.to_image()
    im.save(out_path, format='PNG')
    figures = page.figures
    for i, fig in enumerate(figures):
        size = fig['width'], fig['height']
        crop = page.crop((fig['x0'], fig['top'], fig['x1'], fig['bottom']))
        img_crop = crop.to_image()
        out_path = path.joinpath(f'002pdf_figures_{i}.png')
        img_crop.save(out_path, format='png')
    im.draw_rects(page.extract_words(), stroke='yellow')
    im.draw_rects(page.images, stroke='blue')
    im.draw_rects(page.figures)
im # show in notebook

おすすめ

転載: blog.csdn.net/stay_foolish12/article/details/112847712