RPAツール関係のお話が2017年からぐわっと盛り上がっていますが、実際の所このRPAと呼ばれるツール群やその話題は昔からあったもので、いわばペンキ塗り替えでRPAと称して再登場してるものです。代表的なものはExcelのマクロやVBA、UWSCといった自動化ツール、またウェブ操作系のデバッグツールとしては、Seleniumなどなど。

今までは事務方が現場で自分のために部分最適化の一例として細々と実践してたものなのです。ASPSaaSと名を変えてリバイバルしたようなものです。ちょっと前まで「Excelマクロで楽するなんてずるい」とか言ってた時代だったのに、変わったものです。さて、そんなRPAですが、Excel VBAでどこまで行けるのか?まとめてみました。

今回使用するファイル

※今回のサンプルはSeleniumBasicは参照設定ではなく、実行時バインディングでコードを記述してあります。

Excel VBAで他のアプリを操作する

SendKeysを使った手法

問題点と解消法

最もポピュラーでこれまでもよく利用されていた手法です。キーボードの操作をプログラムのコードで送りつけて、アプリケーションを操作します。ショートカットキーなども利用出来るのですが、いくつかの問題点があって、結構癖があり扱いにくいです。問題点は

  1. コピペなどの場合、マクロ側でコピーをしたものでないとコピーがうまく動かない
  2. 一方的にキーを無造作に送りつけるので、起動が遅いとか処理が間に合わなくても送ってしまう
  3. 実行中に下手に操作すると、アクティブウィンドウが変わって、そちらにキーを送ってしまう
  4. 印刷ダイアログなどではショートカットキーが効かない
  5. ESCキーを送りたい場合、マクロが途中停止する事がある。
  6. NumLockが外れることがある

コピペはCtrl+C, Ctrl+Vだとうまく動かない時には、VBAでクリップボードにコピーする関数を間に挟んで処理をする。日本語の文字化け処理に対してもこの方法は有効です。

処理が間に合わない場合にはスリープを入れてあげる。Win32 APIを使うので冒頭で宣言が必要です。

印刷ダイアログ等では、ショートカットキーではなく、TABキーやスペースキー(” “)、Enterキーなどを組み合わせて送ってあげます。例えば、TABを6回、スペースを1回ならば

ESCキーはマクロの停止と被るので、これをまずは受け付けないようにブロックしておく

NumLockがオフになったりする現象がバグとして公式で報告されています。これが鬱陶しいのでこの場合には、NumLockをSendkeysで送ってしまうか?こちらのサイトで紹介されてるような、NumLockの状態を取得して必ずオンになるようにするコードを追加してみる。

基本、SendKeysを使うようなVBAの場合、実行中は操作してはいけません。

サンプルコード

今回は、「irfanviewを起動し、特定フォルダ内の画像を全てBMP形式で特定のフォルダに変換して保存する」といった処理をSendKeysで作ってみました。sleepをさせるコードと特殊フォルダのパスを取得する関数を別に用意してあります。

※SHGetFoldPathは特殊なフォルダパスを取得する為のルーチンです。

※StopTimeはミリセカンド単位でsleepをさせる為のルーチンです。

※事前にデスクトップにsaveとkinokoというフォルダを作っておき、kinokoフォルダに画像類を入れておく必要があります。

実行してみた

WSHのSendKeysを使った手法

概要

VBAのSendKeysメソッドはバグがあるということで、避けている人が代替としてよく利用しているのがこの手法。同じSendKeysなのですが、Windows Scripting Hostと呼ばれるスクリプト実行環境版です。これをVBAから利用します。参照設定より、「Microsoft Scripting Runtime」を追加すればOKですが、一時的に使用したいような場合には、CreateObjectで呼び出すのも良いでしょう。

※但し、VBAではWindows Scripting HostのSleepは使えません。また、書き方は殆ど同じですが、()で括る点やRunでアプリを起動させる時にProgram Filesのような半角スペースを含むものは、パスの渡し方がちょっと独特です。

サンプルコード

SendInputを使った手法

概要

SendKeysを送る手法のバグ対策の為に、WSHを使った手法を使いました。それ以外にもWindows APIを使ったSendInput関数を使ったキーの送信方法があります。但しこの手法は素のやり方でコードを書くと非常に煩雑になるので、こちらのサイトを参考にして、キー送信部分を関数化しておくと、扱い易くなります。

素の状態でコードを組んだ時、SendInputの場合はキーを押す&キーを離すといった動作まで細かく定義をしなければなりません。簡単にコピペとした場合でも、Ctrlキーを押す⇒Cキーを押す⇒Ctrlキーを離す⇒Cキーを離す⇒(何かの移動処理)⇒Ctrlキーを押す⇒Vキーを押す⇒Ctrlキーを離す⇒Vキーを離すといった処理を事細かに書かなければなりません。

※キーをいちいち作成するわけなのですが、例えばCtrlキーを押してそのままにしておくと、ずっとOSレベルで押しっぱなしの状態になるのでややこしいことになります。キーを作る時には注意が必要です。必ずCtrlキーをアップして開放してあげなければなりません。

※Altキーなどに秀Capsなどのキーボードショートカットコマンドを割り当てていると、反応してうまく動作しない事があります。常駐させている場合には注意が必要です。

サンプルコード

今回のサンプルコードはこちらのサイトの関数化されたプロシージャを利用しています。また、今回使用する分のキーコード定数だけを宣言しているので、他のキーコードを使う場合には追加で宣言に足してあげる必要があります。冒頭の宣言関係やキーコード定数は省略して記載しています。

また、特殊フォルダのパスの取得やirfanviewの起動に関してはWindows Scripting Hostを利用しています。clipman関数はクリップボードにデータを保存するための自作の関数です。

解説

SendInputは冒頭ジェネラルプロシージャ内で、別途宣言が必要になります。WindowsのAPIであってVBAの機能ではないので、必ずこれは必要になります。以下のような宣言文です。

今回利用させていただいたSendInputを簡略化して使える関数を利用すると、非常に楽にキーストロークの組み合わせを作って送信する事ができます。ひとつ注意したい点は、ALT(Menu)キーやCtrlキーについては、キーダウンとアップのキーコード定数が異なります。間違えるとOSレベルで押されっぱなしになり、再起動するまで解除されません。VK_CONTROL_DOWNの後には必ず、VK_CONTROL_UPでキーを送りましょう。

また、キーボード以外にもマウス操作も可能ですが今回は使用しませんでした。

プロシージャ内で送り込みたい文字列などはクリップボード関数でまずコピーしておき、Ctrl+Vを送るようなコマンドを送ると良いでしょう。今回も開くフォルダ、保存先フォルダの2つで利用しています。

コマンドラインで操作する手法

概要

これまでの操作は、人間がマウスやキーボードを操作する流れを、忠実にキーコードを送信して実現し、アプリケーションを操作する手法でした。最近はそれほど多くなくなりましたが、かつてのプログラムはGUIと同時にコマンドラインでも操作できるように実装されてるものがありました。irfanviewもそのうちの1つです(今はAPIのほうが主流ですね)。

IrfanViewのコマンドライン・オプション一覧を見て、コマンドプロンプトで入力すればCUIで同じ操作が可能になります。実際に不確実な面がどうしても拭えないキーコード送信よりも、100%確実に結果が期待できるコマンドラインのほうが結果的には面倒が少ないとも言えます。VBAからはWindows Scripting Hostを使ってコマンドプロンプトへコマンドラインを送り込んで実行可能です。これまでと同じ操作のコマンドラインを組んでみました。

*.*で対象フォルダ内にある全てのファイルが対象になり、$N.jpgで同じファイル名で拡張子がbmpのファイルに、/convertオプションでバッチ変換をする命令文です。

サンプルコード

※wshshell.execでコマンドラインを実行しているのですが、”%ComSpec% /c “はおまじないみたいなものです。comstrで組み立てたコマンドラインで、非常に高速に処理が完了します。

SeleniumBasicでウェブアプリを操作する

Seleniumとは、ウェブアプリケーションのデバッグテストなどで使用してる、自動テストを行わせる為のツールです。ブラウザを操作してくれるので、これそのものでもRPA的な使い方も可能です。しかし、VBAからブラウザ操作はあまりにも面倒な上に、昔のIEの操作に関するものが殆どで、現代的なものではありません(今更IEを使う事もないですし、Edgeを使う気にはなれないですし)。

そこで使用するのが、Selenium Basic(旧Selenium VBA)です。Chromeなどのブラウザも操作可能になりますが、その代理をしてくれるのが、SeleniumBasicです。

セットアップ

SeleniumBasicのセットアップは簡単。以下の手順でセットアップをします。

  1. 配布元に行き、Release Pageへ入る
  2. 最新版をクリックしてダウンロード
  3. ダウンロードされたインストーラを起動して適当に進める。
  4. 途中、Web Driverのインストールに関する項目がでるけれど全てそのままインストール
  5. 完了したらインストール自体は完了。

ただし、このWeb Driverが最新とは限らないので、以下の手順で最新版にすげ替える。今回はChromeで操作を考える。

  1. Chrome Driverの配布元に行き、Downloadページにゆく
  2. 最新版をダウンロード
  3. 解凍すると、exeが1個入ってる。
  4. Explorerを起動し、パスの部分に「%LOCALAPPDATA%\SeleniumBasic」を入れて移動する
  5. 3.で解凍されたexeをそのフォルダに放り込み上書きする

これで完了です。

図:インストール自体はとても簡単

実際に操作してみる

使用するには事前に「Selenium Type Library」を参照設定で入れておく必要性があります。インストールした後であれば参照設定のリストに出てくるはずです。チェックを入れておきましょう。コードの中で事前バインディングではなく、実行時バインディングで使う場合には、以下のようなコードになります。今回のサンプルは、実行時バインディングで記述してあります。

図:事前バインディングの場合参照設定をする

早速コードを書いてみます。今回は、Googleのページで「Excel 自動化」で検索をした結果を、スクリーンショットで取得して、Excelに貼り付けるといった一連のフローを書いてみます。

古いSelenium VBA時代のコードとかなり変わっているので、入力補完などを使ってメソッドは組み立てる必要があります。しっかりした作りのウェブアプリケーションであれば、ほぼログインからデータの取得まではこなせるだけでなく、ウェイトなどを駆使して、Excelのデータを元に申請などを半自動で送り込めるのではないかと思います。

※もともとはウェブアプリケーションの実行テストの為のものなので、かなり細かく挙動をコントロール出来ます。

図:自動でスクショ取って閉じてくれる

Name属性ボタンをクリックできない時の対処法

Googleのトップページなど、ボタンにはID属性がなくName属性が付けられています。このボタンをクリックさせることで検索がされるわけなのですが、Selenium BasicでClickをさせてもクリックされない事があります。こんな時用にキーコードを送ることでクリックさせたことと同じ処理を行わせる事ができます。

この場合、事前にkeysを設定する必要があります。実行時バインディングであれば

事前バインディグさせている場合であれば

冒頭が異なりますが、Keyを送る時には、Clickではなく、SendKeys(keys.Enter)で、Enterキーを送りつけています。

Headless Chromeで実行

最新のChromeはPhantomJSのようなHeadless Modeという特殊なモードを備えています。これは、Chrome自体を表示させずにバックグラウンドで非表示のブラウザを使って処理を進める為のモードです。Excelでも高速化処理の時に「Application.ScreenUpdating = False」を加えて処理を非表示にする事がありますが、似たようなものです。

Headlessで動かす場合には、Startする前にseleniumオブジェクトにオプションを指定してあげます。

実行してみると一切ブラウザを表示せずに後ろで作業が進められます。

関連リンク