Как использовать множественные и вложенные CSS-селекторы в Scrapy? - PullRequest
0 голосов
/ 25 сентября 2018

Я имею дело с хитрой проблемой селектора CSS, которая включает в себя несколько вложенных span s.

(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 €',...]

Это показывает, что проблемный <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 €']

На данный момент я в растерянности от того, как:

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

Q: Как мне сделать это самым простым способом?


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

Но они не оказали большой помощи в моем случае.


ОБНОВЛЕНИЕ :

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

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

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

1 Ответ

0 голосов
/ 25 сентября 2018

Хмм.

Это 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 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()
...