如何在 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 的有问题的<span ...>
在选择器文本中添加了空格。所以我试图忽略 both strike
和 promotion
类以及使用 :not()
的各种变体,如下所示:
response.css("div.pricing strong:not([class*='promotion']):not([class*='strike'])::text").extract()
# <same result as above>
我也可以得到promo-price
only,带有:
response.css("div.pricing .promo-price::text").extract()
# ['1 100 €']
此时我不知道如何:
获取所有 (A) 价格 获取所有 (B)promo-price
s(仅限)
没有引入空白的结果(如上所示)
以上所有内容都在(最好)一个 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-price
s(仅限)
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 页面上的嵌套标签