Tech Blog
  • HOME
  • Blog
  • 【RPA】請求書PDFをPADでテキスト化。JavaScriptと正規表現のハマりポイントも回避。

【RPA】請求書PDFをPADでテキスト化。JavaScriptと正規表現のハマりポイントも回避。

公開日:2022.10.18 最終更新日:2024.03.28

ano

あの手先
Profile

この記事では、PAD請求書PDFをテキスト化する方法と、JavaScriptを実行する時のハマりポイントを紹介します!


請求書って、毎月、毎月処理があるので大変ですよね。自分の話でいいますと、AWSの請求書から、各アカウント(各事業部)がそれぞれいくら使ったのかを集計しなくちゃいけないのですが、その請求書PDFが、1ファイル数十ページ、数十ファイルとかあるので、自動化するまでは、かなり大変でした。

例えば、AWSの請求書PDFをPADテキスト化して、さらに正規表現を使って、ちょっとした加工を行うと、こんな感じのtsvファイルが一発で出力できちゃいます。

AWSアカウント 利用料 消費税
hogehoge-AmiVoice00 (012345678900) $1,234,567.89 $123,456.78
hogehoge-AmiVoice01 (012345678901) $123,456.78 $12,345.67
hogehoge-AmiVoice99 (012345678999) $0.12 $0.01

正規表現は、請求書の種類ごとに作る必要がありますが、1度作ってしまえば、毎月の手間がなくなります!

目次

はじめに
1. 全体フローの解説
2. 各アクションの解説とハマりどころ
おわりに

はじめに

PAD(Power Automate Desktop)について

PADとは、Power Automate Desktopの略称で、RPA(Robotic Process Automation)ツールのひとつです。Microsoft社が2021年3月から無償で提供しています。PADを使えば、プログラミングの知識を持っていない方でも、ノーコード・ローコード開発で自動化アプリが簡単に作れます。PADは、ここからダウンロードできます。

実践するとできるようになること

・PDFをテキスト化(※今回の記事では手書きPDFは想定外です)

・PADでJavaScriptを実行(ハマりどころを公開してます)

日常業務を自動化(他の重要な仕事に専念できる時間が増えます)

実践するために必要なものリスト

・PADを実行できる環境(執筆時のバージョン:2.23.114.22217)

・テキスト化したいPDF

1. 全体フローの解説

全体フローの完成形はこんな感じ

最初に処理開始~処理終了までのざっくりとした流れを解説します。

請求書PDFテキスト化の全体フロー

アクション①:フォルダー内のファイルを取得
⇒指定フォルダー内にあるPDFを探します。

アクション②:For each(ループ)
⇒各PDFごとにループ内のアクションを繰り返します。

アクション③:PDFからテキストを抽出
⇒PDFをテキスト化します。

アクション④:テキストを置換する
⇒JavaScriptを実行する際に不都合な文字を置き換えます。

アクション⑤:正規表現のエスケープテキスト
⇒JavaScriptを実行する際に不都合な特殊文字を置き換えます。

アクション⑥:JavaScriptの実行
⇒JavaScriptを実行します。(ここに正規表現を記述します)

アクション⑦:テキストをファイルに書き込む
⇒JavaScriptの実行結果をファイルに保存します。

アクション⑧:ファイルの移動
⇒テキスト化済みのPDFを指定フォルダー内に移動します。

アクション⑨:End(ループ)
⇒PDFが他にもあれば②に戻ります。なければループ終了。

簡単にまとめますと、指定フォルダー内にある、全てのPDFをテキスト化(JavaScriptの実行結果を保存)し、処理が終わったPDFを別のフォルダーに移動させる。です。

2. 各アクションの解説とハマりどころ

アクション①:フォルダー内のファイルを取得

まずは、テキスト化したいPDFの一覧を取得しましょう。
■アクション『フォルダー』⇒『フォルダー内のファイルを取得』

フォルダー:フォルダー内のファイルを取得

「フォルダー」:
テキスト化したいPDFのPath(保存場所)を指定します。例は、AWS請求書の中のAWS Incを指定しています。

「ファイルフィルター」:
この欄に *.pdf と入力すると、拡張子が.pdfである全てのファイルのPath一覧を取得できます。

「フロー変数 Files 」:
この変数に検索でヒットしたファイルのPath一覧が入ります。

これでテキスト化したいPDFのPath一覧が取得できます。

アクション②:For each(ループ)

次に、テキスト化したいPDFが複数あった場合に備えて、各PDFごとに処理を繰り返すためのループを設定しましょう。
■アクション『ループ』⇒『For each』

ループ:For each

「反復処理を行う値」:
PDFのPath一覧を指定します。この欄にフロー変数 %Files% と入力します。PADのアクションの中で変数を指定する時は、両端を % で挟んだ変数名を入力する必要があります。

「フロー変数 CurrentItem 」:
この変数に1つのPDFのPathが入ります。処理が繰り返されるたびに、次のPDFのPathに入れ替わります。

これで各PDFごとに処理を行う用意ができました。

アクション③:PDFからテキストを抽出

では本題に入って、PDFをテキスト化してみましょう。
■アクション『PDF』⇒『PDFからテキストを抽出』

PDF:PDFからテキストを抽出

「PDFファイル」:
PDFのPathを指定します。この欄にフロー変数 %CurrentItem% と入力します。

「フロー変数 ExtractedPDFText 」:
この変数にPDFから抽出したテキスト情報が入ります。実は、これだけでPDFのテキスト化が完了します。

単に請求書PDFをテキスト化したいだけの場合は、【アクション⑦:テキストをファイルに書き込む】移動可能です。あとは、フロー変数 %ExtractedPDFText% を「書き込むテキスト」に入力し、保存場所を決めるだけです。

テキスト化後に、CSV形式やTSV形式に整えたい場合には、スクリプト(今回はJavaScript)で正規表現を使うと便利です。

アクション④:テキストを置換する

PADでJavaScript等のスクリプトを実行する時には、ハマりポイントいくつか存在しています。その落とし穴を回避するために、ちょっとした工夫が必要です。このアクションでは、JavaScriptを実行する際に不都合な文字を置き換えます。この例では、フロー変数 %ExtractedPDFText% に含まれる ” を削除しています。
■アクション『テキスト』⇒『テキストを置換する』

テキスト:テキストを置換する

「解析するテキスト」:
テキスト情報が入っている変数を指定します。この欄にフロー変数 %ExtractedPDFText% と入力します。

「検索するテキスト」:
置き換えられるテキストを指定します。この欄に ” と入力します。(ダブルクォーテーション1つです。)テキスト情報に ” と ‘ の両方が含まれている場合、どちらか片方を削除しないとスクリプトにその変数が渡せません。理由は、【アクション⑥:JavaScriptの実行】紹介します。今回は ” の方を削除するために入力しています。

「置き換え先のテキスト」:
置き換えるテキストを指定します。この欄に %”% と入力します。(シングルクォーテーション2つです。)これは、削除したい(何もない状態に置換したい)場合に使います。この欄に何も入力しなかった時は、下記のエラーになります。(パラメーター’置き換え先のテキスト’:空にできません。)

「フロー変数 Replaced 」:
この変数に削除処理が完了したテキスト情報が入ります。

これでテキスト情報に含まれる ” を削除できます。

アクション⑤:正規表現のエスケープテキスト

ハマりポイントは、まだあります。もうひと工夫が必要です。このアクションでは、JavaScriptを実行する際に不都合な特殊文字を置き換えます。
■アクション『テキスト』⇒『正規表現のエスケープテキスト』

テキスト:正規表現のエスケープテキスト

「エスケープするテキスト」:
エスケープするテキストを指定します。この欄にフロー変数 %Replaced% と入力します。テキスト情報に文字になっていない改行が含まれている場合、スクリプトにその変数が渡せません。ここで改行を文字の改行 \n に置換(エスケープ)します。【アクション:テキストを置換する】では、 \n に置換できません。

「フロー変数 EscapedText 」:
この変数に置換処理が完了したテキスト情報が入ります。

これでテキスト情報に含まれる改行を文字の改行に置換できます。

アクション⑥:JavaScriptの実行

JavaScript等のスクリプトを実行する前処理がやっと完了したので、気を取り直してJavaScriptを実行しましょう。
■アクション『スクリプト』⇒『JavaScriptの実行』

スクリプト:JavaScriptの実行

「実行するJavaScript」:
JavaScriptのソースコードを指定します。この欄にJavaScriptのソースコードと入力します。ソースコードは、請求書の仕様に応じて正規表現を作ってください。

PADで定義した数値型の変数をJavaScriptに渡す時は、%hogehoge% で渡すことができるのですが、テキスト型の変数を渡す時は、両端を ” 又は ‘ で挟んだ変数名、”%hogehoge%” 又は ‘%hogehoge%’ で渡す必要があります。これらのように記述しなかった時は、下記のエラーになります。(Microsoft JScript コンパイル エラー: 文字が正しくありません。)テキスト情報に ” が含まれていなければ、 “%hogehoge%” で、‘ が含まれていなければ、 ‘%hogehoge%’ で渡せます。

アクション④:テキストを置換する】回避した、テキスト情報に ” と ‘ の両方が含まれている場合、どちらか片方を削除しないとエラーになる理由ですが、両端を ” 又は ‘ で挟んだ変数名で渡す必要があるので、両方が含まれていた時は、下記のエラーになります。(Microsoft JScript コンパイル エラー: ‘;’ がありません。等)

JavaScriptの中で変数の宣言を行う時は、var 、 let 、 const が使えません。これらを記述した時は、下記のエラーになります。(Microsoft JScript コンパイル エラー: ‘;’ がありません。等)

JavaScriptの実行結果を出力するために、WScript.Echo() や WScript.StdOut.Write() が利用できます。WScript.Echo() は、改行ありの出力で、WScript.StdOut.Write() は、改行なしの出力です。

「フロー変数 JavascriptOutput 」:
この変数にJavaScriptの実行結果(正常時)が入ります。

「フロー変数 ScriptError 」:
この変数にJavaScriptのエラー内容(異常時)が入ります。

これでPADでJavaScriptを実行することができます。

アクション⑦:テキストをファイルに書き込む

では、JavaScriptの実行結果をファイルに保存しましょう。
■アクション『テキスト』⇒『テキストをファイルに書き込む』

テキスト:テキストをファイルに書き込む

「ファイルパス」:
保存場所のPath(ファイル名も)を指定します。例は、AWS請求書の中のAWS Inc.tsvを指定しています。※tsv形式でもcsv形式でも正規表現を使うと簡単に作れます。

「書き込むテキスト」:
保存したいテキスト情報を指定します。この欄にフロー変数 %JavascriptOutput% と入力します。※JavaScript(正規表現)を使わずに済んだ場合には、 この欄にフロー変数 %ExtractedPDFText% と入力します。

「新しい行を追加する」:
テキスト情報を書き込んだ後に改行を入れるかを指定します。オンでもオフでもお好きなように。

「ファイルが存在する場合」:
既存の内容を上書きするか、末尾に追記するかを指定します。今回はループの中で書き込む仕様なので、内容を追加するを選択します。

これで保存したいテキスト情報をファイルに保存できます。

アクション⑧:ファイルの移動

テキスト化済みのPDFを別のフォルダー内に移動させて管理したい場合には、これを使います。
■アクション『ファイル』⇒『ファイルの移動』

ファイル:ファイルの移動

「移動するファイル」:
PDFのPathを指定します。この欄にフロー変数 %CurrentItem% と入力します。

「宛先フォルダー」:
移動させるファイルのPath(保存場所)を指定します。例は、AWS請求書の中のAWS Inc_処理済を指定しています。

「ファイルが存在する場合」:
既存の内容を上書きするか、なにもしないかを指定します。基本的には、上書きを選択します。(お好きなように)

これでテキスト化済みのPDFを別のフォルダーに移動できます。

アクション⑨:End(ループ)

『アクション②:For each』を設定すると、自動的に追加されます。テキスト化してないPDFが他にもあれば②に戻ってループします。全てのPDFの処理完了で、ループ(フロー全体)が終了です。

おわりに

いかがでしたか?テキスト化できましたでしょうか?初回の設定は、ちょっと大変だったかもしれませんが、これらを業務フローに応じてカスタマイズしていけば、毎月の請求書処理がワンクリックでできると思います。

あの手先

あの手先

ポチポチするだけで大半の仕事を遂行できるように、
業務自動化・RPA・MAの領域で、日々試行錯誤しています。

APIを無料で利用開始