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

How do I find an element that contains specific text in Selenium WebDriver (Python)?

提问人:josh 提问时间:9/8/2012 最后编辑:Benjamin Loisonjosh 更新时间:6/22/2023 访问量:872290

问:

我正在尝试使用 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 网络驱动程序是这样。

想法?


我在这里问(并回答)了一个更具体的版本:如何在 Selenium WebDriver 中获取元素的文本,而不包含子元素文本?

python selenium-web驱动程序

评论

1赞 alejandro 7/19/2014
目前的答案对我不起作用。这个做到了:sqa.stackexchange.com/a/2486

答:

42赞 andrean 9/8/2012 #1

您可以尝试如下所示的 XPath 表达式:

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

评论

0赞 josh 9/8/2012
谢谢。。。所以这有助于区分内部和外部,但这实际上适用于 xpath,我只是在遍历所有 div 时遇到了这个问题。我对xpath的问题是我无法弄清楚如何使其不区分大小写?
2赞 andrean 9/8/2012
XPath 2.0 有一个小写函数,所以这应该可以工作: '//div[contains(lower-case(text()), “{0}”)]'.format(text)
0赞 josh 9/8/2012
谢谢!虽然,我的理解是 XPath 2.0 在主要浏览器中不受支持......
0赞 andrean 9/8/2012
Selenium 直接使用浏览器自己的方法计算 XPath 表达式,因此这取决于您使用 Selenium 的浏览器。通常只有 IE 6、7 和 8 不支持 XPath 2.0。
0赞 anujin 7/26/2013
.format在我的日食中无法识别。它给出和错误。任何想法,为什么?
489赞 Ricky Sahu 9/9/2013 #2

请尝试以下操作:

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

评论

7赞 Ivan Koshelev 10/12/2014
感谢您的回复,这是我需要的 50%(让我开始)。我得到的形式是这样的“(//*[contains(text(), '” + text + “')] |*[@value='“ + text + ”'])“ 它不仅会在元素节点内搜索给定的文本,还会在文本通过”value“属性设置的输入元素内搜索,即 <button value=”My Button“ /> 。但请注意,该值必须严格匹配,而不仅仅是包含文本。
16赞 Dan Passaro 11/18/2014
对于其他搜索引擎访问者来说,还值得一提:如果您正在寻找链接,则有 和 方法find_element(s)_by_link_textfind_element(s)_by_partial_link_text
4赞 IcedDante 7/9/2015
如果文本是动态的呢?也就是说,可能包含引号。这不会破坏这个解决方案吗?
4赞 Sakamoto Kazuma 6/8/2016
搜索某些名称似乎打破了这一点。以以下示例为例:“//*[contains(text(), '”+username+“')]” if username = “O'Reilly”;那么 XPath 将失效。有没有办法解决这个问题?
3赞 Shawn 11/21/2016
当目标文本有多行时,它似乎不起作用。
-20赞 Amit 2/7/2014 #3

试试这个。这很简单:

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

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

评论

13赞 palacsint 2/9/2014
如果文本是由 JavaScript 生成的,则它不起作用。
3赞 thomas.han 8/25/2014
这是一种非常检查它的方法,因为您正在通过网络传输页面的全部内容。对于非常小的页面,这是可以接受的,但对于非常大的页面,您需要传输文件的所有内容并在服务器端进行检查。更好的方法是在客户端使用 xpath、javascript 或 css 来做到这一点。
1赞 René 9/6/2014
我会认为整个页面源代码已经需要通过网络传输才能让浏览器呈现它?
3赞 Cedric 5/29/2015
Josh 询问如何通过文本查找元素,而不是测试文本是否存在于页面源中。
1赞 Karlth 9/21/2015
对于只需要在页面上查找静态文本的实例,此解决方案就足够了。(它对我的情况有所帮助)。
17赞 Krzysztof Walczewski 1/17/2017 #4

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

请尝试以下代码:

@FindBy(xpath = "//*[contains(text(), 'Best Choice')]")
WebElement buttonBestChoice;
1赞 mike oganyan 8/12/2017 #5
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"));
0赞 Andriy Ivaneyko 8/30/2018 #6

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

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

评论

1赞 Todor Minakov 1/29/2019
matches()是 XPath 2.0 的功能,遗憾的是浏览器仅支持 1.0。
33赞 Ishita Shah 12/17/2018 #7

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

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

评论

0赞 Nomad77 5/14/2023
谢谢!这个版本对我有用,但最新版本的 Selenium 使用:driver:driver。FindElement(By.XPath...
9赞 Todor Minakov 1/29/2019 #8

有趣的是,几乎所有的答案都围绕着XPath的函数,忽略了它是区分大小写的事实 - 与OP的要求相反。contains()

如果你需要不区分大小写,这是可以在 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()(但尚未完全感知区域设置)和匹配(对于正则表达式搜索,带有不区分大小写的 () 标志)。'i'

3赞 Reto Höhener 5/14/2019 #9

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

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

wait.until(ExpectedConditions.elementToBeClickable(//
    driver.findElements(By.tagName("button")).stream().filter(i -> i.getText().equals("Advanced...")).findFirst().get())).click();
51赞 undetected Selenium 1/12/2020 #10

在您提供的 HTML 中:

<div>My Button</div>

文本是 并且周围没有空格,因此您可以轻松使用,如下所示:My ButtoninnerHTMLtext()

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 + "']")

评论

1赞 9 Guy 12/24/2020
您还可以使用 * 作为通配符来选择任何类型的元素,例如,如果您使用的是 find_elements_by_xpath
1赞 undetected Selenium 12/24/2020
@9Guy是的,这是真的。
6赞 Amar Kumar 1/19/2021 #11

只需使用这个:

driver.find_elements_by_xpath('//*[text() = "My Button"]')
1赞 Jortega 4/9/2023 #12

在 Selenium 中,4 已弃用。请参阅文档,https://selenium-python.readthedocs.io/locating-elements.htmlfind_element_by_xpath

这里有两个选项:

from selenium import webdriver
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
service = Service('D:\\Path\\to\\geckodriver.exe')
driver = webdriver.Firefox(service=service)

element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//*[contains(text(), 'My Button')]")))

element = driver.find_element(By.XPATH, "//*[contains(text(), 'My Button')]")
2赞 PhPires13 6/7/2023 #13

包含的文本

若要查找文本(显示在 HTML 页面中)包含特定文本元素,可以使用以下 XPath 表达式:

driver.find_element(By.XPATH, "//*[contains(text(), 'text_to_be_contained')]")
  • '*',选择文档中的所有元素,而不考虑标签名称。如果要在特定标签类型中进行搜索,可以将星号 (*) 替换为特定标签名称
  • [contains(text(), 'text_to_be_contained')] 是检查文本是否包含指定文本 ('text_to_be_contained') 的条件。这将匹配其 text 属性包含指定文本的元素,即使它是较大文本值的一部分。
  • “text_to_be_contained”,应该是您要查找的文本

包含的属性

若要查找属性包含特定文本的元素,可以使用以下 XPath 表达式:

//*[contains(@attribute_name, 'text_to_be_contained')]
  • “attribute_name”替换为要在其中搜索的属性的实际名称,例如:classnamehrefvalue 或任何其他属性

文本/属性相等

若要查找文本或属性与特定文本完全匹配元素,可以使用以下 XPath 表达式: 对于文本

正文:

//*[text()='exact_text']

对于属性:

//*[@attribute_name='exact_text']
  • “exact_text”,应该是您要查找的文本

注意:所有方法均区分大小写