Power Automate DesktopでPDFのページ数を取得するのは難しい
Power Automate DesktopでPDFのページ数を取得するのは容易ではないという話です。
2022/12/04 追記
Acrobat や Edge を利用してページ数を取得するフローを作ってみました。
Power Automate Desktop: Acrobat を使ってPDFのページ数を取得
Power Automate Desktop: Edge を使ってPDFのページ数を取得
PDFをページごとに処理するにはページ数が必要
銀行のサイトから計算書を取得しました。1ページ1件で複数ページあります。このファイルから1件ごとにデータを取得したいと思います。
「PDFからテキストを抽出」アクションを使ってループ内で1ページごとデータを取得して処理しようと思いました。
ループを使うにはファイルのページ数が必要です。簡単にPower Automate Desktopで取れるのだろうと思ったらなんとそのような方法が見つかりませんでした。
ありえないページ数を最大値に指定して、見つからなかったらエラー処理という方法も考えられますが好きではありません。
ExtractedPDFTables.Countを使用
丁度今月リリースされたPower Automate Desktop 2.17 には「PDFからテーブルを抽出する」というアクションが追加されています。
このアクションで取得されたデータの Count プロパティを使うとファイルに含まれるテーブル数を取得できます。
今回のPDFファイルは1ページに1つテーブルが含まれていたため、これを使って取得することができました。
例:ExtractedPDFTables.Count
アクションの実行に時間はかかるものの、今回の件では確実にページ数を取得でき、正しく処理できました。
PDFから直接ページ数を取得するのは容易ではない
PDFファイルを直接読み込んでページ数を取得できるのではと思いました。
しかし、実際にはバージョン違い等があって、容易ではないようです。
EXCEL VBA AcrobatReaderやAdobeを使わずにPDFのページ数を取得する方法
自社で作ったPDFならバージョンやフォーマットがある程度特定できるのでこういった方法も一つだと思います。
しかし、いろんなところからくる請求書を処理するような場合、いつどんなデータがくるのかわかりません。
Power Automate DesktopでPDFのプロパティを取得できるアクションが欲しいと思いました。
試してみると
次のページにVBAでページ数を取得する方法が紹介されていました。
ExcelVBAのみでPDFファイルのページ数を取得する Qiita
PDFファイルの構造上、「/Count 」はソーステキストに1回しか出現しないこと、通常表示される文字列はStreamオブジェクト内に圧縮されているため正規表現にマッチしないことからページ数の抜き出しが可能となっています。
と書かれています。
そこでPower Automate Desktopに移植してみました。
コピーしたコードは次の通りです。Power Automate Desktopの編集画面に貼付すれば復元できます。
Display.SelectFileDialog.SelectFile FileFilter: $'''*.pdf''' IsTopMost: True CheckIfFileExists: False SelectedFile=> SelectedFile ButtonPressed=> ButtonPressedページ数はSubtext変数に入ります。
実行してみたところExcelから出力したファイルは取得できました。
しかし、家電製品等の取説などは軒並みだめでした。
まずソニーの取説はCountが見つかりませんでした。Encryptという文字があったので暗号化されているようです。もしかしたらそのせいかもしれません。
Chromeで保存したと思われるPDFは次のように複数のカウントがありました。
223 0 objこれは、ページカウントオブジェクトが階層化されているようです。
この場合 /Parentがないオブジェクトを探し出して処理する必要があります。
少しトライしてみましたが容易ではありませんでした。
/Type /Pagesと/Countの順番が入れ替わっている場合もあるようです。
各キーワードのデリミターもスペースの場合と改行の場合もあります。改行はCRなのかLFなのか、CRLFなのかも考える必要があります。
存在しないページを指定してもエラーが発生しない
好きではないけれど、エラーが発生したらおしまいという方法も試してみようと思いました。
ところが、ループで「PDFからテキストを抽出」アクションを繰り返して、存在しないページに達してもエラーは発生しませんでした。
そしてExtractedPDFTextには最終ページのテキストが入るようです。直前でExtractedPDFTextをクリアしても挙動は一緒でした。
これは困りました。
ファイル分割ではエラーが発生
仕方がないのでファイル分割を試したところ、さすがにこちらはエラーが発生しました。そのため、「ページが範囲外です」エラーが発生したらループを抜けるというフローを書いてみました。
ループ中で、「新しいPDFファイルへのPDFファイルページの抽出」アクションにページ数(LoopIndex)を指定しながら実行します。存在しないページを指定するとエラーが発生するので、LoopIndexから1引いた数がページ数です。
コードは次の通りです。
デスクトップフローとして部品化してもよいかもしれません。
実際に使うとなると、分割ファイルのパスについて考慮が必要です。固定ファイルにするのか、一時ファイルとして処理するのか。分割ファイルの最後は削除するのかどうかも考慮する必要があります。他のエラーが発生したときのTry Catchも必要でしょう。
ページ数が最大値に達したときの処理も必要かもしれません。ありえないページ数にしておけば現実的には問題ありませんが。
2022/11/24 追記
ループで1ページずつカウントアップしていくと時間がかかるので、10ページずつカウントアップして抽出を試みて、エラーが起こったら1ページずつカウントダウンして、エラーが起こらないページを探す、という方法が考えられます。これだと抽出回数を軽減できます。
数百ページがざらなら、100ページずつカウントアップして探すのも一つだと思います。
このあたりは二分探索的なアルゴリズムが使える気がするので、調べてみるのも一つでしょう。
アルゴリズムを勉強するなら二分探索から始めよう! 『なっとく!アルゴリズム』より
Acrobatから取得する
2022/11/24 追記
原始的というかPower Automate for Desktopらしい方法としては、Acrobat でPDFを開き、「ファイル」メニューの「プロパティ」を開き、「ページ数」を取得するという方法が考えられます。調べたいファイルしか開いていないのが確実であればこの方法も一つです。
しかし、実際に Acrobat のウィンドウを待機するには次のような問題が開いrます。
- タイトルにファイル名が表示されるとは限らない
- MDIとSDI
タイトルにファイル名が表示されるとは限らない
Acrobatのウィンドウのタイトルに表示される文字は、ファイル名とは限りません。PDFファイルのタイトルが表示されている場合があります。常にファイル名を表示するには、「編集」「環境設定」「文書」にある「常にファイル名を文書のタイトルとして使用」にチェックが入っている必要があります。
MDIとSDI
AcrobatはMDIとSDIを選択可能です。デフォルトはMDI(一つのウィンドウで複数のファイルを開く)ですが、「編集」「環境設定」「一般」の「同じウィンドウで新しいタブとして文書を開く」のチェックを外すとSDIにすることができます。
ユーザーによって使い方が異なるのでウィンドウクラスが「AcrobatSDIWindow」かどうかを考慮する必要があると思います。
他にも問題があったような気もしますが、眠いのでここまでとします。
コメント
コメントを投稿