Не удается получить текст span с помощью Python

#python #python-3.x #web-scraping

#python #python-3.x #очистка веб-страниц

Вопрос:

У меня есть поставщик с веб-страницей входа, на которой я пытаюсь узнать цену и доступность. В то время как в VBA селекторы работают на Python, я не получаю ни одного.

Это HTML-часть, из которой я получаю цену:

 <div class="product-info-price">
  <div class="price-box price-final_price" data-role="priceBox" data-product- 
  id="32686" data-price-box="product-id-32686">
    <span class="special-price">
      <span class="price-container price-final_price tax weee"  itemprop="offers" itemscope itemtype="http://schema.org/Offer">
        <span class="price-label">Ειδική Τιμή</span>
        <span  id="product-price-32686"  data-price-amount="7.9" data-price-type="finalPrice" class="price-wrapper " >
          <span class="price">7,90 €</span>
        </span>
        <meta itemprop="price" content="7.9" />
        <meta itemprop="priceCurrency" content="EUR" />
      </span>
    </span>
  </div>
</div>
  

В VBA я использую следующий селектор:

 .price-box .price-final_price .price
  

В Python я использую:

 price = soup.find('span', attrs={'class':'price'})

if price is not None:
  price_text = price.text.strip()
  print(price_text)
else:
  price_text = "0,00"
  print(price_text)
  

и я всегда получаю 0,00 в качестве цены..

Что я должен изменить в soup.find ?

Комментарии:

1. это только часть..

2. Можете ли вы попробовать это снова с if price вместо if price is not None ?

3. Тот же результат, должен ли я получить div, а затем span, я не могу получить непосредственно span?

4. Похоже, вам нужно удалить пробел между двумя тегами выбора класса, поскольку они находятся в одном элементе: .price-box.price-final_price .price Поскольку price-final_price класс отображается на нескольких уровнях, попробуйте использовать другой класс селектора.

5. Поэтому я делаю price = soup.find(‘span’, attrs={‘class’:’price-box.price-final_price .price’})

Ответ №1:

Селекторы Css, как правило, быстрее, чем xpath. Вы можете использовать следующее:

 from bs4 import BeautifulSoup as bs

html = '''
<div class="product-info-price">
  <div class="price-box price-final_price" data-role="priceBox" data-product- 
  id="32686" data-price-box="product-id-32686">
    <span class="special-price">
      <span class="price-container price-final_price tax weee"  itemprop="offers" itemscope itemtype="http://schema.org/Offer">
        <span class="price-label">Ειδική Τιμή</span>
        <span  id="product-price-32686"  data-price-amount="7.9" data-price-type="finalPrice" class="price-wrapper " >
          <span class="price">7,90 €</span>
        </span>
        <meta itemprop="price" content="7.9" />
        <meta itemprop="priceCurrency" content="EUR" />
      </span>
    </span>
  </div>
</div>
'''

soup = bs(html, 'lxml')
prices = [price.text for price in soup.select('.price')]
print(prices)
  

В качестве альтернативы:

 altPrices = [price['content'] for price in soup.select("[itemprop=price]")]
print(altPrices)
  

Комментарии:

1. Я не знал, что вы можете извлечь метаданные таким образом. Я обязательно буду использовать эту технику в будущем.

2. @QHarr не могли бы вы объяснить мне немного подробнее, что prices = [price.text для price в soup.select(‘.price’)] что делает?

3. Это понимание списка, которое извлекает текст каждого возвращаемого соответствующего элемента

4. @QHarr Я помещаю его в середину … price = soup.find(‘span’, attrs={‘class’:’price’}) altPrices = [цена [‘content’] для price в soup.select(«[itemprop=price]»)] print(altPrices) если цена не равна None: я получаю только URL-адреса, подлежащие обработке, его подобное не регистрируется .. Я вошел в систему с помощью chromedriver

5. @QHarr Я получаю пустой список

Ответ №2:

Я предпочитаю lxml, для меня ясно использовать XPath вместо селекторов css:

 from lxml import html
all_html = html.fromstring(the_entire_html)
price = all_html.xpath('//meta[@itemprop="price"]/@content')
# or
price = all_html.xpath('//div[@class="product-info-price"]//span[@class="price"]/text()')