如何选择所有子文本但使用Scapy的XPath排除标记?

nul*_*ull 6 html python xpath scrapy

我有这个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>
Run Code Online (Sandbox Code Playgroud)

我希望<div id="content">在Scrapy 中使用XPath 获取所有文本,但不包括<div class="infobox">内容,因此预期结果如下:

Title 1


Sub-Title 1


Descripton 1.

Descripton 2.


Sub-Title 2


Descripton 1.
Descripton 2.
Run Code Online (Sandbox Code Playgroud)

但是我还没有到达排除部分,我仍然在努力从中获取文本<div id="content">.

我试过这个:

response.xpath('//*[@id="content"]/text()').extract()
Run Code Online (Sandbox Code Playgroud)

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

然后我尝试了:

response.xpath('//*[@id="content"]//*/text()').extract()
Run Code Online (Sandbox Code Playgroud)

它只返回Title 1,Sub-Title 1,Sub-Title 2,Information Title,和Long Information Text.


所以这里有两个问题:

  1. 我怎么能从contentdiv 获得所有的孩子文本?
  2. 如何infobox从选择中排除div?

Mat*_*ler 13

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

将上述内容转换为XPath表达式:

//div[@id = 'content']/descendant::text()[not(parent::div/@class='infobox')]
Run Code Online (Sandbox Code Playgroud)

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

-----------------------
Title 1
-----------------------
-----------------------
Sub-Title 1
-----------------------
-----------------------
Description 1.
-----------------------
Description 2.
-----------------------
-----------------------
Sub-Title 2
-----------------------
-----------------------
Description 1
-----------------------
Description 2
-----------------------
-----------------------
-----------------------
Run Code Online (Sandbox Code Playgroud)

你的方法有什么问题?

你的第一次尝试:

//*[@id="content"]/text()
Run Code Online (Sandbox Code Playgroud)

用简单的英语表示:

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

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


你的第二次尝试:

//*[@id="content"]//*/text()
Run Code Online (Sandbox Code Playgroud)

翻译为:

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

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


编辑:

回应你的评论:

//div[@id = 'content']/descendant::text()[not(ancestor::div/@class='infobox')]
Run Code Online (Sandbox Code Playgroud)

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