17
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

子供を条件にして親を選択するときXpathをどう書く?

Last updated at Posted at 2020-04-15

問題

以下のようなHTMLで「次へ」ボタンをクリックする挙動を再現するために、aタグをクリックさせたいとします。「次へ」という文字列を使いXPathで検索をかけると、どうしても//div/a/span/span[contains(text(), '次へ')]のようになってしまい、aタグを選択することができません。

だからといって、divタグより上のタグで検索をかけると、//div/a[2]のようにマジックナンバーを使って何番目の要素か指定したり、//div/a[last()]のようにHtmlタグのツリー構造に強く依存するなど、苦渋の決断を強いられてしまいます。

<div class="ui-controlgroup-controls">
    <a href="url1" data-role="button" data-theme="f" data-corners="true" data-shadow="true" data-iconshadow="true" data-wrapperels="span" class="ui-btn ui-btn-up-f ui-shadow ui-btn-corner-all ui-first-child">
        <span class="ui-btn-inner">
            <span class="ui-btn-text">前へ</span>
        </span>
    </a>
    <a href="url2" data-role="button" data-theme="f" data-corners="true" data-shadow="true" data-iconshadow="true" data-wrapperels="span" class="ui-btn ui-btn-up-f ui-shadow ui-btn-corner-all ui-last-child">
        <span class="ui-btn-inner">
            <span class="ui-btn-text">次へ</span>
        </span>
    </a>
</div>

その手があったか

OctoparseのXpath紹介ページ「XPathとは?XPathの基本知識を学ぼう!」を読んでいて、解決方法を思いつきました。その時の画像です。
image.png
ピンクの下線で強調した//li[a]//a[contain(text(), 'Next')]を組み合わせると、//li[a[contain(text(), 'Next')]]となることに気が付いたのです。

ここまで気が付けば後は簡単です。

import selenium
from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.common.keys import Keys
from time import sleep

options = ChromeOptions()
# options.add_argument('--headless')

driver = Chrome(options=options)

#

url = "??????? this is url ?????????"
driver.get(url)
# sleep(0.5)

input_element :selenium.webdriver.remote.webelement.WebElement
# 施設空き状況

input_element = driver.find_element_by_css_selector("施設空き状況ボタンのCSSセレクタ")
input_element.click()
# sleep(0.5)

# sleep(0.5)

input_element = driver.find_element_by_css_selector("地域からボタンのCSSセレクタ")
input_element.click()
# sleep(0.5)

# sleep(0.5)

input_element = driver.find_element_by_xpath("//a[span[span[contains(text(), '次へ')]]]")
input_element.click()
# sleep(0.5)

"//a[span[span[contains(text(), '次へ')]]]"としましたが、今回のHTMLの場合は"//a[span/span[contains(text(), '次へ')]]"でも同様の結果が得られますね。

また、「次へ」という文字列を使って判別していますが、例えば、クラス指定で//a[span/span[@class='ui-btn-text']]とか、idがあれば、//a[span/span[@id='next-button']]などもできそうです。

Xpathは本当に便利です。Xpathに感謝です。

別の方法 (2020/5/14 追記)

この記事で対象にしているHTMLでは、以下のXPATHはすべて同じ結果となります。

  • "//a[span/span[contains(text(), '次へ')]]"
  • "//a[span[span[contains(text(), '次へ')]]]"
  • "//a/span/span[contains(text(), '次へ')]/../.."
  • "//a/span/span[contains(text(), '次へ')]/parent::*/parent::*"
  • "//a/span/span[contains(text(), '次へ')]/parent::node()/parent::node()"
  • "//a/span[span[contains(text(), '次へ')]]/.."
  • "//a/span[span[contains(text(), '次へ')]]/parent::*"
  • "//a/span[span[contains(text(), '次へ')]]/parent::node()"

参考にしたページ

#working-with-xpaths

  • Windows 10
  • Miniconda 3
  • Python 3.8.2
  • Selenium 3.141.0
  • Chrome Driver 80.0.3987.106

PythonとSeleniumのバージョンさえ同じであれば、挙動は同じだと思われます。

Excelsior!

17
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?