わんすけに聞いてみる PowerShell W3C WebDriver APIをPowerShell制御まとめ②

W3C WebDriver APIをPowerShell制御まとめ②

昨日の続き、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件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

Related Post