<div id="a">This is some
<div id="b">text</div>
</div>
获得“这是一些”并非易事。例如,这会返回“这是一些文本”:
driver.find_element_by_id('a').text
一般而言,如何获取特定元素的文本而不包括其子元素的文本?
(我在下面提供了一个答案,但如果有人能想出一个不那么可怕的解决方案,我会留下这个问题)。
<div id="a">This is some
<div id="b">text</div>
</div>
获得“这是一些”并非易事。例如,这会返回“这是一些文本”:
driver.find_element_by_id('a').text
一般而言,如何获取特定元素的文本而不包括其子元素的文本?
(我在下面提供了一个答案,但如果有人能想出一个不那么可怕的解决方案,我会留下这个问题)。
这是一个通用的解决方案:
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)
我实际上在测试套件中使用此代码。
在您共享的 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的pythonThis is some
客户端从文本节点中提取和打印文本,您有以下两种方法:
使用splitlines()
:您可以识别父元素即<div id="a">
,提取innerHTML
然后使用splitlines()
如下:
使用xpath:
print(driver.find_element_by_xpath("//div[@id='a']").get_attribute("innerHTML").splitlines()[0])
使用xpath:
print(driver.find_element_by_css_selector("div#a").get_attribute("innerHTML").splitlines()[0])
使用execute_script()
:你也可以使用execute_script()
可以在当前窗口/框架中同步执行JavaScript的方法,如下:
使用xpath和firstChild:
parent_element = driver.find_element_by_xpath("//div[@id='a']")
print(driver.execute_script('return arguments[0].firstChild.textContent;', parent_element).strip())
使用xpath和childNodes[n]:
parent_element = driver.find_element_by_xpath("//div[@id='a']")
print(driver.execute_script('return arguments[0].childNodes[1].textContent;', parent_element).strip())
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
您不必进行替换,您可以获取子文本的长度并将其从总长度中减去,然后切片为原始文本。那应该快得多。
不幸的是,Selenium 仅适用于Elements,而不适用于Text节点。
如果您尝试使用诸如get_element_by_xpath
定位文本节点之类的函数,Selenium 将抛出一个InvalidSelectorException
.
一种解决方法是使用 Selenium 获取相关的 HTML,然后使用可以更优雅地处理文本节点的 BeautifulSoup 之类的 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() 遍历元素的子节点并检查它们的对象类型。
BeautifulSoup 有四种类型的元素,您会感兴趣的一种是NavigableString类型,它由 Text 节点生成。相比之下, 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.")
请注意,BeautifulSoup 不支持 Xpath 表达式。如果您需要这些,那么您可以使用此线程中的一些解决方法。