Selenium Webdriver(Python)で特定のテキストを含む要素を見つけるにはどうすればよいですか?


259

Seleniumで複雑なJavaScriptインターフェースをテストしようとしています(Pythonインターフェースを使用して、複数のブラウザー間で)。次の形式のボタンがいくつかあります。

<div>My Button</div>

「My Button」(または「my button」や「button」などの大文字と小文字を区別しない部分一致)に基づいてボタンを検索できるようにしたい

私はこれが驚くほど難しいことに気づき、明らかな何かを見逃しているように感じます。私がこれまでに持っている最高のものは:

driver.find_elements_by_xpath('//div[contains(text(), "' + text + '")]')

ただし、これは大文字と小文字が区別されます。私が試したもう1つのことは、ページ上のすべてのdivを反復処理し、element.textプロパティを確認することです。ただし、次のような状況になるたびに:

<div class="outer"><div class="inner">My Button</div></div>

div.outerにも、テキストとして「My Button」があります。これを修正するために、div.outerがdiv.innerの親であるかどうかを確認しようとしましたが、それを行う方法を理解できませんでした(element.get_element_by_xpath( '..')は要素の親を返しますが、テストはdiv.outerと等しくありません)。また、ページ上のすべての要素の反復処理は、少なくともChrome Webdriverを使用すると、非常に遅くなります。

アイデア?

編集:この質問は少し漠然と出てきました。より具体的なバージョンをここで尋ねました(そして答えました):子要素のテキストを含めずに、(Python APIを介して)Selenium WebDriverで要素のテキストを取得する方法は?


現在の答えは私にはうまくいきませんでした。これは次のとおり
alejandro

回答:


328

以下を試してください:

driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")

3
お返事ありがとうございます。それは私が必要とするものの50%でした(始めました)。私がたどり着いた形式は、この "(// * [contains(text()、 '" + text + "')] | // * [@ value = '" + text + "']))です。要素ノード内だけでなく、テキストが 'value'属性を介して設定された入力要素内の指定されたテキスト、つまり<button value = "My Button" />。ただし、値はテキストだけではなく、厳密に一致している必要があります。
Ivan Koshelev 2014年

9
他の検索エンジンの訪問者にも言及する価値があります。リンクを探している場合はfind_element(s)_by_link_textfind_element(s)_by_partial_link_text方法があります
Dan Passaro 2014年

3
テキストが動的な場合はどうなりますか?つまり、引用符が含まれている可能性があります。それはこのソリューションを壊しませんか?
IcedD​​ante 2015

3
特定の名前を検索すると、これがうまくいかないようです。例として、次の例を考えてみてください。その後、xpathは無効になります。これを回避する方法はありますか?
坂本和馬

対象テキストが複数行の場合は動作しないようです。
Shawn、

29

あなたは次のようなxp​​athを試すことができます:

'//div[contains(text(), "{0}") and @class="inner"]'.format(text)

おかげで...それは内部と外部を区別するのに役立ちますが、それは実際にはxpathでうまく機能し、私はすべてのdivを反復処理するという問題のみを抱えていました。xpathに関する私の問題は、大文字と小文字を区別しないようにする方法を理解できないことですか?
josh

2
xpath 2.0には小文字の関数があるため、これは機能するはずです: '// div [contains(lower-case(text())、 "{0}")]'。format(text)
andrean

ありがとう!しかし、私の理解では、xpath 2.0は主要なブラウザーではサポートされていません...
josh

seleniumは、ブラウザーの独自のメソッドを使用してxpath式を直接評価するため、seleniumで使用しているブラウザーによって異なります。通常、6、7、8のみがxpath 2.0をサポートしません。
andrean 2012

.format私の日食では認識されません。それは与えるとエラー。どんな考え、なぜ?
anujin 2013

16

ページオブジェクトパターンと一緒に使用することもできます。例:

このコードを試してください:

@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;

13

// *はHTMLタグを探します。一部のテキストがボタンとdivタグに共通であり、// *がカテゴリの場合、期待どおりに機能しません。特定のものを選択する必要がある場合は、HTML要素タグを宣言することで取得できます。お気に入り:

driver.find_element_by_xpath("//div[contains(text(),'Add User')]")
driver.find_element_by_xpath("//button[contains(text(),'Add User')]")

5

興味深いことに、実質的にすべての回答はxpathの関数を中心に展開されcontains()、大文字と小文字が区別されるという事実を無視します-OPの要求とは逆です。
大文字と小文字を区別する必要がある場合は、xpath 1.0 (最新のブラウザがサポートするバージョン)で実現できますが、このtranslate()関数を使用することで、きれいではありません。変換テーブルを使用して、ソース文字を目的の形式に置き換えます。

すべての大文字のテーブルを作成すると、ノードのテキストがそのlower()形式に効果的に変換され、大文字と小文字を区別しないマッチングが可能になります(ここでは特権のみです)

[
  contains(
    translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'my button'
  )
]
# will match a source text like "mY bUTTon"

完全なpython呼び出し:

driver.find_elements_by_xpath("//*[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZЙ', 'abcdefghijklmnopqrstuvwxyzй'), 'my button')]")

当然、このアプローチには欠点があります-与えられたように、それはラテン語のテキストに対してのみ機能します。Unicode文字をカバーする場合は、それらを変換テーブルに追加する必要があります。上記のサンプルではこれを行いました"Й"。最後の文字はキリル文字です。


そして、ブラウザーがxpath 2.0以上をサポートする世界に住んでいた場合(🤞、しかしすぐには発生しません☹️)、関数lower-case()(まだ、完全にロケールに対応しているわけではありません)、およびmatches(正規表現検索では、大文字と小文字を区別) -insensitive('i')フラグ)。


3

あなたが提供したHTMLで:

<div>My Button</div>

テキストMy ButtonはでありinnerHTML、周囲に空白がないためtext()、次のように簡単に使用できます。

my_element = driver.find_element_by_xpath("//div[text()='My Button']")

text()コンテキストノードのすべてのテキストノードの子を選択します


先頭/末尾にスペースがあるテキスト

先頭に空白を含む関連テキストを大文字にします:

<div>   My Button</div>

または最後に:

<div>My Button   </div>

または両端で:

<div> My Button </div>  

これらの場合、2つのオプションがあります。

  • contains()次のように、最初の引数文字列に2番目の引数文字列が含まれているかどうかを判別し、ブール値trueまたはfalseを返す関数を使用できます。

    my_element = driver.find_element_by_xpath("//div[contains(., 'My Button')]")
  • normalize-space()文字列から先頭と末尾の空白を取り除き、空白文字のシーケンスを単一のスペースで置き換え、結果の文字列を次のように返す関数を使用できます。

    driver.find_element_by_xpath("//div[normalize-space()='My Button']]")

可変テキストのxpath

テキストが使用できる変数の場合:

foo= "foo_bar"
my_element = driver.find_element_by_xpath("//div[.='" + foo + "']")

1
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(), 'YourTextHere')]")));
    assertNotNull(driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")));
    String yourButtonName=driver.findElement(By.xpath("//*[contains(text(), 'YourTextHere')]")).getAttribute("innerText");
    assertTrue(yourButtonName.equalsIgnoreCase("YourTextHere"));

1

同様の問題:検索 <button>Advanced...</button>

多分これはあなたにいくつかのアイデアを与えるでしょう(JavaからPythonに概念を移してください):

wait.until(ExpectedConditions.elementToBeClickable(//
    driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();


-19

これを試して。それは超簡単:

driver.getPageSource().contains("text to search");

これは、セレンWebドライバーで本当にうまくいきました。


9
テキストがJavaScriptによって生成されている場合は機能しません。
palacsint

2
これは、ページのコンテンツ全体をネットワーク経由で転送するため、これをチェックする非常に方法です。非常に小さいページの場合はこれで十分ですが、非常に大きいページの場合は、ファイルのすべてのコンテンツを転送してサーバー側でチェックします。より良いアプローチは、xpath、javascript、またはcssを使用してクライアント側で実行することです。
thomas.han 2014

ブラウザがレンダリングするためには、ページのソース全体がすでにネットワーク経由で転送される必要があると思いますか?
ルネ・

3
Joshは、テキストがページのソースに存在するかどうかをテストするのではなく、テキストで要素を見つける方法を求めています。
セドリック

1
ページ上で静的テキストを見つけることがすべて必要な場合は、このソリューションで十分です。(それは私の場合に役立ちました)。
Karlth、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.