【问题标题】:How do I find an element that contains specific text in Selenium WebDriver (Python)?如何在 Selenium WebDriver (Python) 中找到包含特定文本的元素?
【发布时间】:2012-09-01 15:36:03
【问题描述】:

我正在尝试使用 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 including child element text?

【问题讨论】:

标签: python selenium selenium-webdriver


【解决方案1】:

尝试以下方法:

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

【讨论】:

  • 感谢您的回复,这是我需要的 50%(让我开始了)。我到达的表格是这个“(//* [contains(text(),'”+ text +“')] | //* [@value ='”+ text +“'])”它将搜索不仅在元素节点内给出文本,而且在其文本通过“值”属性设置的输入元素内给出文本,即 。请注意,该值必须严格匹配,而不仅仅是包含文本。
  • 对于其他搜索引擎访问者也值得一提:如果您正在寻找链接,则有 find_element(s)_by_link_textfind_element(s)_by_partial_link_text 方法
  • 如果文本是动态的呢?也就是说,可能包含引号。这不会破坏这个解决方案吗?
  • 搜索某些名称似乎打破了这一点。举个例子: "//*[contains(text(), '"+username+"')]" if username = "O'Reilly";那么xpath将变得无效。有没有办法解决这个问题?
  • 目标文本多行时似乎不起作用。
【解决方案2】:

你可以试试这样的 XPath 表达式:

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

【讨论】:

  • 谢谢...这样有助于区分内部和外部,但这实际上适用于 xpath,我只是在遍历所有 div 时遇到了这个问题。我对 xpath 的问题是我不知道如何使它不区分大小写?
  • xpath 2.0 有一个小写函数,所以这应该可以工作:'//div[contains(lower-case(text()), "{0}")]'.format(text )
  • 谢谢!不过,我的理解是主流浏览器不支持 xpath 2.0...
  • selenium 直接使用浏览器自己的方法评估 xpath 表达式,因此这取决于您使用 selenium 的浏览器。一般只有 ie 6,7 和 8 不应该支持 xpath 2.0。
  • .format 在我的日食中无法识别。它给出了错误。有什么想法,为什么?
【解决方案3】:

在您提供的 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 + "']")

【讨论】:

  • 您也可以使用 * 作为通配符来选择任何类型的元素,例如,如果您使用的是 find_elements_by_xpath
  • @9Guy 是的,没错。
【解决方案4】:

//* 将寻找任何 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')]")

【讨论】:

    【解决方案5】:

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

    试试这个代码:

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

    【讨论】:

      【解决方案6】:

      有趣的是,几乎所有答案都围绕 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(用于正则表达式搜索,带有不区分大小写的 ('i') 标志)。

      【讨论】:

        【解决方案7】:

        只需使用这个:

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

        【讨论】:

          【解决方案8】:

          类似问题:查找&lt;button&gt;Advanced...&lt;/button&gt;

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

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

          【讨论】:

            【解决方案9】:
            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"));
            

            【讨论】:

              【解决方案10】:

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

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

              【讨论】:

              • matches()是xpath 2.0的功能,遗憾的是浏览器只支持1.0。
              【解决方案11】:

              如果使用 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");
              }
              

              【讨论】:

                【解决方案12】:

                试试这个。很简单:

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

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

                【讨论】:

                • 如果文本是由 JavaScript 生成的则不起作用。
                • 这是一种非常好的检查方式,因为您正在通过网络传输页面的全部内容。对于非常小的页面,这是可以接受的,但对于非常大的页面,您需要传输文件的所有内容并在服务器端进行检查。更好的方法是在客户端使用 xpath、javascript 或 css。
                • 我认为整个页面源已经需要通过网络传输以便浏览器呈现它?
                • Josh 询问如何通过文本查找元素,而不是测试文本是否存在于页面源中。
                • 对于只需要在页面上查找静态文本的情况,此解决方案就足够了。 (对我来说有帮助)。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-09-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多