不正确的父元素lxml

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

我正在用Python实现Web抓取程序。

请考虑以下HTML代码段。

<div>
  <b> 
    <i>
      HelloWorld
   </i>
   HiThere
  </b>
</div>

如果我只想使用lxml提取粗体或斜体文本,请使用以下命令

tree = etree.fromstring(myhtmlstr, htmlparser)
opp1 = tree.xpath(".//text()[ancestor::b or ancestor::i or ancestor::strong]")

这给了我正确的结果,即我的opp1的结果是:

[['HelloWorld','HiThere']

到目前为止,一切都很完美。但是,如果我尝试查询标签的父母,就会出现真正的问题。不出所料,opp1[0].getparent().tagopp1[0].getparent().getparent().tag的输出是ib

但是真正的问题在第二个标签中。理想情况下,opp[1]的父级应该是b标记。但是,opp1[1].getparent().tagopp1[1].getparent().getparent().tag的输出又是ib

您可以在以下代码中进行验证:

from lxml import etree
htmlstr = """<div><b><i>HelloWorld</i>HiThere</b></div>"""
htmlparser = etree.HTMLParser()
tree = etree.fromstring(htmlstr, htmlparser)
opp1 = tree.xpath(".//text()[ancestor::b or ancestor::i or ancestor::strong]")
print(opp1)
print(opp1[0].getparent(), opp1[0].getparent().getparent())
print(opp1[1].getparent(), opp1[1].getparent().getparent())

有人可以指出为什么会这样吗?我该怎么做才能纠正它?我计划仅对我的程序使用lxml,并且不希望使用bs4的任何解决方案。

python web-scraping lxml
1个回答
0
投票

这个问题似乎源于LXML(和ElementTree)的数据模型,其中一个元素大致是“标签,属性,文本,子项,尾部”; DOM数据模型也具有文本的实际节点。

如果您更改程序以执行此操作

for x in tree.xpath(".//text()[ancestor::b or ancestor::i or ancestor::strong]"):
    print(x, x.getparent(), "text?", x.is_text, "tail?", x.is_tail)

它将打印

HelloWorld <Element i at 0x10aa0ccd0> text? True tail? False
HiThere <Element i at 0x10aa0ccd0> text? False tail? True

"HiThere"是i元素的尾部,因为这是Etree数据模型表示混合的文本和标签的方式。

这里的重点(可能适用于您的用例)是将.getparent().getparent()视为具有is_tail=True的文本结果的有效父级。

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