ぷそさんのプログラミング研究所

【Python】PDFのテキストを抽出する方法|座標を取得する方法やエクセルに出力する方法も紹介

目次

PythonでPDFのテキストを抽出する

PythonではPDFの文字を抽出することができます。

今回は,テキストの抽出と,テキストの座標を出力する方法をご紹介します。

【基礎編】PDFのテキストを抽出する方法

準備するモノ

以下のモジュールが必要となります。

pipcondaでインストールしてください。

  • pdfminer
  • pandas(エクセル出力用)
  • 読み取りたいPDF

ここでは,下のようなPDFを読み取る例でご紹介します。

コード解説

モジュールの読み込み

まずは,必要なモジュールをimportします。

import pandas as pd
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage

読み取り関係のオブジェクトを取得(コピペOK)

pdfminerの読み取り関係のオブジェクトを取得します。

それぞれの関係は以下のようになっています。

ライブラリ機能
PDFResourceManagerPDF文書内のリソースへのアクセスや、リソースの共有を管理
LAParamsPDF文書のレイアウト解析に関するパラメータを設定
PDFPageAggregator中間的なストレージとして使用
PDFPageInterpreterテキストやグラフィックスの構造を理解し、テキストの抽出や処理を実行
# 読み取り関係のオブジェクトを取得(コピペでOK)
resourceManager = PDFResourceManager()
# 読み取りパラメータの設定
laParams = LAParams(line_overlap = 0.3,
                    word_margin  = 0.05,
                    char_margin  = 2,
                    detect_vertical = True)
device = PDFPageAggregator(resourceManager, laparams=laParams)
interpreter = PDFPageInterpreter(resourceManager, device)

テキストボックスを取得する関数(コピペでOK)

PDF文書内のテキストボックスを取得する関数です。

テキストの座標を取得する際に使用します。

# テキストボックスを取得する関数(コピペでOK)
def find_textboxes(layout):
    if isinstance(layout, LTTextBox):
        return [layout]
    elif isinstance(layout, LTContainer):
        boxes = []
        for child in layout:
            boxes.extend(find_textboxes(child))
        return boxes
    else:
        return []

読み取るPDFを指定

読み取りたいPDFを取得します。

pdf_fileに読み取りたいファイルのパスを指定します。

# 読み取りファイルの指定
pdf_file = 'テキストpdf/読み取り2ページ.pdf'
# ファイルの取得
fp = open(pdf_file, 'rb')
# PDFの取得
pdfPages = PDFPage.get_pages(fp)

テキストを抽出して保存する

PDF内のテキストをテキストボックスごとに抽出してtext_listという配列に保存します。

複数ページに対応するためにpdfPagesをfor文で回しています。

1ページごとに全テキストボックスを抽出して読み取りを行うイメージです。

text_list = []
for page_no, page in enumerate(pdfPages, start=1):
    #ページ処理
    interpreter.process_page(page)
    #LTPageオブジェクトを取得
    layout = device.get_result()
    #1ページ内のテキストのまとまりのリストを取得
    boxes = find_textboxes(layout)

    #テキストひとまとまりごとに処理
    for box in boxes:
        text_list.append(box.get_text().strip())

出力イメージ

print(text_list)

>> ['これはヘッダーです',
 'サンプル⽂章',
 '夏の⽇、さわやかな⾵が⼼地よく吹き抜ける。空は⻘く、雲⼀つない。海岸には家族連れ\nやカップルが楽しいひとときを過ごしている。⼦供たちは砂浜で砂遊びに夢中で、波が⾜\n元に優しく押し寄せては引いていく。',
 'の中にはカラフルな⿂たちが泳いでおり、シュノーケリングを楽しむ⼈々がその美しさ',
 '海',
 'を堪能している。遠くにはヨットが静かに漂い、太陽の光を受けてキラキラと輝いてい\nる。',
 'んな⾵景に囲まれて、私は深呼吸をする。この瞬間が永遠に続いてほしいと思う。家族\nと過ごす特別な休暇は、⽇常の喧騒から離れて⼼をリフレッシュさせる貴重な時間だ。',
 'そ',
 '⽅になると、⼣⽇が海の中に沈み、空はオレンジとピンクに染まる。夜には星が輝き、\n海岸にはキャンプファイヤーが灯り、友⼈たちと楽しい時間を過ごす。この場所での思い\n出は、私の⼼にずっと残るだろう。',
 '⼣',
 'n a summer day, a refreshing breeze blows gently through the air. The sky is blue, without',
 'O',
 '2023  ぷそらぼ',
 'a single cloud in sight. Along the coastline, families and couples are enjoying a delightful \nmoment. Children are engrossed in playing with the sand on the beach, and the waves roll in \nand out gently at their feet.',
 "eneath the sea's surface, colorful fish are swimming, and people snorkel to appreciate their \nbeauty. In the distance, a yacht peacefully drifts, glistening in the sunlight.",
 'B',
 'urrounded by such a scenery, I take a deep breath. I wish this moment could last forever. \nSpecial vacations with family offer precious time to refresh the soul, away from the hustle \nand bustle of everyday life.',
 'S',
 's evening approaches, the sun sets into the sea, painting the sky with shades of orange and \npink. At night, the stars twinkle, and campfires light up the coastline as friends gather for a \njoyful time. The memories made in this place will stay in my heart forever. \nade in this place will stay in my heart forever.',
 'A',

コード全文

こちらが基礎編のコード全文です。

コピペで使用する際には,pdf_fileを変更する必要があります。

import pandas as pd
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage

# 読み取り関係のオブジェクトを取得(コピペでOK)
resourceManager = PDFResourceManager()
# 読み取りパラメータの設定
laParams = LAParams(line_overlap = 0.3,
                    word_margin  = 0.05,
                    char_margin  = 2,
                    detect_vertical = True)
device = PDFPageAggregator(resourceManager, laparams=laParams)
interpreter = PDFPageInterpreter(resourceManager, device)

# テキストボックスを取得する関数(コピペでOK)
def find_textboxes(layout):
    if isinstance(layout, LTTextBox):
        return [layout]
    elif isinstance(layout, LTContainer):
        boxes = []
        for child in layout:
            boxes.extend(find_textboxes(child))
        return boxes
    else:
        return []

# 読み取りファイルの指定
pdf_file = 'テキストpdf/読み取り2ページ.pdf'
# ファイルの取得
fp = open(pdf_file, 'rb')
# PDFの取得
pdfPages = PDFPage.get_pages(fp)

text_list = []
for page_no, page in enumerate(pdfPages, start=1):
    #ページ処理
    interpreter.process_page(page)
    #LTPageオブジェクトを取得
    layout = device.get_result()
    #1ページ内のテキストのまとまりのリストを取得
    boxes = find_textboxes(layout)

    #テキストひとまとまりごとに処理
    for box in boxes:
        text_list.append(box.get_text().strip())

【応用編】テキストの座標を取得

テキストボックスの座標を取得する方法は,基礎編の応用で出来ます。

座標を取得するイメージ

そもそも,座標を取得するというのは以下のようなイメージです。

簡単に言うと,テキストボックスの四角形の各頂点を取得する形になります。

この時,原点は赤丸で示している左隅下となります。

コード解説

基礎編の「モジュールの読み込み」〜「読み取るPDFを指定」までは同じ手順で行ってください。

テキストボックスと座標を取得する

pandasのDataFrameに座標・テキスト・ページ数を保存します。

各テキストボックスの情報を順番にdfに結合していくイメージです。

df = pd.DataFrame()
for page_no, page in enumerate(pdfPages, start=1):
    #ページ処理
    interpreter.process_page(page)
    #LTPageオブジェクトを取得
    layout = device.get_result()
    #1ページ内のテキストのまとまりのリストを取得
    boxes = find_textboxes(layout)

    #テキストひとまとまりごとに処理
    for box in boxes:
        df_page = pd.DataFrame({"x_start":[box.x0],
                                "x_end"  :box.x1,
                                "y_start":box.y0,
                                "y_end"  :box.y1,
                                "text"   :box.get_text().strip(),
                                "page"   :page_no}
                                )

        df = pd.concat([df,df_page])

dfには以下のような情報が入ります。

csvで出力

エクセルなどで管理したい場合には,csvで出力します。

df.to_csv("outout.csv")

コード全文

テキストの座標を取得するコードは以下になります。

コピペで使用する際には,pdf_fileを変更する必要があります。

import pandas as pd
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage

# 読み取り関係のオブジェクトを取得(コピペでOK)
resourceManager = PDFResourceManager()
# 読み取りパラメータの設定
laParams = LAParams(line_overlap = 0.3,
                    word_margin  = 0.05,
                    char_margin  = 2,
                    detect_vertical = True)
device = PDFPageAggregator(resourceManager, laparams=laParams)
interpreter = PDFPageInterpreter(resourceManager, device)

# テキストボックスを取得する関数(コピペでOK)
def find_textboxes(layout):
    if isinstance(layout, LTTextBox):
        return [layout]
    elif isinstance(layout, LTContainer):
        boxes = []
        for child in layout:
            boxes.extend(find_textboxes(child))
        return boxes
    else:
        return []

# 読み取りファイルの指定
pdf_file = 'テキストpdf/読み取り2ページ.pdf'
# ファイルの取得
fp = open(pdf_file, 'rb')
# PDFの取得
pdfPages = PDFPage.get_pages(fp)

df = pd.DataFrame()
for page_no, page in enumerate(pdfPages, start=1):
    #ページ処理
    interpreter.process_page(page)
    #LTPageオブジェクトを取得
    layout = device.get_result()
    #1ページ内のテキストのまとまりのリストを取得
    boxes = find_textboxes(layout)

    #テキストひとまとまりごとに処理
    for box in boxes:
        df_page = pd.DataFrame({"x_start":[box.x0],
                                "x_end"  :box.x1,
                                "y_start":box.y0,
                                "y_end"  :box.y1,
                                "text"   :box.get_text().strip(),
                                "page"   :page_no}
                                )

        df = pd.concat([df,df_page])
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

このブログでは,PythonやLaTeXの使い方などを紹介しています!
仕事でも趣味でもプログラミングをしています。
ブログは2022年8月にスタートしました。
【経歴】東京大学大学院修了→大手IT企業勤務

コメント

コメントする

目次