339

我正在尝试使用 Selenium 测试一个复杂的 JavaScript 界面(使用 Python 界面,并跨多个浏览器)。我有许多形式的按钮:

<div>My Button</div>

我希望能够根据“我的按钮”(或不区分大小写的部分匹配项,例如“我的按钮”或“按钮”)搜索按钮。

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

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

但是,这是区分大小写的。我尝试过的另一件事是遍历页面上的所有 div,并检查 element.text 属性。但是,每次您获得以下形式的情况时:

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

div.outer 也有“我的按钮”作为文本。为了解决这个问题,我尝试查看 div.outer 是否是 div.inner 的父级,但我无法弄清楚如何做到这一点 (element.get_element_by_xpath('..') 返回一个元素的父级,但是它测试不等于 div.outer)。

此外,遍历页面上的所有元素似乎真的很慢,至少使用 Chrome 网络驱动程序。

想法?


我在这里询问(并回答)了一个更具体的版本:How to get text of an element in Selenium WebDriver, without include child element text?

4

12 回答 12

421

尝试以下操作:

driver.find_elements_by_xpath("//*[contains(text(), 'My Button')]")
于 2013-09-09T14:54:21.080 回答
36

您可以尝试使用 XPath 表达式,例如:

'//div[contains(text(), "{0}") and @class="inner"]'.format(text)
于 2012-09-07T18:44:23.693 回答
34

在您提供的 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 + "']")
于 2020-01-11T20:54:29.203 回答
28

//* 将寻找任何 HTML 标记。如果某些文本对于 Button 和 div 标签是常见的,并且如果 //* 是类别,它将无法按预期工作。如果您需要选择任何特定的,那么您可以通过声明 HTML Element 标记来获取它。喜欢:

driver.find_element_by_xpath("//div[contains(text(),'Add User')]")
driver.find_element_by_xpath("//button[contains(text(),'Add User')]")
于 2018-12-17T10:18:10.113 回答
16

您还可以将它与页面对象模式一起使用,例如:

试试这个代码:

@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;
于 2017-01-17T09:44:50.467 回答
9

有趣的是,几乎所有答案都围绕 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 字符 - 您必须将它们添加到翻译表中。我已经在上面的示例中做到了 - 最后一个字符是 Cyrillic symbol "Й"


如果我们生活在一个浏览器支持 XPath 2.0 及更高版本的世界中(但不会很快发生☹️),我们可以使用这些函数lower-case()(但是,不是完全支持区域设置),并且matches(对于正则表达式搜索,在这种情况下) -insensitive ( 'i') 标志)。

于 2019-01-29T08:53:41.253 回答
4

只需使用这个:

driver.find_elements_by_xpath('//*[text() = "My Button"]')
于 2021-01-19T06:50:09.673 回答
3

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

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

wait.until(ExpectedConditions.elementToBeClickable(//
    driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();
于 2019-05-13T22:16:24.300 回答
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"));
于 2017-08-11T16:27:23.393 回答
0

使用driver.find_elements_by_xpath匹配正则表达式匹配函数,以通过其文本对元素进行不区分大小写的搜索

driver.find_elements_by_xpath("//*[matches(.,'My Button', 'i')]")
于 2018-08-30T12:47:59.337 回答
0

如果使用 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");
}
于 2021-06-27T16:36:08.433 回答
-20

尝试这个。这很容易:

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

这在 Selenium WebDriver 中确实对我有用。

于 2014-02-07T14:54:18.360 回答