1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【PyMuPDF】PDF内の表以外を抽出する

Last updated at Posted at 2024-10-05

PyMuPDFというPDF内の表抽出ができるライブラリがありますが、削除する直接的なメゾッドがなさそうだったので、何か方法がないか調べてみました。

手順

本記事では以下の手順で実装しています。

  1. PDFを読み込み
  2. 表の座標を抽出
  3. 座標を使って表を塗りつぶし保存
  4. 再度PDFを読み込み

注意事項

そもそもですが、私の経験上PyMuPDFはすべての表を認識できる訳ではありません。
例えば縦線が入っていない表は表と認識されません。
また逆に画像中のテキストなど、表ではないのに表と認識されてしまうケースもあります。

今回はPyMuPDFが正しく表と認識できるPDFを使用することを前提として記載しています。

実行環境

  • Google Colaboratory
  • Python: 3.10.12
  • PyMuPDF: 1.24.11

参考にしたドキュメント・サイト

実装

①PDFを読み込み

今回はこちらの論文を使用させていただきました。
「電車混雑予測 ~混雑の可視化が社会にもたらすインパクト~」
https://data.navitime.co.jp/pdf/monograph_20170610_2.pdf

colaboにはデフォルトでpymupdfが入っていないのでpipします。

ライブラリをインストール
!pip install pymupdf

早速ファイルを読み込み、正しく読み込めているか確認します。
今回はp. 12の表7を使用します。

PDFを読み込み
import pymupdf

# PDFファイルを読み込み
pdf_path = "/content/sample.pdf"
doc = pymupdf.open(pdf_path)
page = doc[11] #12ページ目を指定
page.get_text()

【出力結果】
※全体が見えるように各文で改行しています

\n12 \n表-7  運賃収入減少上位路線 \n線名 \n収支(円/日) 割合(%) \nJR山手線 \n-262866  \n-0.098  \nJR東海道本線 \n-129302  \n-0.068  \nJR京浜東北線 \n-94601  \n-0.045  \nJR宇都宮線〔東北本線〕 \nJR上野東京ライン \n-64110  \n-0.046  \n京急本線 \n-58849  \n-0.065  \n東武東上線 \n-51553  \n-0.055  \n京急空港線 \n-48776  \n-0.994  \n小田急小田原線 \n-44747  \n-0.026  \n都営浅草線 \n-34341  \n-0.049  \n東武野田線 \n-30825  \n-0.986  \n \n表6,表7 は利用人員の増減を金額換算した表である.
\n収支の変化が大きい上位20 路線を掲載している.
黒字\nは増額,赤字は減額を表す.鉄道運賃は同一事業者内で\nは路線ごとの運賃というものはないが,距離に比例して\n運賃を按分することに仮想的に路線ごとの運賃を算出し\nた...

表7の情報も抽出されていることが確認できました。

②表の座標を抽出

まず表が正しく抽出できているか確認します。

表を抽出
tabs = page.find_tables()
print(f"{len(tabs.tables)} found on {page}") 

【出力結果】

1 found on page 11

p. 12には1つしか表がないので、正しく認識できていると考えます。

次に座標を抽出します。

表の座標を抽出
tab = tabs[0]
rect = tab.bbox
rect

【出力結果】

(51.21999979019165, 69.77996826171875, 278.46998087565106, 240.32000732421875)

余談ですが、今回はp. 12のテーブルは1つですが、tabstabは異なるクラスに属するので、上記をtabs.bboxで取得しようとするとエラーが返ってきます。
いくつ目のテーブルか指定してから座標を抽出する必要がありそうです。

tabs.bboxで座標を取得しようとする
tabs.bbox

【出力結果】

AttributeError: 'TableFinder' object has no attribute 'bbox'
オブジェクトの型を確認
print(type(tabs))
print(type(tab))

【出力結果】

<class 'pymupdf.table.TableFinder'>
<class 'pymupdf.table.Table'>

③座標を使って表を塗りつぶし保存

表を塗りつぶし+保存
# 赤字で塗りつぶし
page.add_redact_annot(rect, fill=(1, 0, 0)) # 赤字を指定
page.apply_redactions() 

# 塗りつぶししたPDFを保存
output_path = "masked_pdf.pdf"
doc.save(output_path)
doc.close()

④再度PDFを読み込み

保存したPDFを読み込んで表の内容が削除されているか確認します。

中身の確認
doc_new = pymupdf.open(output_path)
page_new = doc_new[11]
page_new.get_text()

【出力結果】
※全体が見えるように各文で改行しています

 \n12 \n表-7  運賃収入減少上位路線 \n \n表6,表7 は利用人員の増減を金額換算した表である.\n収支の変化が大きい上位20 路線を掲載している.
 黒字\nは増額,赤字は減額を表す.鉄道運賃は同一事業者内で\nは路線ごとの運賃というものはないが,距離に比例して\n運賃を按分することに仮想的に路線ごとの運賃を算出し\nた.
 乗継割引がある会社をまたいだ時の運賃も同様に距\n離按分した. 
 \n結果としては概ね路線別増減と一致している.
 1日あ\nたり200 人増減,1 人あたりの運賃が200 円とすれば運\n賃収入は1日4万円前後の変化があることになり,結果\nは妥当だと考えられる.年額換算すると平日が年間250\n日とすれば1 路線1000 万円前後の変化がある計算にな\nる...

テーブル処理前の内容と比較してみると、「線名〜〜」意向が削除されており、表7の後の内容からが抽出されています。
念の為、masked_pdf.pdfをローカルにダウンロードし、PDFを見に行ってみます。

スクリーンショット 2024-10-05 15.16.47.png

上記のように赤く塗りつぶされていることがわかります。

終わりに

少し手間のかかる方法ですが、参考になれば幸いです。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?