如何选择所有子文本但不包括带有 Scapy 的 XPath 的标签?

Posted

技术标签:

【中文标题】如何选择所有子文本但不包括带有 Scapy 的 XPath 的标签?【英文标题】:How to select all children text but excluding a tag with Scapy's XPath? 【发布时间】:2015-02-11 15:08:33 【问题描述】:

我有这个 html

<div id="content">
    <h1>Title 1</h1><br><br>

    <h2>Sub-Title 1</h2>
    <br><br>
    Description 1.<br><br>Description 2.
    <br><br>

    <h2>Sub-Title 2</h2>
    <br><br>
    Description 1<br>Description 2<br>
    <br><br>

    <div class="infobox">
        <font style="color:#000000"><b>Information Title</b></font>
        <br><br>Long Information Text
    </div>
</div>

我想在 Scrapy 中使用 XPath 获取 &lt;div id="content"&gt; 中的所有文本,但不包括 &lt;div class="infobox"&gt; 的内容,所以预期的结果是这样的:

Title 1


Sub-Title 1


Descripton 1.

Descripton 2.


Sub-Title 2


Descripton 1.
Descripton 2.

但是我还没有达到排除部分,我还在努力从&lt;div id="content"&gt;中抓取文字。

我试过这个:

response.xpath('//*[@id="content"]/text()').extract()

但它只从两个子标题返回 Description 1.Description 2.

然后我尝试了:

response.xpath('//*[@id="content"]//*/text()').extract()

它只返回Title 1Sub-Title 1Sub-Title 2Information TitleLong Information Text

所以这里有两个问题:

    如何从content div 获取所有儿童文本? 如何从选择中排除infobox div?

【问题讨论】:

【参考方案1】:

使用descendant:: 轴查找后代文本节点,并明确声明这些文本节点的父节点不能是div[@class='infobox'] 元素。

把上面的变成XPath表达式:

//div[@id = 'content']/descendant::text()[not(parent::div/@class='infobox')]

然后,结果类似于(我使用在线 XPath 工具测试)如下。如您所见,div[@class='infobox'] 的文本内容不再出现在结果中。

-----------------------
Title 1
-----------------------
-----------------------
Sub-Title 1
-----------------------
-----------------------
Description 1.
-----------------------
Description 2.
-----------------------
-----------------------
Sub-Title 2
-----------------------
-----------------------
Description 1
-----------------------
Description 2
-----------------------
-----------------------
-----------------------

你的方法有什么问题?

你的第一次尝试:

//*[@id="content"]/text()

用简单的英语表示:

在文档中的任意位置查找具有@id 属性的任何元素(不一定是div),其值为“内容”。对于此元素,返回其所有直接子文本节点

问题:您正在丢失不是外部div 的直接子元素的文本节点,因为它们位于该div 的子元素内。


您的第二次尝试:

//*[@id="content"]//*/text()

翻译为:

在文档中的任何位置查找具有@id 属性的任何元素(不一定是div),其值为“内容”。对于该元素,查找任何后代元素节点并返回该后代元素的所有文本节点。

问题:您正在丢失div 的直接子文本节点,因为您只查看作为div 后代元素的子元素的文本节点。


编辑

回复您的评论:

//div[@id = 'content']/descendant::text()[not(ancestor::div/@class='infobox')]

对于您未来的问题,请确保您显示的 HTML 代表您的实际问题。

【讨论】:

您好,感谢您的回答。但是,如果 infobox div 包含另一个子元素,您的排除解决方案将不起作用,请参阅上面我编辑的 html 示例。 @suud 我已经编辑了我的答案。如果您使用ancestor:: 而不是parent::,则表达式将忽略信息框内的任何文本,无论它是否位于另一个元素内。 谢谢,这解决了我的问题。我需要的是//div[@class="body"]/descendant::text()[not(ancestor::script)](举个例子) 问题:在descendant 之前放两个斜杠而不是一个斜杠有区别吗? @ilius 两个斜线//descendant-or-self:: 轴的缩写。如果您的意思是//div[@id = 'content']//descendant::text()[not(ancestor::div/@class='infobox')],不,那应该没有什么区别,但//descendant:: 是多余的。

以上是关于如何选择所有子文本但不包括带有 Scapy 的 XPath 的标签?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取特定类型(按钮/文本框)的Windows窗体表单的所有子控件?

发布的数据更新子视图但不更新父视图

如何使用 XPath 选择带有引号字符的文本?

使用正则表达式查找模式后的所有内容,但不包括变量

SQL 从带有子查询的多个表中选择数据(包括来自内部连接的数据)错误:1242

Scapy 和 Python 3.2