🦄

SeleniumなしでWebDriverを操作するには - Part2

2021/11/07に公開
2

SeleniumなしでWebDriverを操作するには

はじめに

前回

ブラウザで表示されているエレメントを操作するには

WebDriverでブラウザのエレメントを操作する場合はエレメント特有のIDが必要です。
特定のエレメントIDを取得する場合は以下に示されるエレメントの特徴をPOSTで渡すことが重要になります。

using keyword
CSS selector css selector
Link text selector link text
Partial link text selector partial link text
Tag name tag name
XPath selector xpath

エレメントに関する基礎知識

CSS Selector

CSS(カスケーティングスタイルシート)で利用できる属性を指定します。
具体的には以下のようなHTMLがあるとき CSS Selector は [type="button"] となります。

<input type="button" value="ココをクリック">

なお、WebDriverではvalue属性もCSS Selector として選択できる為
[value="ココをクリック"] でも有効です。

リンクテキスト、つまりはアンカータグに利用できるSelectorのことです。
aタグで括られている文字列を指定します。

Link text selector の部分文字列版

TagName

文字通りタグ名のこと

XPath selector

取得対象までのパスをスラッシュ区切りで書く。
これが一番とっつきにくそうでわかると一番やりやすい?かも

例:pタグを取得

/html/body/div/p

エレメントのプロパティとは

結論から語るとinnerHTMLchildren などのElement に関する情報が取得できる項目のこと
細かいことはMDN の Element のプロパティにありますので
具体的にエレメントとは何なのかは語りません。
とりあえず、エレメントはオブジェクトであるという認識で良いでしょう。

フレームという概念

昔のHTMLではframeとそれを束ねるframeset があり、比較的新しいHTMLについてはiframe(インラインフレーム)が使われます。
WebDriverではフレーム内のドキュメントを取得するとき、スイッチという動作を事前に行う必要があります。

ブラウザオートメーションで代表的なフレームワーク、Seleniumがわかる人であれば
SwitchToFrame を実行すると言えばわかるかもしれない。

フレームにスイッチしてタグを取得

フレームは画面に描画されたタイミングでそれぞれ固有の番号みたいなものを持っており
基本的には左から0,1,2 と数えていけば良いです。
※Seleniumの場合はこのあたりのことを良しなに制御してくれているので意識する必要はないです。

WebDriverで同じことをやる場合はwindowにスイッチする時と同じ要領でやれば、簡単にできます。

エンドポイント:http://localhost:9515/session/{sessionId}/frame
メソッド:POST
リクエスト用のJSON※最初に描画されたframe を取得する場合

{
    "id":0
}

スイッチしたらwindowにスイッチしなおすようにしましょう。
Windowにスイッチする方法はPart1で記載しております。

ちなみにこのスイッチ先のことをW3Cではコンテキストと表記しています。
コンテキストにスイッチすることでフレームを捉えることができるということですね。

※Selenium ではデフォルトコンテキストにスイッチすることで同じことができます。

エレメントを操作

エレメントIDを取り出すときのポイント

エレメントIDを取り出す時は定数値のキーを用いる必要があります。
具体的にはelement-6066-11e4-a52e-4f735466cecfです。

エレメントを探す - CSS selector

エンドポイント:http://localhost:9515/session/{sessionId}/element
メソッド:POST
リクエスト用のJSON ※type 属性がbutton のとき

{
    "using":"css selector",
    "value":"[type=\"button\"]"
}

※ここで渡すvalueはSeleniumのfind_elements_by_css_selectorメソッドの引数と同じ

実行に成功した場合は以下のような形式で一番最初にヒットしたエレメントのIDをJSONで返します。

{
    "value": 
    {
        "element-6066-11e4-a52e-4f735466cecf": "{エレメントID}"
    }
}

エレメントを探す - tag name

エンドポイント:http://localhost:9515/session/{sessionId}/element
メソッド:POST

リクエスト用のJSON ※取得したいタグ名がinputのとき

{
    "using":"tag name",
    "value":"input"
}

実行に成功した場合は以下のような形式で一番最初にヒットしたエレメントのIDをJSONで返します。

{
    "value": 
        {
            "element-6066-11e4-a52e-4f735466cecf": "{エレメントID}"
        }
}

複数のエレメントを探す - CSS selector

FindElementと類似の機能にFindElements という機能があります。
FindElements は複数のエレメントIDを返します。
渡すデータやメソッドタイプに違いはありませんがエンドポイントが違うので利用時はエンドポイントを間違えないようにしましょう。

エンドポイント:http://localhost:9515/session/{sessionId}/elements
メソッド:POST
リクエスト用のJSON ※type 属性がbutton のとき

{
    "using":"css selector",
    "value":"[type=\"button\"]"
}

※ここで渡すvalueはSeleniumのfind_elements_by_css_selectorメソッドの引数と同じ

実行に成功した場合は以下のような形式で該当する全てののエレメントIDをJSONで返します。

{
    "value": [
        {
            "element-6066-11e4-a52e-4f735466cecf": "エレメントID-1"
        },
        {
            "element-6066-11e4-a52e-4f735466cecf": "エレメントID-2"
        }
    ]
}

複数のエレメントを探す - tag name

エンドポイント:http://localhost:9515/session/{sessionId}/elements
メソッド:POST

リクエスト用のJSON ※取得したいタグ名がinputのとき

{
    "using":"tag name",
    "value":"input"
}

実行に成功した場合は以下のような形式で該当する全てののエレメントIDをJSONで返します。

{
    "value": [
        {
            "element-6066-11e4-a52e-4f735466cecf": "エレメントID-1"
        },
        {
            "element-6066-11e4-a52e-4f735466cecf": "エレメントID-2"
        }
    ]
}

Find Element と Find Elements の違い

FindElement は最初にヒットしたエレメントのみを返しますが
FindElements は検索条件にヒットした全てのエレメントを配列で返します。

Find Elementの場合

{
    "value": {
        "element-6066-11e4-a52e-4f735466cecf": "0f1afb14-4601-4719-a2e1-9b1f322976a4"
    }
}

Find Elementsの場合

{
    "value": [
        {
            "element-6066-11e4-a52e-4f735466cecf": "0f1afb14-4601-4719-a2e1-9b1f322976a4"
        },
        {
            "element-6066-11e4-a52e-4f735466cecf": "bd5e4f62-57a8-48c0-b457-997b5231784a"
        }
    ]
}

画面上に一つしかないという要素であれば、FindElementで特定できますが
同じ要素が複数現れる場合は要素を限定してあげる必要があります。

後述しますが、WebDriverにはエレメントIDからエレメントの属性と属性値を調べる機能が存在します。
もし、確実に特定の要素だけをクリック/選択/コピーしたい場合はGet Element系のメソッドと組み合わせることで
特定の要素を確実に操作するように調整できます。
このあたりは次のPart3 で語ります。

エレメントのプロパティを取得

エンドポイント:http://localhost:9515/session/{session id}/element/{element id}/property/{name}
メソッド:GET

エレメントが持つ項目を取得する時に利用します。
例えば、innerHTMLchildren がエレメントのプロパティに相当します。

pタグのエレメントIDを取得して以下のようなHTMLからinnerHTMLを取得する例

<html>
    <head>
        <title>test</title>
    </head>
    <body>
        <p>innerHTML</p>
    </body>
</html>
{
    {"value":  "innerHTML"}
}

エレメントの属性を取得

エンドポイント:http://localhost:9515/session/{session id}/element/{element id}/attribute/{name}
メソッド:GET

タグに付与されている属性値を取得します。
name 属性で属性値testの時のエンドポイントは

エンドポイント:http://localhost:9515/session/{session id}/element/{element id}/attribute/name

実行に成功した場合は指定した属性値ををJSONで返します。

{
    "value": "test"
}

Webスクレイピングをするにあたっての基本

ここまで
WebDriverをウィンドウのコントロールやエレメントの操作まで解説してきましたが

Webスクレイピングの基本としては以下のような動作があります。

  • 取得
    • 要素の状態を取得
    • ページソースを取得
  • 入力
    • UIクリック
    • テキストを入力
  • 出力
    • ファイル出力
  • ウィンドウ操作
    • ウィンドウハンドルを取得
    • ウィンドウタイトルを取得
  • パース
    • HTML
    • XML
    • JSON
  • スクリプトの実行
    • JavaScriptの同期実行
    • JavaScriptの非同期実行

ここまでの内容とWebリクエストメソッドに関する知識だけでモダンブラウザを活用したWebスクレイピングが実現できます。
Part3 からは実際にプログラムを書いてWebDriverによるスクレイピングをやっていきます。

おわり

Part3 に続く

Discussion

makochimakochi

とても勉強になりました!!
Part3 熱望しております!!

daichi005daichi005

同上です。cookieの追加(add-cookie)、promptにテキスト送信(send-alert-text)の実装に躓いています。何卒。