UiPathでWebページを操作するときはJavaScriptを活用しよう!

UI開発者 宇賀

こんにちは!UI開発者の宇賀です。

RPAに取り組み始めてから「1つの作業あたりにどれくらいの時間がかかって、最終的にどれくらいで終わるのか」というポイントに一層注目するようになった気がするのですが、皆さんはいかがでしょうか?

ほとんどの作業を手動で行うのと同じ手順で自動化させられることがUiPathの魅力の1つですが、人が行う作業と同じフローでなんでもUiPathだけにやらせようとするとxamlファイルの開発時間もかかりますし、UiPathの動作時間も含めて必要な時間が大きくなってしまいます。せっかくUiPathによる自動化で低稼働・高速化が計れるのですから、開発の始まりから動作完了までの時間もなるべく短縮したいですよね。

1ページの中でいくつもいくつも要素をクリックしなければならないようなケースではどうしても1回のタスク処理に時間がかかってしまうので、私はJavaScriptを利用して「クリックしたことにする方法」をとります。すると、UiPathが実際に要素を探してクリックをするというフローが省略されるため、作業終了までの時間を短縮することができます。

コードを書かずに自動処理の設計が行えるのも魅力的ですが、ループのネストが複雑になったりDOM APIを利用したほうが明らかに工数を削減できるようなケースもあるでしょう。

そこでまず今回は、UiPathでJavaScriptを活用する方法をご紹介します。

Inject JS Scriptアクティビティを活用しよう

UiPathでJavaScriptを利用するにはInject JS Scriptというアクティビティを利用します。

Inject JS Scriptアクティビティは、ScriptCodeプロパティにJavaScriptコードをそのまま記述することで、任意のページで好きなJavaScriptコードを実行させることができます。ただし、現状では値(コード)にダブルクオーテーションを含めることができないようなのでSelectorsの仕様を利用する「document.querySelector()」などと相性が悪く、そのまま記述することはあまりない印象です。また、JavaScriptファイルとxamlファイルは別々にしておいたほうが運用効率も高いでしょう。

そこで、Read Text Fileアクティビティを利用して別ファイルに用意しておいたJavaScriptコードを変数の中に格納する方法をとります。Inject JS ScriptアクティビティのScriptCodeプロパティにはその変数を読み込むように設定します。

このとき、Read Text FileアクティビティのFileNameプロパティには直接パスを記述せず、Variablesパネルで定義した変数の値として管理する方法を推奨します。アクティビティのプロパティにハードコーディングすることは避けたほうが更新しやすく感じます。スコープは状況に応じて適切な設定にしておくべきですが、設計によってはパスや、実行時に応じて書き換えるような値を格納している変数はすべてMainスコープでもいいかもしれないですね。

例えば、フロントエンドBlogの記事が1つでも公開された年月を集計してみる

※ あくまでも、UiPathでワークフローを設計するよりもJavaScriptを利用したほうが早いことがあるという視点の例です。
※ 利用するブラウザはGoogle Chromeです。Open Browser(またはAttach Browser)アクティビティの「BrowserType」をChromeに設定してください。

2018年8月現在、https://www.mitsue.co.jp/knowledge/blog/frontend/のページを開くと2014年から2018年までの記事への導線が置かれているディスクロージャーウィジェットが存在します。それぞれ年を押下することで、そのときに記事が公開された月一覧が展開され、その先は月別の記事一覧になっています。

ここから記事が公開された年月を取得する、というxamlファイルを生成するのは少々時間がかかりますが、JavaScriptを利用すればあっという間に作業が終わります。

具体的には、たったこれだけのコードをInject JS Scriptで実行して出力されたテキストをGet Textアクティビティで読み取るだけで完了します。

() => {
    'use strict';

    let result = '';

    document.querySelectorAll('#local_nav a:not([href="#"])').forEach((a) => {
        result += a.innerText + '<br>';
    });

    document.body.innerHTML = '<p id="RPA_RESULT">' + result + '</p>';
};

似たような作業をして結果をブラウザから取得したい、といったプロセスを用意する場合、出力結果を表示するための要素には固有のIDを付与するルールで設計していくとUiPathが当該要素を見つける際のセレクタもまとめて流用できることが多いため、おすすめです。

なお、例に挙げたJavaScriptコードが匿名即時関数ではなく、1つの関数であることは重要です。

_clientFunc is not a function

Inject JS Scriptアクティビティは、受け取るJavaScriptコードを1つの関数として受け取るようで、普段の慣れで匿名即時関数を渡してしまうと「_clientFunc is not a function」というエラーを吐きます。

どうしても匿名即時関数を渡したい場合はTry Catchアクティビティの中にInject JS Scriptアクティビティを入れておき、Catchesで中身が空の「System.Exception」を1つ用意しておくか、匿名即時関数で関数をreturnすることでこの問題は解消します。

(() => {
    'use strict';

    let result = '';

    document.querySelectorAll('#local_nav a:not([href="#"])').forEach((a) => {
        result += a.innerText + '<br>';
    });

    document.body.innerHTML = '<p id="RPA_RESULT">' + result + '</p>';

    return function () {};
})();

さて、いかがでしたでしょうか?UiPath単体でも非常に強力ですが、JavaScriptなどのほかの技術を合わせて活用することで、もっともっと生産性を高めることができる気がしてきますよね。

今回はInject JS Scriptアクティビティの利用方法とちょっとした例のご紹介でしたが、次回は実際にWebページを操作する際に使えるJavaScriptの活用方法をご紹介したいと思います。お楽しみに!