Я имею дело с сложной проблемой селектора 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>
Использование селектора CSS Scrapy типа:
response.css("div.pricing strong ::text").extract()
# ['2 500 €', '\n ', '\n ', '1 100 €', '\n ', '\n ', '1 200€', '3 999 €',...]
Это показывает, что проблемный <span...>
из приведенного выше CSS добавляет пробелы в текст селектора. Поэтому я попытался игнорировать как strike
и promotion
классы с различными вариантами использования :not()
следующим образом:
response.css("div.pricing strong:not([class*='promotion']):not([class*='strike'])::text").extract()
# <same result as above>
Я могу получить только promo-price
, с:
response.css("div.pricing .promo-price::text").extract()
# ['1 100 €']
На данный момент я теряю информацию о том, как:
promo-price
(только)В: Как я могу сделать это самым простым способом?
Примечание. Я уже видел похожие вопросы:
Но в моем случае они не очень помогли.
ОБНОВЛЕНИЕ:
Я не смог выполнить задачу в соответствии с инструкциями @boltclock и закончил с уродливым взломом, как это:
adPrice = aditem.css("div.pricing strong::text").extract_first().strip()
if adPrice == '':
adPrice = aditem.css("div.pricing span.promo-price::text").extract_first()
Поэтому, если у кого-то есть лучшее или более элегантное решение...
Хм.
div.new
появляется только после strong
который содержит всю эту сложность (B), и никогда после strong
который содержит только одну цену (A)?
Если так:
- получить все цены (A)
- результат без введенного пробела (как показано выше)
response.css("div.pricing strong:only-child::text").extract()
Обратите внимание на отсутствие пробела перед ::text
, который гарантирует, что вы получите только текст, который находится прямо в strong
- см. Конец моего ответа на этот вопрос для рекомендаций по использованию.
:only-child
гарантирует, что он не совпадает, когда присутствует div.new
, если его отсутствие подразумевает (A), поэтому вам никогда не придется беспокоиться о (B).
- получить все (B)
promo-price
(только)
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
кажется, появляется только в случае (B).