昨日の続き、W3C WebDriver APIについてザザザーっと勉強しました。
思ったより仕様の量が多くて、、、1つづつコマンド検証しながら進めてると時間かかりますねー。
気を取り直して、地道にいきましょう。
前提条件
- 前回に引き続き、PowerShellプロンプトには以下の関数だけロードしている状態で検証を進めていきます。
- 元ネタはW3C WebDriver APIを参照しながら、ChromeDriverで進めていきます。
- コマンド単位でうまく動かないところがある場合は、Driverのバージョンを確認してみましょう。
# Uriと連想配列を渡してJsonでPostするfunction function Post-JsonContent($postUri,$body) { $json = $body | ConvertTo-Json -Compress $JsonBody = [Text.Encoding]::UTF8.GetBytes($json) return Invoke-RestMethod -Method POST -Uri $postUri -Body $JsonBody -ContentType application/json }
1.HTML要素操作の基本。
HTML要素には、elementIdっていう定数が割り振られて制御されている様です。
sessionIdと一緒でHTML要素のid属性とは別なのでDriverから取得して利用していきます。
取得されたタグ要素が編集可能なインプット要素ではない場合、pointer-eventsという属性がnoneで返る様だ。
要素検索の方法は、表を参照。
JavascriptのquerySelectorAllみたいな指定でもいけるみたいだ。
RPAツールだと、ほぼXPath使う様になってるのにねー
CSS selectorは、純粋にJavascriptのquerySelectorAll使う要領でセレクタ指定できる。
- Link text selectorは、aタグに限定してリンクラベルの完全一致検索。
- Partial link text selectorは、aタグに限定してリンクラベルの部分一致検索。
- Tag nameは、getElementsByTagNameの要領でタグ名検索。
- XPath selectorは、RPAでもお馴染みのXpath記法による検索。
さっそく、使い方を見ていきましょう。
要素の検索(Find Element)
リクエスト
(POST) http://localhost:9515/session/{sessionId}/element
bodyのusingで検索方法キーワードを指定して、valueで検索内容を指定する。
取得結果は、value.ELEMENTとしてelementIdが取得される。
検索結果でヒットする要素がなかった場合、以下のエラーが出る。
必ずステータスをチェックしてから要素に対するアクションに移ろう。
status : 7
message : no such element: Unable to locate element
# CSS selectorの場合 $body = @{using="css selector";value="div.textwidget p a"} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body
# Link text selectorの場合 $body = @{using="link text";value="RPA風のvbsめーかー"} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body
# Partial link text selectorの場合 $body = @{using="partial link text";value="RPA風"} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body
# XPath selectorの場合 $body = @{using="xpath";value='//*[@id="custom_html-2"]/div/div/p/a'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body
4例とも、同じリンクラベル要素を取得する指定方法です。
いろんなアプローチがあっていいですねぇ。
要素の取得に失敗した時の通知の為に、メッセージボックス使える様にする関数宣言しとく。
ほんで、結果は必ずstatusをチェックして成功していた場合だけelementId取得して後続処理したいからStatusチェック関数作っておく。
以降の検証で、このCheck-OnErrorStop多用してきます。
Add-Type -AssemblyName System.Windows.Forms function Check-OnErrorStop($chk_res) { If($chk_res.status -ne 0){ $errmsg = "停止します。よろしいですか?`r`n" + $chk_res.value.message $ans = [System.Windows.Forms.MessageBox]::Show($errmsg,"要素の取得に失敗","YesNo","Exclamation","Button1") If($ans -eq "Yes"){ exit }Else{ return $false } }Else{ return $true } }
さて、これで以降のelementIdを使う処理はこの塊の中に書いていく。
If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT # ここにelementId使う処理を入れる。 }
複数要素の検索(Find Elements)
リクエスト
(POST) http://localhost:9515/session/{sessionId}/elements
# CSS selectorの場合 $body = @{using="css selector";value="div.textwidget"} $elm_uri = $uri + '/elements' $rsp = Post-JsonContent $elm_uri $body
セレクタで複数ヒットした場合は、value要素が配列になって配列の中に連想配列が入って返る。
value={@{ELEMENT=elementId},@{ELEMENT=elementId},...}の形なので取り出し方注意。
要素の中から要素を検索(Find Element From Element)
リクエスト
(POST) http://localhost:9515/session/{sessionId}/element/{elementId}/element
$body = @{using="xpath";value='//*[@id="custom_html-2"]/div/div'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $body = @{using="link text";value="RPA風のvbsめーかー"} $elm_uri = $uri + '/element/' + $elmId + '/element' $rsp = Post-JsonContent $elm_uri $body }
基本的には、CSS SelectorとかXpathの使い方マスターしてたら使わないと思うんだけど。。。
一応、動くことは確認した。
要素から複数要素を検索(Find Elements From Element)
リクエスト
(POST) http://localhost:9515/session/{sessionId}/element/{elementId}/elements
$body = @{using="css selector";value='aside.front-page-widget-area'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $body = @{using="tag name";value="section"} $elm_uri = $uri + '/element/' + $elmId + '/elements' $rsp = Post-JsonContent $elm_uri $body }
いつ使いたい場面が来るのかわかんないけど、特定の1つの要素の子要素から複数要素の検索、動いた。
取れ方は、普通にelementsで検索するのと変わんねっす。
アクティブ要素の取得(Get Active Element)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/active
$elm_uri = $uri + '/element/active' Invoke-RestMethod -Uri $elm_uri
選択状態になっている要素のelementIdが取れた。
アクティブが取れなかったら no such element エラーが出るって書いてあるけど
なんか、どっかんかのアクティブには見えないa要素がアクティブ化されててエラーは発生させられなかった。。。
状態の取得に関する機能
選択状態の取得(Is Element Selected)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{elementId}/selected
$body = @{using="xpath";value='//*[@id="lit_str"]'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/selected' $rsp = Invoke-RestMethod -Uri $elm_uri }
直前でアクティブ要素取得したから混乱するけど、SelectedはInput要素のチェック状況とかの方ね。
inputおよびtextarea以外のタグはSelectedに対して常にFalseを返すよ。
要素属性の取得(Get Element Attribute)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{element id}/attribute/{name}
$body = @{using="xpath";value='//*[@id="lit_str"]'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/attribute/type' $rsp = Invoke-RestMethod -Uri $elm_uri }
タグ属性が取得できました。。。うん。
要素プロパティの取得(Get Element Property)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{element id}/property/{name}
$body = @{using="xpath";value='//*[@id="lit_str"]'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/property/value' $rsp = Invoke-RestMethod -Uri $elm_uri }
一瞬、ん?属性?プロパティ?ってなった。
DOMで、要素.id とか 要素.value で取得できるのがプロパティで
getAttribute('属性名')で取得できるのが属性なんだって。
getAttribute('id')でも取得できるじゃんって思ってたけど、実は挙動や振る舞いが違うらしい。
本筋とは違うけど、知らんかった・・・。
要素のCSS値を取得(Get Element CSS Value)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{element id}/css/{name}
$body = @{using="xpath";value='//*[@id="variable"]'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/css/line-height' $rsp = Invoke-RestMethod -Uri $elm_uri }
んー、CSS値の取得はびみょーにブラウザの開発コンソールと取れ方が違うみたいだ。
line-height取ってみたら、開発者コンソールでは1.5ってでたのに21pxって取れた。
結果、同じ意味なんだろうけどね。使いどころがよーわからん。
要素テキストの取得(Get Element Text)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{element id}/text
$body = @{using="xpath";value='//*[@id="custom_html-2"]/div/div/p/a'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/text' $rsp = Invoke-RestMethod -Uri $elm_uri }
これはラベルとか本文とか、取得する時にめっちゃ使いそう。
なんか、注意が記載されてる。a要素のlink textとpartial link textで既知の不具合がどうとか・・・。
ちょいと詳しい不具合の詳細が原文から汲み取れないけど、とりあえず後方互換にも配慮した最善適用だと?
要素タグ名の取得(Get Element Tag Name)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{element id}/name
$body = @{using="xpath";value='//*[@id="custom_html-2"]/div/div/p/a'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/name' $rsp = Invoke-RestMethod -Uri $elm_uri }
ん?タグはわかってた上でSelector書いていると思うんだけど、タグ取得したいシーンっていつだろ?
要素の位置サイズを取得(Get Element Rect)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{element id}/name
$body = @{using="xpath";value='//*[@id="custom_html-2"]/div/div'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/rect' $rsp = Invoke-RestMethod -Uri $elm_uri }
valueに@{height=xxx; width=xxx; x=xxx; y=xxxx}が取得できたよ。
要素の有効化状況取得(Is Element Enabled)
リクエスト
(GET) http://localhost:9515/session/{sessionId}/element/{element id}/enabled
$body = @{using="xpath";value='//*[@id="literal_str"]'} $elm_uri = $uri + '/element' $rsp = Post-JsonContent $elm_uri $body If(Check-OnErrorStop($rsp)){ $elmId = $rsp.value.ELEMENT $elm_uri = $uri + '/element/' + $elmId + '/enabled' $rsp = Invoke-RestMethod -Uri $elm_uri }
True/Falseで有効化状態が取得されます。これもinputとtextareaだけの属性かな?
タグ要素情報の取得だけで結構なボリュームになったので、一旦ここで切って、次回からタグ要素への操作編に入っていきます!
「W3C WebDriver APIをPowerShell制御まとめ②」への3件のフィードバック