こんにちは、アライアンス事業部のまつおかです。
Alteryx で Pythonツールを使って PDFファイル内の文字列を読み込んでみましたので、その手順をご紹介します。
使用環境
- Windows 10 Pro
- Alteryx Designer 2023.1.1.200
使用したPDFファイル
今回は超シンプルなPDFファイルからテキストを抽出してみることを目的とし、青空文庫からいただいてきたテキストのみが入っている以下のようなPDFファイルを使用しました。
やってみた
- ライブラリのインストール
- PDFファイル内のテキストを抽出
- PDFファイル内のテキストを抽出し、1ページ1レコードで出力
- フォルダ内の複数PDFファイルを読み込みテキストを抽出し、ファイル別1ページ1レコードで出力
1. ライブラリのインストール
Python を使用して PDFファイルからテキストを抽出する場合いくつか使用できるライブラリがあるのですが、その中でも今回は「pdfminer.six」を使用します。
まずはAlteryx Designerを開き、開発者のパレットの中にあるPythonツールを配置します。
ツールを配置すると左側に Jupyter Notebook の画面が開きますので、ここにコードを書いていきます。通常の Jupyter Notebook 同様セル単位で実行することもできます。
Alteryx Designer で新たにライブラリを追加するにはPackage.installPackages(”package-name”)
を実行します。ツールを配置するとライブラリインストール時の記述方法が書いてありますので、それにならって書けばOKです。
実際のコードはこちらになります。
ayx
というモジュールは、Alteryx独自のPython用モジュールです。
from ayx import Package
Package.installPackages("pdfminer.six")
実行して「Successfully Installed・・・」と表示されれば正常にインストールできています。
Successfully installed charset-normalizer-3.3.1 cryptography-41.0.5 pdfminer.six-20221105
エラーが発生し「check the permissions」といった旨のメッセージが表示された場合は、インストール先のフォルダへの書き込み権限がないことが考えられます。
その場合は Alteryx Designer を管理者権限で実行(Alteryx Designer のアイコンを右クリックし「管理者権限で実行」をクリック)した上で、再度インストールを実行してください。
ライブラリのインストールは一度正常に実行できればOKですので、コード自体を削除もしくはコメント(行頭に#をつける)に変更していただいて問題ありません。
2. PDFファイル内のテキストを抽出
ライブラリのインストールが完了したので、まずはPDFファイルに入っているテキストをまとめて抽出してみます。
作成したワークフローはこちら。
最初に配置したテキスト入力ツールに、読込み対象となるファイルのフルパスが設定してあります。
次のフォーミュラツールでは、ファイルパスが「\」で区切られているのを「/」に置換しています。Pythonでは「\」だと正しくファイルパスと認識してくれないためです。
次のPythonツールでいよいよテキストを読み込みます。
記述したコードはこちらです。
from ayx import Alteryx
from pdfminer.high_level import extract_text
import pandas as pd
#ファイル情報取得
PathInf=Alteryx.read("#1")
#PDF内のテキスト取得
text = extract_text(PathInf.iat[0,0])
#アンカー出力用にpandasデータフレーム作成
out = {
'Path': [PathInf.iat[0,0]],
'text': [text]
}
#データフレーム作成
df = pd.DataFrame(out)
#アンカー1からデータ出力
Alteryx.write(df,1)
フォーミュラツールから渡されたデータは、6行目のAlteryx.read
で取得できます。「#1」というのはツール同士の接続の名前です。
取得したデータは pandasデータフレーム という表形式のデータ構造になっていますので、iatメソッドで行と列の番号を指定してデータを抜き出します。ここではデータは1行1列しかありませんのでiat[0,0]
と記述することでファイルパスが取得できます。
また、PDFファイルからテキストを抽出するにはextract_text(’PDF_file’)
を使用します。
以上を組み合わせて9行目のように記述すると、PDFファイル内のテキストを取得することができます。
Pythonツールからデータを出力する際も pandasデータフレームにする必要がありますので、ファイルパスとテキストデータからデータフレームを作成し(12~16行目)、最後にPythonツールのアンカー1からデータを出力します。
出力した結果がこちらです。ちゃんとテキストが取得できています!
3. PDFファイル内のテキストを抽出し、1ページ1レコードで出力
では次は、複数ページに渡るファイルのテキストを、1ページ1レコードで出力してみます。
記述したコードはこちらです。
from ayx import Alteryx
from pdfminer.high_level import extract_text
import pandas as pd
#ファイル情報取得
PathInf=Alteryx.read("#1")
#PDF内のテキスト取得
text = extract_text(PathInf.iat[0,0])
#リスト作成
data=[]
#テキストをページで区切る
text = text.rstrip('\f')
for page_num, page_text in enumerate(text.split('\f'), start=1):
#ページごとに区切ったデータをリストに追加
data.append([page_num, page_text])
#データフレーム作成
df = pd.DataFrame(data, columns=["page", "text"])
#アンカー1からデータ出力
Alteryx.write(df,1)
9行目のテキストを取得するところまでは先程と同じですが、その後テキストを改ページで区切って1ページ1レコードで出力しています。
区切ったデータを追加していくために、12行目で「data」という名前のリストを用意しておき、16~19行目で改ページコード(\f)で区切ったデータをリストに追加しています。
実行してみたところ、データの最後にも改ページコードが含まれていることがわかったので、15行目で事前に最後の改ページコードは削除しています。
これで出力した結果がこちらです。ちゃんと1ページ1レコードでテキストが出力できています!
4. フォルダ内の複数PDFファイルを読み込みテキストを抽出し、ファイル別1ページ1レコードで出力
では最後に、フォルダ内の複数PDFファイルを読み込みテキストを抽出し出力してみます。
作成したワークフローはこちら。
まずはディレクトリツールを使って、複数のPDFファイルが入ったディレクトリからファイルパスを取得し、不要な列を除外し、先程同様ファイルパスを置換します。
Pythonツールに渡されるデータはこのようになっており、2つのファイル情報が取得できている状態です。
そしてPythonツールに記述したコードはこちらになります。
from ayx import Alteryx
from pdfminer.high_level import extract_text
import pandas as pd
#ファイル情報取得
PathInf=Alteryx.read("#1")
#リスト作成
data=[]
#データフレームからindexを取得
for index in PathInf.index:
#PDF内のテキスト取得
text = extract_text(PathInf.iat[index,0])
#テキストをページで区切る
text = text.rstrip('\f')
for page_num, page_text in enumerate(text.split('\f'), start=1):
#ファイル名とページごとに区切ったデータをリストに追加
data.append([PathInf.iat[index,1], page_num, page_text])
#データフレーム作成
df = pd.DataFrame(data, columns=["filename", "page", "text"])
#アンカー1からデータ出力
Alteryx.write(df,1)
今回はファイルごとに処理する必要があるので、そこのループ処理を書いているのが12行目のfor文となります。ここでは index ではなくデータ自体を取得しても良いのですが、今までの記述と同じようにするためiat
メソッドでパラメータに index を使用することで、参照する行を可変にしました。
ということで、出力した結果がこちら!
2つ目のファイルは1ページしかないので、合計3行のデータとして出力されています。
これでPDFに含まれる文字列の取得ができたので、このあとはテキストデータとして扱うことが可能となります。
さいごに
今回はごくごくシンプルなテキストの抽出を試してみました。
いろいろなライブラリやそこに用意されている関数を使用することでもっと複雑なPDFファイルのデータを抽出することも可能ですので、今後はそちらも試してみたいと思います。