はじめに
この記事は、トラストバンク Advent Calendar 2021の21日目です。
トラストバンク パブリテック事業部の藤谷です!トラストバンクといえば「ふるさとチョイス」ですが、今年の1月にパブリテック事業部にジョインし、行政専用ビジネスチャット「Logoチャット」のSREチームで開発、保守運用、サポート等幅広く担当しています。
パブリテックは新規事業ということもあり、約30名程度の少ない人数で業務を回しています。そのため、様々な作業が並行して必要となり、業務の自動化がテーマとなりました。
そんな中、Microsoftから「Power Automate Desktop」が無償で提供されました。これがとても素晴らしくて、日々の業務を自動化、改善するうえで大いに役立っているため紹介することにしました。
Power Automate Desktopの概要
Power Automate DesktopはMicrosoftが提供するRPAツールです。ノンコードでWindows上で行われるキーボードやマウス操作などの操作をコードを書かずに直感的に自動化プログラムを作成することができます。
何よりすごいのが無料で使えること。Windows10であれば以下から無償でダウンロードが可能。Windows11では標準インストールされ、無料でほとんどの機能を利用することができます。
https://powerautomate.microsoft.com/ja-jp/desktop/
以下、アクション一覧です。Windows上のあらゆる作業を自動化する機能(アクション)があり、不足しているアクションはPythonやJavaScript等と連携することも可能で、組み合わせ次第で可能性は無限大です。
すべてを紹介するのは難しいので、今回はブラウザとエクセルを連携させ、簡単な自動化ツールのサンプルを作成します。「こんな便利機能があるんだ!」というのを知ってもらえる内容にしました。これからPower Automate Desktopを使いたい、使い始めたけれど、どんなことができるかまだいまいち掴めていないという方はぜひ参考にしてみてください。
今回作るツールの概要
今回はサンプルとして以下の機能を備えたフローを作成します。
出発駅名と到着駅名が入力されたエクセルを開き、その区間の最安料金と乗り換え回数をYahoo路線情報から取得して自動でエクセルに入力する
フロー
では一つずつフローを解説していきます!
ファイルの選択ダイアログでユーザーにファイルを選択させる
「ファイルの選択ダイアログを表示」アクションで最安料金と乗り換え回数を抽出したい駅名の入力されたエクセルファイルをユーザーに選択させます。
今回は以下の通り、タイトルとファイルフィルター(拡張子で選択させるファイルの種類を制限)を設定しました。
ファイルフィルターは*.xlsx
とすることで、拡張子がxlsx以外のファイルは選択できなくなります。
ここでユーザーが選択したファイルのパスは変数SelectedFile
に格納されます。
ファイル選択ダイアログでキャンセルされた際の処理も追加します。
キャンセルされた場合は、SelectedFile
が空白になりますので、ifのフローで if SelectedFile=''
で判定し、「キャンセルされましたので処理を中断します」というメッセージを出してフローの実行を中止します。
この時、「2番目のオペランド」を空白に設定すると以下のようなエラーが発生します。
空白ではなく%''%を設定することで空文字として判定が可能です。
エクセルを起動し、最終行を取得する
現在存在している変数は{×}をクリックし、簡単に検索できます。
ここで起動したエクセルインスタンスは変数Excellinstance
に保存されます。
「アクティブなExcelワークシートの設定」アクションで、開いたエクセルの特定のシートをアクティブにします。
シートが複数存在する場合に、どのシートを使うのかをここで指定します。
「Excelワークシートから空の列や行を取得」アクションでエクセルの最終行を取得します。
このアクションでは以下の変数が自動で生成されます。
FirstFreeColumn
最初の空の列が何列目かを取得します。今回使うエクセルの場合はE列(5列目)が最初の空の列となり、変数には5
が保存されます。
FirstFreeRow
最初の空の行が何行目かを取得します。今回使うエクセルの場合は6行目が最初の空の列となり、変数には6
が保存されます。
これでエクセルに入力されているすべての駅名を読み込む準備が整いました。エクセルの行が増えてもツール側はそれを判定することができます。
エクセルを最終行まで1行ずつループさせ読み込む
「Excelワークシートから読み取り」アクションで今回使うデータの範囲を指定します。
今回は、2行目から最終行(5行目)までをデータとして使いますので以下のように指定します。最終行には、先ほどのアクションで生成されたFirstFreeRow
を指定します。(この変数には最初の空の行である6行目が保存されていますので-1します。)
上記で指定した範囲は変数ExcelData
に保存されます。
「For each」アクションで、エクセルを最終行まで読み込みます。
「For each」アクションは、リストやデータテーブル、データ行の各行に対して繰り返し処理を行うループアクションです。
先ほど指定した範囲が保存された変数ExcelData
を「反復処理を行う値」に指定します。ループでは、1行ずつ読んだデータを変数Currentitem
に保存します。
あまり早くループさせすぎるとWebページに負荷をかけたり失敗しやすくなります。必要に応じてWaitアクションを追加してください。
Google Chromeを起動し、読み込んだエクセルデータを元にYahoo路線情報へアクセスする
出発駅の取得
「Excelワークシートから読み取り」アクションで、エクセルのどの列のどの行のデータを取得するかを指定します。
事前に設定していた変数rowCount
を先頭行として指定し、先頭列には1
を指定します。rowCount
はループの中で1ずつ加算されます。
今回は初期値が2で、最終行が5のため、4回ループされます。
ここで取得した出発駅は変数fromStation
に保存されます。
到着駅の取得
同様に事前に設定していた変数rowCount
を先頭行として指定し、先頭列には2
を指定します。
ここで取得した出発駅は変数toStation
に保存されます。
これで、出発駅と到着駅の情報の取得が完了しました。後はブラウザを起動して、Yahoo路線情報にアクセスするだけです!
「新しいChromeを起動する」アクションでGoogle Chromeを起動します。
ループの中でこのアクションを入れてしまうと、ループするたびにChromeが起動するので、ループより前に起動しましょう。
初期URLは必ず指定が必要なのですが、後で別ページに飛ぶのでここでは何を設定してもOKです。とりあえずヤフーのトップページを設定しました。
ここで起動したChromeインスタンスは変数Browser
に保存されます。
「変数の設定」アクションで、路線情報ページのURLを変数に設定する
ヤフーの路線情報のページはURLにパラーメーターを渡すことで特定の路線情報のページへアクセスできる仕組みのようです。
from:出発駅
to:到着駅
s=1:「料金の安い順で表示」
そのため、変数には以下を設定します。
https://transit.yahoo.co.jp/search/result?from=%fromStation%&to=%toStation%&s=1
先ほどエクセルから取得してきた変数fromStation
とtoStation
をURLのパラメータに入れてください。
ここでURLは変数NewVar
に保存されます。※変数名を変え忘れていたのですが、このアクションでは初期値だとNewVar
になります。わかりやすい変数名にした方が良いでしょう。
「Webページに移動します」アクションで、路線情報ページにアクセスする
先ほど設定したURLの格納されている変数NewVar
をURLの欄に入力します。これで起動したブラウザで、路線情報のページへ移動ができます。
Yahoo路線情報からデータを取得し、エクセルに入力する
「Webページからデータを抽出する」アクションを追加します。
このアクションではWebページの特定の要素内の文字列等を取得することができます。
以下、アクションの編集画面が表示されている状態で、Yahooの路線情報のページが表示された状態のブラウザを起動します。
するとライブWebヘルパーダイアログが自動で表示され、ブラウザ内の要素をマウスオーバーで選択できます。
取得したいデータの要素を見つけて、右クリックし、「要素の値を抽出」から目的のテキスト(今回は乗り換え回数と金額)を選択します。
ライブWebヘルパーダイアログは以下の状態になりますので、内容を確認します。値として168円と乗り換え1回が取得できています。
ここで取得したデータは配列形式で変数OutputData
に保存されます。
「Excelワークシートに書き込み」アクションで、取得したデータをエクセルに書き込む
このアクションでエクセルの列と行を指定してそこにデータを書き込むことができます。
書き込む値:OutputData
書き込みモード:指定したセル上
列:3(OutputData
には2列分が配列で格納されていますので、ここで3列目を指定するとそれが開始列となり、3~4列目にデータが書き込まれます)
行:rowCount
(ループで使っている変数)
最終処理(これで完了!)
「Excelの保存」アクションでデータ入力が完了したエクセルを保存し、「Webブラウザーを閉じる」アクションで今回起動したChromeを閉じます。
変数には、起動時に生成された変数を指定してください。
Excelの保存:Excelinstane
Webブラウザーを閉じる:Browser
参考
無償版と有償版の違いは?
無償版で出来ないことは以下の通りです。トリガーが使えないのが大きいですね。内容によっては有償にした方が良いかもしれません。
・トリガー・スケジュール実行
・クラウド版のPower Automateサイトとの接続
・フローの共有
・他サービスとの連携
・デスクトップフローの無人実行(PCを起動したら自動で起動するなど)
有償版の料金は1630円/月~のようです。
https://powerautomate.microsoft.com/ja-jp/pricing/
Power Automate Desktopのフローの共有
作成したフローを他の人のPCでも使いたい!という場合、無償版では共有する機能はありません。(有償版であれば可)え、ないの?って思うかもしれませんが、以下の裏技で共有が可能です。
以下の4ステップで完了です。(かんたん!)
1.作成したフローの編集画面でCtrl+Aで全選択
2.Ctrl+Cでコピー
3.メモ帳等に貼り付け
メモ帳に貼り付けると以下のようにフローが自動でコード化されます。
4.共有先に上記のデータを送付し、同じようにPower Automate Desktopの編集画面に内容を貼り付けてもらう
※注意点:上記のNo4の手順で貼り付けた際に「不明なアクション」と表示される場合があります。共有元と共有先でPower Automate Desktopのバージョンが異なっている場合に表示されるので、どちらかが古いバージョンの場合は、新バージョンにアップデートしてバージョンを合わせてから共有する必要があります。
テキストの暗号化
例えば、特定のWEBサイトにアクセスし、IDとパスワードを自動で入力し、ログインするというフローを作るとしましょう。パスワードを直接Power Automate Desktopに貼り付けるのは、セキュリティ的に心配です。
その場合は、「Webページ内のテキストフィールドに入力する」というアクションで、「テキスト」の設定を「直接暗号化されたテキストの入力」にします。
「password1」というテキストを設定していましたが、暗号化することで、このフローを他者に共有する場合にパスワードがわからなくなります。
ちなみに暗号化の設定をしなかった場合は以下のように直接パスワードが入ってしまうためセキュリティ的に危険です。特にWEBログインの自動化等を含む場合は必ず設定しましょう。
まとめ
以上、出発駅と到着駅の入力されたエクセルを開き、Yahoo路線情報のページへアクセスし、データを取得し、エクセルに書き込むフローを詳しく解説しました。
すべてがノンコードで直感的に操作できますので、慣れたらこのようなツールは短時間で作れてしまいます。一度作るとそれをベースに使いまわすこともできますので、今回お伝えした手順を参考に試してみてください!
今回のフローはコード化し以下に記載しますので、フローを作るのが面倒な方はこちらをコピペしてください。
Display.SelectFileDialog.SelectFile Title: $'''Excelを選択してください''' IsTopMost: False CheckIfFileExists: False SelectedFile=> SelectedFile ButtonPressed=> ButtonPressed
IF SelectedFile = $'''%''%''' THEN
Display.ShowMessageDialog.ShowMessage Title: $'''キャンセル''' Message: $'''キャンセルされましたので処理を中断します。''' Icon: Display.Icon.Information Buttons: Display.Buttons.OK DefaultButton: Display.DefaultButton.Button1 IsTopMost: False ButtonPressed=> ButtonPressed2
EXIT Code: 0 ErrorMessage: $'''キャンセルされましたので処理を中断します。'''
END
Excel.LaunchExcel.LaunchAndOpen Path: SelectedFile Visible: True ReadOnly: False LoadAddInsAndMacros: False Instance=> ExcelInstance
Excel.SetActiveWorksheet.ActivateWorksheetByName Instance: ExcelInstance Name: $'''乗り換え情報'''
Excel.GetFirstFreeColumnRow Instance: ExcelInstance FirstFreeColumn=> FirstFreeColumn FirstFreeRow=> FirstFreeRow
Excel.ReadFromExcel.ReadCells Instance: ExcelInstance StartColumn: 1 StartRow: 2 EndColumn: 4 EndRow: FirstFreeRow - 1 ReadAsText: False FirstLineIsHeader: False RangeValue=> ExcelData
SET rowCount TO 2
WebAutomation.LaunchChrome.LaunchChrome Url: $'''https://yahoo.co.jp/''' WindowState: WebAutomation.BrowserWindowState.Normal ClearCache: False ClearCookies: False Timeout: 60 BrowserInstance=> Browser
LOOP FOREACH CurrentItem IN ExcelData
WAIT 1
Excel.ReadFromExcel.ReadCell Instance: ExcelInstance StartColumn: 1 StartRow: rowCount ReadAsText: False CellValue=> fromStation
Excel.ReadFromExcel.ReadCell Instance: ExcelInstance StartColumn: 2 StartRow: rowCount ReadAsText: False CellValue=> toStation
SET NewVar TO $'''https://transit.yahoo.co.jp/search/result?from=%fromStation%&to=%toStation%&s=1'''
WebAutomation.GoToWebPage.GoToWebPage BrowserInstance: Browser Url: NewVar
@@timestamp: '12/17/2021 07:25:21'
@@source: 'Recorder'
@@culture: 'ja-JP'
WebAutomation.ExtractData.ExtractHandPickedValues BrowserInstance: Browser ExtractionParameters: { ^['Css Selector', 'Attribute', 'Regex', 'Column Name'], ['html > body > div > body > div > div:eq(0) > div:eq(1) > div:eq(0) > div:eq(0) > div:eq(1) > div:eq(0) > ul:eq(1) > li:eq(0) > dl > dd > ul > li:eq(1) > span', 'Own Text', '', 'Value #1'], ['html > body > div > body > div > div:eq(0) > div:eq(1) > div:eq(0) > div:eq(0) > div:eq(1) > div:eq(0) > ul:eq(1) > li:eq(0) > dl > dd > ul > li:eq(2)', 'Own Text', '', 'Value #2'] } ExtractedData=> OutputData
Excel.WriteToExcel.WriteCell Instance: ExcelInstance Value: OutputData[0] Column: 3 Row: rowCount
Variables.IncreaseVariable Value: rowCount IncrementValue: 1 IncreasedValue=> rowCount
END
Excel.SaveExcel.Save Instance: ExcelInstance
WebAutomation.CloseWebBrowser BrowserInstance: Browser