xpathについてのtips
idやclassが設定されていないページで多様するxpath
selenium webdriverのコードを実装していく時にソースコードを見てidやclassが振られていれば良いのですが、
そんなにこちらの都合に合わせて作ってくれていないWEBページはよくあります。
そんな時にどうしても使わなければならないのがxpathです。
今回はそんなxpathで実装する際のtipsをいくつかご紹介したいと思います。
classにスペースが含まれるとエラーになる場合
classが複数振られている場合、ソース上はclass毎にスペース区切りで書かれています。
1 |
<div class="class1 class2 class3 class4" |
このような時に以下のように実装するとエラーが表示されてしまいます。
1 2 3 |
driver.find_element(:class, 'class1 class2 class3 class4') # => invalid selector: Compound class names not permitted |
直訳すると「無効セレクタ:複合クラス名は許可されていません」ですね。
こんな時はxpathで書けばOKです。
書き方はこんな感じ。
1 |
driver.find_element(:xpath, '//*[@class="class1 class2 class3 class4"]') |
これで問題なく要素を取得できます。
xpathの中に*(アスタリスク)を入れる
以下のようなxpathの時
1 |
//*[@id="topics"]/div[1]/ul[1]/li[1]/a |
違う権限のユーザーで見たり、項目が追加されたりしてxpathが変わることがあります。
if文などで条件分岐をさせてxpathを都度変えても良いのですが、*(アスタリスク)を使うことによって全ての条件で要素を取れることがあります。
例えば
1 2 3 4 5 |
//*[@id="topics"]/div[1]/ul[1]/li[1]/a //*[@id="topics"]/div[1]/ul[2]/li[1]/a //*[@id="topics"]/div[1]/ul[3]/li[1]/a |
このようにul[]の中の値が条件によって変わる場合は以下のようにするとどの条件下でも要素を取得できます。
1 |
driver.find_element(:xpath, '//*[@id="topics"]/div[1]/ul[*]/li[1]/a') |
さらにli[]部分が複数ある場合は*を入れることで全ての要素を配列として取得できます。
1 |
elements = driver.find_elements(:xpath, '//*[@id="topicsfb"]/div[1]/ul[*]/li[*]/a') |
find_elementsになっていることに注意してください。これはfind_elementと違って複数の要素を取得するためのものです。
この場合、elemensには配列が返ってきますので、それぞれの要素を操作したい場合はeachを使うと良いでしょう。
例えば、今回は複数のaタグを取って来ているので、リンク先を取得したい場合はこんな感じ。
1 2 3 4 5 6 7 |
# 配列links links = [] # elementsをeachで回してlinksに追加する elements.each do |el| links << el.attribute("href") end |
これですべてのリンク先がlinksの中に配列として格納されました。
xpathを文字列として連結する
これはもうわかっている人も多いと思いますが、文字列を連結してxpathを書くこともできます。
使用するシーンとしては、xpathの中にuser_idやcomment_idなどが含まれることがある時、
その可変のidを変数などに入れておいてxpathに埋め込むという感じ。
以下のようなxpathになっている場合
1 |
//*[@id="user_0001"]/div[1]/ul[1]/li[1]/a |
0001が可変になるとすると数値部分がIDになっているのでIDをどうにか変数に入れて以下のように連結することができます。
1 2 3 4 5 |
# 変数idにIDを入れる id = "0001" # 変数xpathに文字列を連結して入れる xpath = '//*[@id="user_' + id + '"]/div[1]/ul[*]/li[1]/a' |
本来のxpathの中で””(ダブルクォート)が使用されているため、それを囲むようにシングルクォートを使用していることに注意してください。
そして以下のようにすれば要素を取ることができます。
1 |
driver.find_element(:xpath, xpath) |
簡単ですね。
以上になります。
xpathはDOMの変化に弱いので、本来は使用を推奨されていないのですが、
それでも使わなければならない時があるかと思います。
find_elementで使えるfinderについては以下のページにまとまっていますので参考にしてみてください。
Module: Selenium::WebDriver::Find — Documentation for selenium-webdriver (0.0.28)