如何获取 Selenium WebDriver 中元素的文本,而不包含子元素文本?

问题描述 投票:0回答:5

考虑:

<div id="a">This is some
   <div id="b">text</div>
</div>

获得“这是一些”是很重要的。 例如,这会返回“这是一些文本”:

driver.find_element_by_id('a').text

如何以一般方式获取特定元素的文本而不包含其子元素的文本?

python html selenium selenium-webdriver
5个回答
30
投票

这是一个通用解决方案:

def get_text_excluding_children(driver, element):
    return driver.execute_script("""
    return jQuery(arguments[0]).contents().filter(function() {
        return this.nodeType == Node.TEXT_NODE;
    }).text();
    """, element)

传递给函数的元素可以是从

find_element...()
方法获得的东西(即,它可以是
WebElement
对象)。

或者如果你没有 jQuery 或者不想使用它,你可以用这个替换上面的函数体:

return self.driver.execute_script("""
var parent = arguments[0];
var child = parent.firstChild;
var ret = "";
while(child) {
    if (child.nodeType === Node.TEXT_NODE)
        ret += child.textContent;
    child = child.nextSibling;
}
return ret;
""", element)

我实际上在测试套件中使用此代码。


15
投票

在您共享的 HTML 中:

<div id="a">This is some
   <div id="b">text</div>
</div>

文本

This is some
位于文本节点内。以结构化方式描述文本节点

<div id="a">
    This is some
   <div id="b">text</div>
</div>

这个用例

要使用 Selenium

python
客户端从 文本节点 提取并打印文本 This is some,有以下两种方法:

  • 使用

    splitlines()
    :您可以识别父元素,即
    <div id="a">
    ,提取
    innerHTML
    ,然后使用
    splitlines()
    ,如下所示:

  • 使用xpath

    print(driver.find_element_by_xpath("//div[@id='a']").get_attribute("innerHTML").splitlines()[0])
    
  • 使用css_selector

    print(driver.find_element_by_css_selector("div#a").get_attribute("innerHTML").splitlines()[0])
    
  • 使用

    execute_script()
    :您还可以使用
    execute_script()
    方法,它可以在当前窗口/框架中同步执行JavaScript,如下:

  • 使用xpathfirstChild

    parent_element = driver.find_element_by_xpath("//div[@id='a']")
    print(driver.execute_script('return arguments[0].firstChild.textContent;', parent_element).strip())
    
  • 使用 xpathchildNodes[n]:

    parent_element = driver.find_element_by_xpath("//div[@id='a']")
    print(driver.execute_script('return arguments[0].childNodes[1].textContent;', parent_element).strip())
    

5
投票

用途:

def get_true_text(tag):
    children = tag.find_elements_by_xpath('*')
    original_text = tag.text
    for child in children:
        original_text = original_text.replace(child.text, '', 1)
    return original_text

4
投票

您无需更换。您可以获取子文本的长度,从总长度中减去该长度,然后切片到原始文本中。 这应该会快得多。


3
投票

不幸的是,Selenium 仅适用于 Elements,而不是 Text 节点。

如果您尝试使用像

get_element_by_xpath
这样的函数来定位文本节点,Selenium 将抛出
InvalidSelectorException

一种解决方法是使用 Selenium 获取相关 HTML,然后使用像 Beautiful Soup 这样可以更优雅地处理文本节点的 HTML 解析库。

import bs4
from bs4 import BeautifulSoup

inner_html = driver.find_elements_by_css_selector('#a')[0].get_attribute("innerHTML")
inner_soup = BeautifulSoup(inner_html, 'html.parser')

outer_html = driver.find_elements_by_css_selector('#a')[0].get_attribute("outerHTML")
outer_soup = BeautifulSoup(outer_html, 'html.parser')

从那里,有多种方法可以搜索文本内容。您必须进行试验,看看什么最适合您的用例。

这里有一句简单的话可能就足够了:

inner_soup.find(text=True)

如果这不起作用,那么您可以使用 .contents() 循环遍历元素的子节点并检查它们的对象类型。

Beautiful Soup 有四种类型的元素,您感兴趣的是 NavigableString 类型,它是由文本节点生成的。相比之下,Elements 将具有 Tag 类型。

contents = inner_soup.contents

for bs4_object in contents:

    if (type(bs4_object) == bs4.Tag):
        print("This object is an Element.")

    elif (type(bs4_object) == bs4.NavigableString):
        print("This object is a Text node.")

请注意,Beautiful Soup 不支持 XPath 表达式。如果您需要这些,那么您可以使用一些解决方法在此问题中

© www.soinside.com 2019 - 2024. All rights reserved.