【Excel VBA×Selenium】XPathのcontainsで部分一致する要素を取得・クリックする方法
みなさんこんにちは。
Excel VBA×SeleniumでWebスクレイピングをしていると、デベロッパーツールで取得したXPathをそのまま使用していたのに、ある日突然要素が取得できなくなった経験をしたことがある方も多いかと思います。
特に、Webサイト側でidやclassの一部が動的に変わる場合、完全一致で指定しているXPathでは要素を取得できなくなることがあります。
このような場合に便利なのが、XPathのcontains()です。contains()を使用すると、文字列や属性値の一部が一致する要素を検索できます。
今回は、Excel VBA×SeleniumでXPathのcontains()を使い、文字列・id・classが部分一致する要素を取得してクリックする方法についてご紹介したいと思います。
この記事はこんな人におすすめ
- XPathで指定した要素が突然取得できなくなった人
- idやclassの一部が毎回変わるWebサイトを操作したい人
- XPathのcontains()をVBA×Seleniumで使いたい人
- 表示文字の一部を使ってボタンやリンクをクリックしたい人
- 動的なXPathをできるだけ安定して指定したい人
完全一致のXPathでは取得できない場合がある
まずは、完全一致で要素を指定した場合を確認してみます。
例えば、HTMLが次のようになっているとします。
<button id="submit_12345" class="btn btn-primary">
申し込みを確定する
</button>
この要素をidの完全一致で指定する場合は、次のようなXPathになります。
//button[@id='submit_12345']
しかし、ページを開くたびにidの数値部分が変わり、次回はsubmit_67890になった場合、このXPathでは要素を取得できません。
このように、属性値の一部だけが固定で、それ以外が動的に変わる場合にcontains()が便利となります。


XPathのcontains()の基本構文
contains()は、指定した文字列が属性値やテキストの中に含まれているかを判定します。
基本的な書き方は次のようになります.
//タグ名[contains(@属性名, '検索文字')]
先ほどのsubmit_12345というidの場合は、固定されているsubmit_だけを使って指定できます。
//button[contains(@id, 'submit_')]
これなら、idがsubmit_12345でもsubmit_67890でも、submit_を含んでいれば候補として取得できます。
idを部分一致で取得する
VBA×Seleniumでは、FindElementByXPathへcontainsを含むXPathを指定します。
Sub GetElementByContainsId()
Dim driver As New Selenium.WebDriver
Dim targetButton As Selenium.WebElement
'========================================
' Chromeを起動する
'========================================
driver.Start "chrome"
'========================================
' 操作対象となるWebページを表示する
' ※URLは実際の対象ページへ変更してください
'========================================
driver.Get "https://example.com/"
'========================================
' idに「submit_」を含むbutton要素を取得する
' 数値部分が変わっても固定部分で検索できる
'========================================
Set targetButton = driver.FindElementByXPath( _
"//button[contains(@id, 'submit_')]" _
)
'========================================
' 取得したボタンをクリックする
'========================================
targetButton.Click
'========================================
' 処理完了後にChromeを終了する
'========================================
driver.Quit
End Sub
完全一致ではなく、変化しない部分だけを条件にすることで、動的なidにも対応しやすくなります。
表示文字を部分一致で検索する
contains()は属性だけではなく、要素に表示されている文字列の部分一致にも使用できます。
例えば、次のようなリンクがある場合を考えてみます。
<a href="/detail/123">商品詳細を見る</a>
「商品詳細」という文字を含むリンクを取得したい場合は、次のように指定できます。
//a[contains(text(), '商品詳細')]
VBAでは次のように記述します。
Sub ClickLinkByContainsText()
Dim driver As New Selenium.WebDriver
Dim targetLink As Selenium.WebElement
'========================================
' Chromeを起動して対象ページを表示する
'========================================
driver.Start "chrome"
driver.Get "https://example.com/"
'========================================
' 表示文字に「商品詳細」を含む
' aタグを部分一致で取得する
'========================================
Set targetLink = driver.FindElementByXPath( _
"//a[contains(text(), '商品詳細')]" _
)
'========================================
' 取得したリンクをクリックする
'========================================
targetLink.Click
'処理完了後にChromeを終了する
driver.Quit
End Sub

classを部分一致で検索する
class属性の一部を使って検索することもできます。
例えば、次のHTMLがあるとします。
<button class="button primary-button size-large">
登録する
</button>
primary-buttonを含むbutton要素を取得する場合は、次のように指定できます。
//button[contains(@class, 'primary-button')]
VBAから直接クリックする場合は、次のように記述できます。
driver.FindElementByXPath( _
"//button[contains(@class, 'primary-button')]" _
).Click
classが複数設定されている要素でも、目的の文字列が含まれていれば取得できます。
属性と文字列を組み合わせて候補を絞る
contains()は便利ですが、条件が広すぎると複数の要素が一致してしまうことがあります。
そのような場合は、タグ名や属性、表示文字などの条件を組み合わせると対象を絞り込みやすくなります。
//button[contains(@class, 'primary-button') and contains(text(), '登録')]
このXPathでは、次の2つを両方満たすbutton要素だけを対象にします。
- classに「primary-button」が含まれている
- 表示文字に「登録」が含まれている
実際のWebサイトでは同じclassを持つボタンが複数存在することもあるため、できるだけ目的の要素を特定できる条件にすることが大切です。
取得からクリックまでをまとめた実務コード
最後に、動的なidをcontains()で検索し、対象要素を取得してクリックする基本形をご紹介します。
Sub ClickDynamicElement()
Dim driver As New Selenium.WebDriver
Dim targetButton As Selenium.WebElement
Dim xpath As String
'========================================
' Chromeを起動する
'========================================
driver.Start "chrome"
'対象ページを表示する
driver.Get "https://example.com/"
'========================================
' 動的なidの固定部分を使用して
' XPathを作成する
'========================================
xpath = "//button[contains(@id, 'submit_')]"
'========================================
' XPathに一致する要素を取得する
'========================================
Set targetButton = driver.FindElementByXPath(xpath)
'========================================
' 取得した要素をクリックする
'========================================
targetButton.Click
'========================================
' 操作終了後にChromeを閉じる
'========================================
driver.Quit
End Sub
XPathを変数へ分けておくと、デバッグ時にどの条件で要素を探しているのか確認しやすくなります。

contains()を使用するときの注意点
条件を短くしすぎない
例えばcontains(@id, 'btn')のように短い文字列だけを指定すると、複数のボタンが一致する可能性があります。
可能であればsubmit_やprimary-buttonなど、その要素を特定しやすい文字列を使用してください。
text()で取得できない場合がある
要素の中にspanタグなどの子要素が含まれている場合、contains(text(), '文字列')では期待した結果にならないことがあります。
その場合は、要素全体の文字列を対象にする次の指定も確認してみてください。
//button[contains(., '登録')]
WebページのHTML構造によって使い分けることが大切となります。
一致する要素が複数ないか確認する
FindElementByXPathは条件に一致した要素のうち1つを取得するため、同じ条件に複数の要素が一致していると意図していない要素を操作する可能性があります。
ChromeのデベロッパーツールでXPathを検索し、候補が1件に絞れているか確認してからVBAへ組み込むと安心です。
過去の記事のご紹介
XPathの基本的な取得方法については、過去の記事でもご紹介しています。
デベロッパーツールからXPathを取得する手順を確認したい方は、以下の記事も参考にしてください。
また、規則性のあるXPathを使って複数の要素を取得する方法については、以下の記事でもご紹介しています。
最後に
いかがでしたでしょうか。
今回は、Excel VBA×SeleniumでXPathのcontains()を使い、文字列やid・classが部分一致する要素を取得してクリックする方法についてご紹介しました。
Webサイトによっては、idやclassの一部がページ表示ごとに変わることがあります。そのような場合は、完全一致だけではなく、変化しない部分をcontains()で指定できないか確認してみてください。
ただし、条件が広すぎると複数の要素が一致する可能性があるため、タグ名や属性、表示文字などを組み合わせて対象を絞ることが大切です。
動的なWebページから要素を取得するときに、少しでも参考になれば幸いです。
開発依頼について
ココナラでWebスクレイピング開発サービスを出品しております。
自分で開発をしようと思ったけど、VBAでのネット記事が少なく困っている方も多いかと思います。
そんな方はいつでもお気軽にご相談ください。
また、本ブログからご依頼いただいた方については割引特典がございますので、
ご不明点と合わせてメッセージをいただけると幸いです。
Excelにてブラウザ操作自動化ツールを作成します その作業、webスクレイピングを使って自動化しましょう!Webスクレイピング以外にもWebアプリの開発サービスも出品しております。
こちらについても、本ブログからご依頼いただいた方については割引特典がございますので、
お気軽にご相談ください。
スモールスケールのWebアプリ開発します 先ずはスモールスケールのWebアプリから始めませんか?
