「1.導入編」の記事に続き、RPAのセレクタの詳細内容について解説したいと思います。RPAの安定したフローを構築するには、セレクタを十分に理解しておく必要があります。先ずは、下記の3点を押さえると良いでしょう。
- 属性(Id、Class、Text、Name)
- インデックス番号(eq)
- 動的(変数埋め込み)
【検証1】一般的な場合
1-1. セレクタの形
導入編でも言及しましたが、ブラウザ上のUI要素のセレクタはHTMLのタグ名が連なった形になります。
タグ[属性="値"] > タグ > タグ > ・・・ > タグ[属性="値"]
例えば、こちらの検証用ページの【検証1】の「button2」ボタンのセレクタは下記のようになると思います。Power Automate for desktopのバージョンによっては、取得されるセレクタが異なるかもしれません。セレクタの確認方法は、導入編の「3. セレクタの確認方法」を参照してください。
section[Id="test1"] > div > ul > li > button[Text="button2"]
1-2. セレクタの経路
セレクタを理解するには、電車の経路をイメージすると分かりやすいです。左端が「出発駅」で、右端が「到着駅」です。その間に、各「通過駅」が配置されます。この経路に沿って、ターゲットのUI要素を特定します。
実際のWebページのHTMLコードとセレクタを対比しながら、どのようにターゲットのUI要素が特定されるのか順に確認していきます。ブラウザ上でHTMLコードを表示するには、F12ボタンをクリックし、選択ツールでターゲットのUI要素を指定します。
出発駅
先ずは「出発駅」がどこか確認します。基本的には出発駅はhtmlまたは任意のタグ名[Id=””]のどちらかになります。ターゲットのUI要素の祖先に特定のIDを持つ要素がある場合は、タグ名[Id=””]から始まります。そのような要素がない場合は、ルートであるhtmlから始まります。今回は出発駅は、section[Id=”test1″]です。
通過駅
出発駅から始まり、途中の通過駅を順に辿っていきます。今回の通過駅は「div」、「ul」、「li」の3つです。
到着駅(ターゲットのUI要素)
適切なセレクタであれば、最終的に「到着駅」、つまりターゲットのUI要素に辿り着きます。このUI要素をアクションで操作することになります。セレクタが不適切な場合は、到着駅に辿り着けずに、アクションでエラーが発生するかもしれません。
今回の到着駅は、button [Text=”button2″]です。タグ名はbuttonでText属性を持っています。Text属性の値は「button2」です。つまり、button2の文字列が表示されたbuttonタグを指すことになります。
1-3. 経路の必要性
ターゲットのUI要素がbutton2の文字列のボタンであるなら、セレクタは到着駅のbutton [Text=”button2″]だけでも良い気がします。確かに、対象のWebページ内に、button2の文字列のボタンが1つしかないのであれば、それでも上手くいくかもしれません。しかし、button2の文字列のボタンが複数ある場合は、最終的にどのボタンを指すか曖昧になります。
通常、類似したUI要素が複数あった場合でも、ターゲットのUI要素を正しく識別するために、セレクタは出発駅と通過駅を含む経路の形を取ります。到着駅の1点による特定よりも、経路による特定の方が信頼度は高くなります。
【検証2】ID属性のピンポイント指定
一般的に、セレクタは複数のタグが連なった形を取ります。傾向としては、セレクタが長くなるほどWebページの構造変化に影響を受けやすくなります。では、セレクタは短いほど良いのかと言うと、そうとも限りません。ターゲットのUI要素を特定するための情報量が減るため、極端に短いのも好ましくないです。
ただし、例外的にターゲットのUI要素にidがあれば、セレクタは極端に短くすることができます。idはWebページ上の要素を一意に特定できるため、セレクタが短くても特に問題ないです。
では、実際に確認してみましょう。検証用ページの【検証2】の「orange」ボタンのセレクタは下記のようになると思います。セレクタの確認方法は、導入編の「3. セレクタの確認方法」を参照してください。
button[Id="btn-orange"]
タグ名はbuttonでId属性を持っています。Id属性の値は「btn-orange」です。つまり、btn-orangeのidを持ったbuttonタグを指すことになります。とてもシンプルなセレクタになります。
実際のWebページのHTMLコードも確認してみると、「orange」ボタンの要素には「btn-orange」のidが振られているのが分かります。確かに一致しています。
【検証3】Text属性が使えない場合
【検証1】では、到着駅がbutton[Text=”button2″]でした。このText属性はターゲットのUI要素の特徴(文字列)を表すため直感的に分かりやすく、とても便利な属性です。しかし、いつでもこのText属性が使える訳ではありません。
では、実際にText属性が使えないケースを確認してみましょう。検証用ページの【検証3】の「mobile」ボタンのセレクタは下記のようになると思います。セレクタの確認方法は、導入編の「3. セレクタの確認方法」を参照してください。
section[Id="test3"] > div > ul > li > button:eq(2)
3-1. インデックス番号(eq)による指定
【検証3】のボタンにはアイコンマークの要素を付けたことにより、Text属性は使えなくなっています。その代わりに、セレクタの到着駅のbuttonには「:eq(2)」が付与されています。eqはインデックス番号を表し、0から数えます。つまり、eq(2)は3番目のボタンを指しています。実際に、ターゲットのUI要素の「mobile」ボタンは上から数えて3番目なので一致しています。
3-2. インデックス番号の注意点
Text属性が使えない場合、eqのインデックス番号の指定が使われることがあります。しかし、インデックス番号を使用する際は、少し注意が必要です。
インデックス番号の指定は、Webページの構造変化に影響を受けやすいです。セレクタの経路の途中に要素が追加または削除されると、インデックス番号が変化するので、間違った要素を指してしまうリスクがあります。
では、インデックス番号以外の方法はないのでしょうか。Id属性ほど確かではないですが、Class属性を使うことで、インデックス番号に依存せずに済みます。
3-3. Class属性による指定
では、実際にインデックス番号から、Class属性に変更してみましょう。なお、いつでもClass属性が使える訳ではありません。Webページ上のターゲットのUI要素に、明確な特徴となるclassが付与されていることが前提条件です。
先ずは、セレクタ情報の編集画面で、タグのリストの最後にある「Button ‘mobile’」を選択します。タグの属性で、Ordinal(eq、つまりインデックス番号)のチェックボックスをOFFにして、代わりにClassのチェックボックスをONにします。画面下の「セレクタをプレビューする」を確認すると、下記のようなセレクタに変化しています。
section[Id="test3"] > div > ul > li > button[Class="btn btn-mobile"]
buttonの後ろにあった「:eq(2)」が消えて、代わりに[Class=”btn btn-mobile”]が付きました。Class属性の値は、「btn」と「btn-mobile」の2つです。複数の値を付ける場合は、半角スペースで区切ります。特に重要となるのは、「mobile」ボタンの特徴を明確に表している「btn-mobile」の方です。「btn」の方は、あってもなくても特に影響はないでしょう(button[Class=”btn-mobile”]でもOK)。
実際のWebページのHTMLコードも確認してみると、「mobile」ボタンの要素には「btn」と「btn-mobile」のclassが振られているのが分かります。確かに一致しています。
3-4. Class属性の注意点
今回のように、ターゲットのUI要素に特徴のあるclassが付与されている場合は、インデックス番号の代わりにClass属性による指定が可能です。
メリットとしては、Webページの構造変化の影響を受けにくくなることです。ただし、classはidとは違い、Webページ上のUI要素を一意に特定することはできません。つまり、同じ値のclassを複数のUI要素に付けることができます。従って、ターゲットのUI要素の特徴を明確に表すclassがある場合に限り、Class属性を使用しましょう。
【検証4】Text属性が変化する場合
セレクタにText属性は使えるが、条件によって値が変化してしまうケースを確認してみましょう。検証用ページの【検証4】の日時の文字列のセレクタは下記のようになると思います。セレクタの確認方法は、導入編の「3. セレクタの確認方法」を参照してください。
section[Id="test4"] > p[Text="2024/9/12 9:23:55"]
Text属性の値に日時の文字列が含まれていることが分かります。検証用ページにアクセスする度に日時が変化するようにしているので、Text属性の値も毎回変化します。この状況ではセレクタが正しく認識されなくなってしまいます。このように、セレクタに固有情報が入ってしまうと、それ以外のケースでは合致しなくなります。つまり、融通の利かないセレクタになってしまうのです。
では、このようなケースはどのように対応するべきでしょうか。1つの方法としては、セレクタから固有情報を排除することです。しかし、セレクタの情報量を削ることは、UI要素を特定する精度が下がることを意味します。従って、別の属性を付与するなどして補ってあげる必要があります。この考え方はとても重要なので、しっかりと頭に入れておきましょう。
4-1. 固有情報の排除
日時が変化しても問題ないように、実際にセレクタを編集してみましょう。セレクタ情報の編集画面で、タグのリストの最後にある「Paragraph ‘2024/9/12 9:23:55’」を選択します。タグの属性で、Text属性のチェックボックスをOFFにします。画面下の「セレクタをプレビューする」を確認すると、下記のようなセレクタに変化しています。
section[Id="test4"] > p
到着駅のpタグのText属性が消えているのが分かります。この状況で一度、セレクタのテストを試してみましょう。上部メニューの「テスト」ボタンを押して、対象のWebブラウザのタブを指定してください。すると、Webページ上で、「下記の日時を取得してください。」のテキスト部分がハイライトされたと思います。
元々のターゲットは「日時」のテキストだったので、UI要素の認識に失敗しています。これは前述した通り、セレクタの情報量を削ったことで特定の精度が下がり、別のUI要素を誤認識してしまったのです。
4-2. 特定精度の補完
では、どのようにして特定精度を補完するのでしょうか。今回のケースでは、ターゲットのpタグのclassにtimeが振られているので、これを活用することにします。
セレクタ情報の編集画面で、タグのリストの最後にある「Paragraph ‘2024/9/12 9:23:55’」を再度選択します。タグの属性で、Class属性のチェックボックスをONにします。画面下の「セレクタをプレビューする」を確認すると、下記のようなセレクタに変化しています。
section[Id="test4"] > p[Class="time"]
この状況で、もう一度、セレクタのテストをしてみましょう。今度は、正しく「日時」のテキスト部分がハイライトされたと思います。なお、前述した通り、Class属性による指定は完璧ではないので注意が必要です。ターゲットのUI要素の特徴を明確に表すclassを使用するようにしましょう。
section[Id=”test4″] > p:eq(1)
【検証5】動的に指定する場合
実行時に動的にターゲットのUI要素を指定したいケースがあります。例えば、ユーザーから入力された値に応じて、クリックするボタンを切り替える場合などです。これを実現する1つの方法としては、セレクタに変数を埋め込み、ターゲットのUI要素を動的に変更します。
では、実際に試してみましょう。検証用ページの【検証5】のラジオボタン「ヤギ」のセレクタは下記のようになると思います。セレクタの確認方法は、導入編の「3. セレクタの確認方法」を参照してください。
section[Id="test5"] > div > label > input[Name="test"]:eq(2)
到着駅はinputタグです。これにName属性とeq(インデックス番号)が付与されています。Name属性はHTMLのinputタグのname属性のことです。値は「test」で、このラジオボタンのグループ名として付けられたものでしょう。ラジオボタンの特徴を表すものなので、Name属性はこのまま使用することにします。
問題はeq(インデックス番号)です。eq(2)は3番目なので、左から3番目のラジオボタンを指しています。確かに、「ヤギ」は左から3番目にあります。
変数の埋め込み
では、指定する項目を動的に変更するにはどうすれば良いでしょうか。1つの方法としては、eqのインデックス番号を変化させることです。eq(%num%)などのように、インデックス番号に変数を埋め込みます。ただし、インデックス番号による指定は、ラジオボタンの配置の変化に対して脆弱です。
インデックス番号よりも、動物の名前による指定の方が分かりやすいと思います。では、動物の名前による指定に変更します。セレクタ情報の編集画面で、タグのリストの最後にある「Input radio ‘test’」を選択します。タグの属性で、Ordinal(eqのこと)のチェックボックスをOFFにします。そして、Value属性のチェックボックスをONにします。画面下の「セレクタをプレビューする」を確認すると、下記のようなセレクタに変化しています。
section[Id="test5"] > div > label > input[Name="test"][Value="ヤギ"]
このままでは、毎回、「ヤギ」を選択してしまうので、Value属性の値を変数に置き換えます。タグの属性で、Value属性の値をダブルクリックして、%animal%を入力します(既に作成済みの変数を配置してもOK)。セレクタは下記のように変化します。
section[Id="test5"] > div > label > input[Name="test"][Value="%animal%"]
この状況で一度、セレクタのテストを試してみましょう。上部メニューの「テスト」ボタンを押して、対象のWebブラウザのタブを指定してください。次に、「変数を持つセレクタ」の画面が表示されます。テストする際に、毎回、変数の値を入力する必要があります。試しに、「ゴリラ」と入力してみます。すると、Webページ上で、「ゴリラ」のラジオボタンがハイライトされたと思います。何度かテストして、変数の値を変え、動的にラジオボタンが指定できるか確認してみてください。
実際に運用する際は、ユーザーからの入力値や、設定ファイルから読み込んだ値を変数に保存しておきます。そして、この変数をセレクタに反映させます。
「3.ケーススタディ編」の記事に続く。