XPath展平除某些节点之外的文本

时间:2016-07-05 09:20:58

标签: xpath scrapy

使用scrapy的XPath选择器我试图压缩包含纯文本或格式化HTML内容的div元素的文本内容。以下是两个例子:

<div>
    <div itemprop="content">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
        <br>
        Donec fringilla est eu euismod varius.
    </div>

    <div itemprop="content">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
        <p>Donec fringilla est eu euismod varius.</p>
        <p class="quote">
            <span>Quote</span>
            <a href="#">Exclude me</a>
            <ul>
                <li>Exclude me</li>
                <li>Exclude me</li>
            </ul>
        </p>
        <blockquote>Cras facilisis suscipit euismod.</blockquote>
    </div>
</div>

现在的目标是省略展平文本中的<p class="quote">Quote</p>,因为它仅作为跟随它的blockquote的视觉提示。由于第一个示例的性质,即文本作为所选div的直接子项,我提出的解决方案看起来如下:

//div[@itemprop="content"]/descendant-or-self::*[not(self::script)]/text()[normalize-space()]

这完成了三件事:

  1. 排除<script>个节点,因为我不希望在结果中包含他们的文字。
  2. 排除任何不包含任何文字的节点。
  3. 包括我的顶级div的直接文字儿童(通过descendant-or-self)。
  4. 不幸的是,在我看来后者导致<p class="quote">Quote</p>被包括在内,尽管有额外的排除过滤器,例如:

    //div[@itemprop="content"]/descendant-or-self::*[not(self::script) and not(@class="quote")]/text()[normalize-space()]
    
    //div[@itemprop="content"]/descendant-or-self::*[not(self::script)]/text()[normalize-space() and not(ancestor::*[@class="quote"])]
    

    迭代<div itemprop="content">个节点,预期输出是一个列表:

    ['Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fringilla est eu euismod varius.',
    'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec fringilla est eu euismod varius. Cras facilisis suscipit euismod.']
    

    有没有办法用单个XPath选择器解决这个问题?

2 个答案:

答案 0 :(得分:0)

要指向具有属性的项目,请将其写入:dmac:camden-market dob$ docker run -d -p 5432:5432 postgres:latest postgresdb 197402ae06c352ff70651b2888ee5018948e2151886a498c096501ec545249d2 dmac:camden-market dob$

self::*[@class="quote"]

答案 1 :(得分:0)

这是使用sc {{}通过lxml支持的EXSLT's set operations的方式。

您可能需要稍微调整XPath,但想法是选择父元素下的所有文本节点,并在该父元素的后代元素下排除这些文本节点。

注意:我必须稍微更改您的输入because <p> can't contain <ul>并导致问题lxml(默认情况下scrapy使用)

>>> import scrapy
>>> t = r'''<div>
...     <div itemprop="content">
...         Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
...         <br>
...         Donec fringilla est eu euismod varius.
...     </div>
... 
...     <div itemprop="content">
...         <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
...         <p>Donec fringilla est eu euismod varius.</p>
...         <div class="quote">
...             <ul>
...                 <li>Exclude me</li>
...                 <li>Exclude me</li>
...             </ul>
...             <span>Quote</span>
...             <a href="#test">Exclude me</a>
...         </div>
...         <blockquote>Cras facilisis suscipit euismod.</blockquote>
...     </div>
... </div>'''
>>> selector = scrapy.Selector(text=t, type='html')
>>> pprint(selector.xpath('''
               set:difference(
                   //div[@itemprop="content"]//text(),
                   //div[@class="quote"]//text())
           ''').extract())
['\n'
 '        Lorem ipsum dolor sit amet, consectetur adipiscing elit. \n'
 '        ',
 '\n        Donec fringilla est eu euismod varius.\n    ',
 '\n        ',
 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
 '\n        ',
 'Donec fringilla est eu euismod varius.',
 '\n        ',
 '\n        ',
 'Cras facilisis suscipit euismod.',
 '\n    ']
>>> 
相关问题