我找到了一个具有特定类的对象:
THREAD = TREE.find_class('thread')[0]
现在我希望得到所有直接孩子的<p>
元素。
我累了:
THREAD.findall("p")
THREAD.xpath("//div[@class='thread']/p")
但所有这些都会返回此<p>
内的所有<div>
个元素,无论<div>
是否是他们最亲近的父级。
我怎样才能让它发挥作用?
修改
示例html:
<div class='thread'>
<p> <!-- 1 -->
<!-- Can be some others <p> objects inside, which should not be counted -->
</p>
<p><!-- 2 --></p>
</div>
<div class='thread'>
<p>[...]</p>
<p>[...]</p>
</div>
脚本应该找到两个<p>
对象,它们是THREAD
的子对象。我应该收到两个对象的列表,在示例HTML的注释中标记为“1”和“2”。
编辑2:
又一个澄清,因为人们感到困惑:
THREAD
是存储在变量中的一些对象,可以是任何html元素。我想找到<p>
的直接子项的THREAD
个对象。那些<p>
不能在THREAD
之外或在THREAD
内的任何元素内。
答案 0 :(得分:2)
我不确定,但似乎您的问题出在HTML本身:请注意there are couple Tag omission cases applicable for p
nodes,因此关闭段落标记
<div class='thread'>
<p>first
<p>second</p>
</p>
</div>
简单地被解析器忽略,并且两个节点都被识别为兄弟节点,但不是父节点和子节点,例如
<div class='thread'>
<p>first
<p>second
</div>
所以XPath //div[@class="thread"]/p
会返回两段
您只需使用p
标记替换div
代码,您就会看到不同的行为:
<div class='thread'>
<div>first
<div>second</div>
</div>
</div>
此处//div[@class="thread"]/div
将仅返回第一个节点
如果我的假设不正确,请纠正我
答案 1 :(得分:1)
试试这个XPath表达式:
//p[parent::div[@class='thread']]
或者在完整的Python表达式中:
THREAD.xpath("//p[parent::div[@class='thread']]")
另一种(逆)方法是这个XPath表达式:
div[@class='thread']/child::p"
使用直接child::
轴,仅选择直接子节点。
要点:
两个表达式中哪一个更快取决于XPath编译器。 child::
是默认轴,如果没有给出其他轴,则使用它。
仅供参考:XPath计数从 1 开始,不是0 。
关于XML示例,请使用以下表达式
count(//div[@class='thread'][1]/child::p)
会产生值2 - 计算<p> <!-- 1 -->
+ <p><!-- 2 --></p>
的结果。
答案 2 :(得分:0)
您可以尝试 PARENT.getchildren()
>>> root = etree.fromstring(xml)
>>> root.xpath("//div[@class='thread']")[0].getchildren()
[<Element p at 0x10b3110e0>, <Element p at 0x10b311ea8>]