指定タグの指定テキストをクリックもHTML構造を選ぶ
これの姉妹スレです。
https://winactor.com/questions/question/「指定テキストをクリック」はhtml構造を選びがち/
「指定テキストをクリック」でも「指定タグの指定テキストをクリック」でもうまくクリックできないケースを複数見かけました。
https://winactor.com/questions/question/chromeでラジオボタンを選択したい/
検証を経て、原因の1つを掴みました。
伏線を回収しつつ、情報のお裾分けです。
結論
- 「指定タグの指定テキストをクリック」でクリックできないケースがある
- うまくいかない場合は、一意になるXPathを特定して、「クリック」を使うべし
原因の記述は★周辺です。
最下部の⭐︎について、ヒント等があれば教えてください。
見立て
- 「指定タグの指定テキストをクリック」は、
このXPathで目的の要素が一意にヒットすれば成功する
//*[contains(text(),"指定テキスト")]/ancestor-or-self::指定タグ
|
//*[contains(@value,"指定テキスト")]/ancestor-or-self::指定タグ
- ※ 指定テキストを存在しないテキストにして、エラー画面でXPathのひな形を把握
Yahoo!JAPANトップページでテスト
- span
- 不動
→ Yahoo!不動産に遷移した
深堀り
- DevToolsからこのXPathを検索
//*[contains(text(),"不動")]/ancestor-or-self::span
|
//*[contains(@value,"不動")]/ancestor-or-self::span→ 2ヒット
→ DevToolsでは改行ありのままペーストしても機能した
→ 外側と内側のspanがヒットした
<span>
<span>不動産</span>
</span>
リファレンス
図解!XPathでスクレイピングを極めろ!
https://ai-inter1.com/xpath/#st-toc-h-34
自身も含めた先祖要素の取得: ancestor-or-self
「指定タグの指定テキストをクリック」のXPath解釈
- text()か@valueが指定テキストのいずれかの要素(1つめ)
で
自身か上位の指定タグ
気になった点
- 難しそうなXPathは、使い慣れてる表記と何が違うのか
難しそうなXPath
//*[contains(text(),"指定テキスト")]/ancestor-or-self::指定タグ
使い慣れてる表記
//指定タグ[contains(text(),"指定テキスト")]
Yahoo!JAPANトップページでDevToolsからXPathの検索結果
//*[contains(text(),"不動")]/ancestor-or-self::span
→ 2つのspanがヒット
//span[contains(text(),"不動")]
→ 内側のspanだけがヒット
「クリック」でテスト
→ どちらもYahoo!不動産に遷移した
テスト結果を踏まえた見立て
- 合致する範囲で外側最上位の指定タグを制御することのメリットがあるはず
- ショベルカーでガバっと広く掴むメリットとは?
- むしろデメリットがありそうな予感
ancestor-or-selfの深堀り
- UserForumにもspanの入れ子がある
- 左メニューの※Coming Soon
//*[contains(text(),"※Coming Soon")]/ancestor-or-self::span
//span[contains(text(),"※Coming Soon")]
- 各スレッドの回答数/いいね数のゼロとか
//*[contains(text(),"0")]/ancestor-or-self::span
//span[contains(text(),"0")]
- Yahoo!不動産はページ内に1か所だったけど、UserForumの例はそもそも複数ある要素
- 2つだけのComing Soonの一方をDevToolsでSome Timeに書き換えればComing Soonは1つになる
- Coming Soonはマウスオンで表示される要素だし、クリックしても画面遷移を伴わないから、挙動を見届けにくい
- 回答数のゼロは画面遷移を伴う
- 回答数が多めで1つしかない数字なら一意(今なら6が一意)
//*[contains(text(),"6")]/ancestor-or-self::span
//span[contains(text(),"6")]
- と思いきや、各スレッドのビューn件にどの数字も含まれがち
- WWW上のサンプルなら意思疎通しやすいと考えたものの行き詰まる
- いずれにしろわたしがWinActor環境から検証できる範囲は限られる
- どなたかが手頃なサンプルサイトを見つけて切り込んでくれたら嬉しい
思い立って自前でページでテスト
※ メモ帳に貼り付けて、UTF-8で「テスト.html」として保存
<html>
<head>
<title>テスト</title>
</head><body>
<span>
<a href="https://www.yahoo.co.jp">
<span>クリックしたいテキスト</span>
</a>
</span></body>
</html>
- ※ 2つあるspanのうち1つめのspanの中身全体が、クリックで画面遷移を伴うa要素
「クリック」
//*[contains(text(),"テキスト")]/ancestor-or-self::span
//span[contains(text(),"テキスト")]
→ どちらもYahoo!JAPANに遷移した
body内を変更
<span>
ああ<br>
<a href="https://www.yahoo.co.jp">
<span>クリックしたいテキスト</span>
</a>
</span>
- ※ 2つあるspanのうち1つめのspanの中身に、クリックで画面遷移を伴うa要素以外を含む
「クリック」
//*[contains(text(),"テキスト")]/ancestor-or-self::span
→ クリックはエラーなく完了するものの、画面遷移が起こらない
- ※ ヒットした2つのうち1つめのspan要素としての「ああ<br>」をクリックしたためと思われる★
- これがわたしの懸念の正体っぽい
- 「指定タグの指定テキストをクリック」で期待した挙動にならない症状の原因の1つ
//span[contains(text(),"テキスト")]
→ Yahoo!JAPANに遷移した
使い慣れてるXPathのかたちなのですんなり入ってくる
更に変更
<span>
<a href="https://www.yahoo.co.jp">
<span>クリックしたいテキスト</span>
</a><br>
ああ
</span>
- ※ 2つあるspanのうち1つめのspanの中身に、クリックで画面遷移を伴うa要素以外を含む(a要素が先頭)★
「クリック」
//*[contains(text(),"テキスト")]/ancestor-or-self::span
//span[contains(text(),"テキスト")]
→ どちらもYahoo!JAPANに遷移した★
まとめ
- 「指定タグの指定テキストをクリック」はancestor-or-selfが使われている
- ancestor-or-selfは、合致する祖先を原始まで辿って1つめの要素をターゲットにする
- 2つのXPathのどちらかでターゲットが一意にヒットしない場合や、
//*[contains(text(),"指定テキスト")]/ancestor-or-self::指定タグ
//*[contains(@value,"指定テキスト")]/ancestor-or-self::指定タグ
一意にヒットした要素内の1つめがクリック対象でない場合は、
「指定タグの指定テキストをクリック」で期待した挙動は得られない - 「指定タグの指定テキストをクリック」がうまくいかない場合は、一意になるXPathを特定(あるいはソースを提示してUserForum等で質問)して、「クリック」を使うべし
検証後記
- ancestor-or-selfの特徴と使いかたを学ぶ良い機会だった
- 「指定タグの指定テキストをクリック」でancestor-or-selfが使われてるメリットの特定には至らず
- 今回検証した範囲では、//指定タグ[contains(text(),"指定テキスト")]スタイルはすべて想定通りの挙動だった
- XPathで2つ以上ヒットする場合に(XPath)[2]みたいな工夫が必要なのはどちらも同じ
- わたしではここまでが限界
⭐︎知りたい欲
- 「指定タグの指定テキストをクリック」のXPathがancestor-or-selfであることのメリット
- 「クリック」で使う場合に、「//指定タグ[contains(text(),"指定テキスト")]」でうまくいかないケース
[参考]「指定テキストを含む」の複数条件
XPath基礎編(3) ー XPathによく使う関数 - Qiita
https://qiita.com/Octoparse_Japan/items/400030227aaa0a5ebac2//a[contains(@href,”M_”) or contains(@href,”L_”)]
検証結果も加味すると、「指定タグの指定テキストをクリック」のXPathはこれでも良さそう。
//指定タグ[contains(text(),"指定テキスト") or contains(@value,"指定テキスト")]