不正确的父元素 lxml
Incorrect parent element lxml
我正在 Python.
中实施网络抓取程序
考虑我下面的 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().tag
和 opp1[0].getparent().getparent().tag
的输出是 i
和 b
.
然而,真正的问题在第二个标签中。理想情况下,opp[1]
的父标签应该是 b
标签。然而,opp1[1].getparent().tag
和opp1[1].getparent().getparent().tag
的输出又是i
和b
。
您可以在以下代码中进行验证:
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 的解决方案。
这个问题似乎源于 LXML(和 ElementTree)的数据模型,其中一个元素大致是 "tag, attributes, text, children, tail"; 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
.
的文本结果的有效父级
我正在 Python.
中实施网络抓取程序考虑我下面的 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().tag
和 opp1[0].getparent().getparent().tag
的输出是 i
和 b
.
然而,真正的问题在第二个标签中。理想情况下,opp[1]
的父标签应该是 b
标签。然而,opp1[1].getparent().tag
和opp1[1].getparent().getparent().tag
的输出又是i
和b
。
您可以在以下代码中进行验证:
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 的解决方案。
这个问题似乎源于 LXML(和 ElementTree)的数据模型,其中一个元素大致是 "tag, attributes, text, children, tail"; 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
.