如何在 Scrapy 中使用多个嵌套跨度 CSS 选择器?

Posted

技术标签:

【中文标题】如何在 Scrapy 中使用多个嵌套跨度 CSS 选择器?【英文标题】:How to use multiple and nested span CSS selectors in Scrapy? 【发布时间】:2019-02-28 22:53:26 【问题描述】:

我正在处理一个涉及多个嵌套 span 的棘手 CSS 选择器问题。

(A) 通常 html/CSS 如下所示:

<div class="pricing">
    <strong>1 200 €</strong> 
</div>

(B)但也有部分是这样的:

<div class="pricing">
    <strong>
        <span class="promotion">
            <span class="promo-price">1 100 €</span>
        </span>
        <span class="strike">
            <span>1 200€</span>
        </span>
    </strong>
    <div class="new">New supplier</div>
</div>

(C) 像这样:

<div class="pricing">
    <strong>3 400 €</strong> 
    <span>/ best:  4500.00 €</span>
</div>

(D) 像这样:

<div class="pricing">
    <strong>4 900 €</strong> 
    <span class="netto">+ taxes</span> 
    <span>/ best:  4900.00 €</span>
</div>

使用 Scrapy CSS 选择器的类型:

response.css("div.pricing strong ::text").extract()
# ['2 500 €', '\n    ', '\n    ', '1 100 €', '\n    ', '\n    ', '1 200€', '3 999 €',...]

这表明上述 CSS 的有问题的&lt;span ...&gt; 在选择器文本中添加了空格。所以我试图忽略 both strikepromotion 类以及使用 :not() 的各种变体,如下所示:

response.css("div.pricing strong:not([class*='promotion']):not([class*='strike'])::text").extract()
# <same result as above>

我也可以得到promo-priceonly,带有:

response.css("div.pricing  .promo-price::text").extract()
# ['1 100 €']

此时我不知道如何:

获取所有 (A) 价格 获取所有 (B) promo-prices(仅限) 没有引入空白的结果(如上所示) 以上所有内容都在(最好)一个 CSS选择器或行

问:我怎样才能以最简单的方式做到这一点?


注意:我已经看过类似的问题了:

Scrapy grab div with multiple classes? Using multiple CSS selectors for the same ArticleItem in Scrapy

但在我的情况下,他们并没有提供太多帮助。


更新

我没能按照@boltclock 的指示完成任务,最后得到了一个丑陋的hack,像这样:

adPrice = aditem.css("div.pricing strong::text").extract_first().strip()
if adPrice == '':
    adPrice = aditem.css("div.pricing span.promo-price::text").extract_first()

所以如果有人有更好或更优雅的解决方案...

【问题讨论】:

【参考方案1】:

嗯。

div.new 是否仅出现在包含所有复杂性 (B) 的 strong 之后,而从未出现在仅包含单个价格 (A) 的 strong 之后?

如果是这样:

获取所有 (A) 价格 没有引入空白的结果(如上所示)
response.css("div.pricing strong:only-child::text").extract()

请注意::text 之前的空格省略,这确保您只能获得直接在strong 中的文本——有关使用指南,请参阅我对this question 的回答末尾。

:only-child 确保当 div.new 存在时它不匹配,如果它的缺失意味着 (A),那么您永远不必担心 (B)。

获取所有 (B) promo-prices(仅限)
response.css("div.pricing .promo-price::text").extract()
以上所有内容都在(最好)一个 CSS选择器或行

此时,将上述两个选择器分组应该是一件简单的事情:

response.css("div.pricing strong:only-child::text, div.pricing .promo-price::text").extract()

如果div.new 不相关,那么使用 CSS 选择器将很难做到这一点,因为没有其他方法可以区分 (A) 和 (B)。另一方面,XPath 使工作变得很短:

response.xpath("//div[@class='pricing']/(strong[not(./span)]|descendant::span[@class='promo-price'])/text()").extract()

【讨论】:

正确。 div.new 似乎只出现在 case(B) 中。 我在上面尝试了你的组合,它缺少很多项目。调查发现还有一个价格版本(C),里面有一个span,不知道还有多少。 (我已经更新了我的帖子) 我现在明白为什么提取它的最佳方法是使用 xpath 方法。但是,我在上面尝试了您的行,但只有第一部分(| 之前)有效,并且实际上得到了除促销项目之外的所有项目。第二部分生成错误信息。

以上是关于如何在 Scrapy 中使用多个嵌套跨度 CSS 选择器?的主要内容,如果未能解决你的问题,请参考以下文章

使用 css 选择器使用 scrapy 抓取 Reactjs 页面上的嵌套标签

如何在内容可编辑的 div 内的嵌套跨度上触发事件?

嵌套跨度标签在 XHTML 中可以吗?

在 Scrapy 中嵌套项目数据

如何在不使用任何图像项目符号或任何跨度标签的情况下通过 CSS 定义 OL/LI 列表中字符的颜色?

如何在表格中添加标题和跨度