如何选择所有子文本但不包括带有 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 获取 <div id="content">
中的所有文本,但不包括 <div class="infobox">
的内容,所以预期的结果是这样的:
Title 1
Sub-Title 1
Descripton 1.
Descripton 2.
Sub-Title 2
Descripton 1.
Descripton 2.
但是我还没有达到排除部分,我还在努力从<div id="content">
中抓取文字。
我试过这个:
response.xpath('//*[@id="content"]/text()').extract()
但它只从两个子标题返回 Description 1.
和 Description 2.
。
然后我尝试了:
response.xpath('//*[@id="content"]//*/text()').extract()
它只返回Title 1
、Sub-Title 1
、Sub-Title 2
、Information Title
和Long 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窗体表单的所有子控件?