我如何在Selenium WebDriver (Python)中找到包含特定文本的元素?

我试图用Selenium测试一个复杂的JavaScript接口(使用Python接口,并跨多个浏览器)。我有一些按钮的形式:

<div>My Button</div>

我希望能够搜索基于“我的按钮”的按钮;(或不区分大小写的部分匹配,如“my button”;或“button")。

我发现这非常困难,以至于我觉得我错过了一些明显的东西。到目前为止,我所拥有的最好的东西是:

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

但是,这是区分大小写的。我尝试的另一件事是遍历页面上的所有div,并检查元素。文本属性。然而,每次你得到这样的情况:

<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 web驱动程序是这样。

想法吗?


我问(并回答)一个更具体的版本在这里:如何在Selenium WebDriver中获得一个元素的文本,不包括子元素文本?< / >

793903 次浏览

您可以尝试这样的XPath表达式:

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

试试下面的方法:

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

试试这个。这很简单:

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

在Selenium WebDriver中,这真的很管用。

你也可以在页面对象模式中使用它,例如:

试试下面的代码:

@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;
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"));

根据文本对元素的不区分大小写搜索使用driver.find_elements_by_xpath匹配正则表达式匹配函数。

driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")

//*将寻找任何HTML标记。如果一些文本是常见的按钮和div标签,如果//*是类别,它将无法正常工作。如果你需要选择任何特定的,那么你可以通过声明HTML元素标签来获得它。如:

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

有趣的是,几乎所有的答案都围绕着XPath的函数contains(),忽略了它是敏感的的事实——与OP的要求相反。

如果需要不区分大小写,可以在XPath 1.0 (当前浏览器支持的版本)中实现,尽管不是很漂亮——通过使用translate()函数。它通过使用转换表将源字符替换为所需的形式。

构造一个包含所有大写字符的表将有效地将节点的文本转换为小写()形式——允许不区分大小写的匹配(这只是特权):

[
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(用于正则表达式搜索,带有不区分大小写('i')标志)。

类似的问题:查找<button>Advanced...</button>

也许这将给你一些想法(请将概念从Java转移到Python):

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

在你提供的HTML中:

<div>My Button</div>

文本My ButtoninnerHTML,它周围没有空格,所以你可以很容易地使用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>

在这种情况下,你有两种选择:

  • 你可以使用contains()函数来确定第一个参数字符串是否包含第二个参数字符串,并返回布尔值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 + "']")

简单地使用这个:

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

如果使用c#

ChromeOptions options = new ChromeOptions();
var driver = new ChromeDriver(options);
var urlLink = "https://www.pexels.com/tr-tr/arama/do%C4%9Fa/";
driver.Navigate().GoToUrl(urlLink);
Thread.Sleep(10000);
var divList = driver.FindElementsByXPath(".//div[contains(@class,'hide-featured-badge')]");
foreach (var divItem in divList)
{
var photoOwnerName = divItem.FindElement(By.XPath(".//span[@class='photo-item__name']")).GetAttribute("innerHTML");
}