【UiPath Studio】多様なWEB画面を１つのワークフロー実装で操作できるか、実験してみる。

# はじめに

これまで対象のWEBシステムごとにワークフローの実装は分けていることが多いはずです。
これは見た目は似ているサイトでも内部構造（HTMLなど）は全く異なることに起因します。
このように、人間は無意識にできることでもプログラムとして実現するのは難しい、ということは多々あります。

当記事はこの課題にチャレンジしてみます。
タイトルの通り対象のWEBシステムに関わらず **実装を共通化できないか** という試みです。

過去にコードを使って似た試みを実施しており、
コード実装の場合はプログラミングそのものであり、コードの共通化は可能であろうことが確認できています。

https://qiita.com/moripo/items/c9c19eb54a0e83f9cf48

今回は**ローコード実装**の場合…、という条件を設定した上でのチャレンジです。

コード実装の場合は、WEB画面ごとにオブジェクトリポジトリが必要でした。
ローコード実装においてもオブジェクトリポジトリを利用すれば実現可能かもしれませんが、当記事ではオブジェクトリポジトリを使わない前提のアイデアを試してみます。

現実的には、全ての共通化＆自動化は難しいです。
まずは **よくある文字の入力欄のみ** に絞って概念実証します。
よくあるの文字の入力欄とは、例えば下図のような画面要素です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/a68c6190-e244-08f1-c1e5-7c7511c3fd68.png)

:::note
記事の内容の実装は```Studio v24.10```を利用しています。
:::


# どのように設計していくか（要件定義 編）

今回の目的である **多様なWEB画面の実装を共通化** していくにあたり何を整理すれば良いでしょう。

## 多様なWEB画面の共通点を考える

処理を共通化する上で、**"各WEB画面において何が共通していると言えるか"** を定義することにしました。

今回は、下図の❶と❷の2パターンのような構成となるケースが多いであろう、という仮説を立てました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/5cd9b6cb-2fb7-f48d-34a0-3ee371256185.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/82fb17b7-db1d-207f-75c1-b03e109b3c29.png)

## これらの要素をUiPathセレクターはどのように認識しているか

見た目上で共通である内容が、UiPathのセレクターの認識メカニズム上も共通である必要があります。
そこで、UiPathのセレクターも調査してみました。
いくつかのWEBサイトを調査した結論を記載しますと、以下の傾向が共通していると言えそうです。

#### 入力欄のラベル部分は ```tag='LABEL'``` となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/ec6990a2-6983-38c4-5718-7a6058f86677.png)

#### 入力欄は ```tag='INPUT'``` となっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/ec5ad08c-9aa9-82df-69d1-bf1710f53174.png)


:::note
今回共通化の対象とするWEB画面はここで整理した内容に合致するWEB画面のみです。例外があった場合、改めて共通する事項の整理が必要になります。
:::

# どのように実装していくか（設計 編）

実装するにあたり、考えを整理した内容を記載しています。

## 人がどのように判断しているか、を考えて実装に反映する

#### １．人の操作 

1. 私たちは画面上のラベル部分を見て入力項目を判断します。（例えば、「ここにE-mailアドレスを入力するのだな」と判断します）
1. そして近くにある入力欄に入力操作をします。
1. 項目に対して入力する内容は操作者の頭の中にあります。

上記、「人の操作」の流れを設計に反映します。このとき、先のセレクター（tag）の調査結果も加味します。

#### ２．実装の設計へ反映

1. 画面全体のラベル（```tag='LABEL'```）の一覧を出力します。
1. 上記の近くにある入力欄（```tag='INPUT'```）をラベルに対応する入力要素とします。
1. 項目に対して入力する内容はあらかじめ提供される前提とします。


:::note
概念実証的な試みなので画面内の全ラベル、全入力欄に対して操作を試みる設計としました。

実際の運用としては、呼び出し元が入力したいラベル名と入力する値を指定し、意図した要素のみへ操作がされれば良いはずです。
:::


## 実際に使用するアクティビティはこちら

これまでの情報を横目にアクティビティを参照していたところ、以下のアクティビティが利用できそうでした。

### １．「子要素を探す」アクティビティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/ecb05315-9b8b-ff01-49a5-9cb52143be8d.png)

要素の子供を検索するアクティビティです。
画面要素の子供を辿って、LABELの一覧を出力することができそうです。

### ２．「相対要素を探す」アクティビティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/f975fe28-5ad0-7981-f997-9de11823d561.png)


指定した要素と位置情報を渡すことで、指定した要素を基点とした要素を取得できます。
LABEL要素を指定して、近くにあるINPUT要素を取得できそうです。

# 実装イメージはこちら（実装 編）

すべてのソースの貼り付けは難しく、あくまで参考画像による実装イメージのご紹介に留まります。

## １．LABEL一覧の出力

「要素をさがす」で以下の要素を探し、「子要素を探す」に見つかった親の要素（UiElement）を渡しています。
`<html app='chrome.exe' url='https://*' /><webctrl tag='BODY' />`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/e225629e-7686-e55d-b712-0a7aeee46d2f.png)


##### 「子要素を探す」アクティビティのプロパティ
- `FindScope.FIND_DESCENDANTS` を指定することで、親要素の子要素を一気に取得できます。
- フィルターに`"<webctrl tag='LABEL'/>"` を指定しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/21879764-b473-482d-321d-4273749c5923.png)

:::note
フィルターを設定すると膨大な画面構造が絞られるため高速化します。フィルターの書き方に注意が必要です。上図のような表現で期待通りの挙動になりました。
:::

:::note
この処理を応用すれば、画面要素の調査が半自動的にできそうです。
フィルターを調整することで、実際の画面を見なくとも画面の要素の全体像を把握することができます。
:::


## ２．LABELに近いINPUTの特定
実際の実装は少々複雑になってしまいました。概念だけのご紹介です。

基点の要素（今回はLABEL）を軸に、オフセット値で指定した距離にある要素を取得できる「相対要素を探す」を使っています。

##### 「相対要素を探す」アクティビティのプロパティ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/40667400-6122-445e-94a0-37879cd79da5.png)
要素の位置は不明なので、繰り返しの中で5pxずつ要素をチェックするようにしてみました。
（検索したい方向によって、XかYの変数を変化させながら呼び出します）

:::note
いろいろと試した結果、
**横方向**への検索は```BottomRight```を基点として上方向へ５ほど訂正```（Y:-5）```し、**下方向**への検索は```LeftBottom```を基点として右方向へ15ほど訂正```（X:+15）```しています。

この訂正が無いと要素の検索が空振りしました。入力欄の要素の外側を検索してしまうようです。（訂正値は検証の余地あり…です）
:::

縦方向、横方向の検索をパラメータで指定できるようにして１つの部品としています。
呼び出し側で、縦方向検索の呼び出し…、見つからなければ続いて、横方向の検索呼び出し…と実行するイメージです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/18873a1a-460f-34e1-e8ff-9fbc19cbb41f.png)


# 検証結果はこちら（テスト 編）
実際の実装は上記で紹介した部品を中心とし組み合わせながら呼び出して実行しています。

## １．RPA ChallengeのLABEL一覧

https://www.rpachallenge.com/?lang=JA

画面上の見た目と同様のラベルが取得できています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/d0657fdd-f48b-ea26-b70e-a1ba739ff9a4.png)

:::note
この検証によって気づいたのですが、どうやら複数LABELのうち最初のaanameが無いという仕様のようです。この仕様によるセレクター認識の不都合はありませんでした。
:::

## 入力処理の検証はこちら

さらに入力欄に、LABELのセレクターの一部を入力するように実装してみました。
検証のポイントとしては、**ワークフロー実装には手を加えず、開いているWEB画面に入力操作がされていく** 点です。



#### １．RPA Challenge
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/562dd0c8-af29-f48c-76ec-9be951459aae.png)

#### ２．デモサイトのInvoice入力画面

https://acme-test.uipath.com/

入力欄が多いのでこのシステムでの検証を選定ています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/464bbdf4-1d05-6eea-2e7f-7a3245dff71f.png)

#### ３．デモサイトのサプライヤー入力画面

https://www.rpasamples.com/suppliers?locale=jp

:::note warn
基本的な画面は期待通りでした。
**NGケース**も確認するために、設計時に考慮していない画面も追加検証しました。
アップロード、プルダウン、日付入力などは設計時に想定していません。こういった要素に対応するにはあらためて設計・検証が必要です。
:::

おおよその入力は出来ているようにも見えます。
内部的にLABELをidで要素特定していたため、LABELのidを入力するように微修正しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3302589/a6ed57ed-c131-5fd2-c96a-aa970a0b622f.png)

一部課題のようなものは見えたものの、概ね期待した操作が実現できたのでは…と思います。

# おわりに
記事のタイトルの課題についてチャレンジしてみました。

都度、要素を検索する挙動になるので、通常のローコード実装の場合よりも速度は劣ります。
ただ実装の手軽さというメリットを考えると、利用可能なレベルの速度だと感じます。（ご参考：10項目程度で数秒～十数秒程度）

応用を前提としたアイデアですので、どこが有用なのかはイメージしづらいかもしれません。
ポイントは、以下の２つの実現可能性があることが分かったという点です。

1. 目に見えるLABEL文字列を指定した入力操作ができる。 
2. ワークフロー実装を共通化できる。

応用例も紹介していきたいと思います。
LABEL指定、入力値の指定などを外部ファイル（引数、Excel等）で与えることで、さまざまな応用ができるはずです。
当記事の内容が 何らかの参考になれば幸いです。