Как использовать множественные и вложенные CSS-селекторы в Scrapy?

1

Я имею дело с сложной проблемой селектора 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 €']

На данный момент я теряю информацию о том, как:

  • получить все цены (A)
  • получить все (B) promo-price (только)
  • результат без введенного пробела (как показано выше)
  • все вышеперечисленное в (предпочтительно) одном CSS-селекторе или строке

В: Как я могу сделать это самым простым способом?


Примечание. Я уже видел похожие вопросы:

Но в моем случае они не очень помогли.


ОБНОВЛЕНИЕ:

Я не смог выполнить задачу в соответствии с инструкциями @boltclock и закончил с уродливым взломом, как это:

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

Поэтому, если у кого-то есть лучшее или более элегантное решение...

Теги:
web-scraping
scrapy
css-selectors

1 ответ

1

Хм.

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()
  • 0
    Верный. div.new кажется, появляется только в случае (B).
  • 0
    Я попробовал ваше комбо выше, и в нем пропало немало вещей. Расследование показало, что существует еще одна ценовая версия (C) , с пролетом в ней, и кто знает, сколько еще. (Я обновил свой пост)
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню