如何用 BeautifulSoup 等一秒钟来保存汤元素以让页面中的元素加载完成

Posted

技术标签:

【中文标题】如何用 BeautifulSoup 等一秒钟来保存汤元素以让页面中的元素加载完成【英文标题】:How to scrape with BeautifulSoup waiting a second to save the soup element to let elements load complete in the page 【发布时间】:2020-02-28 18:19:01 【问题描述】:

我正在尝试从 THIS WEBSITE 中抓取某些产品中具有 3 种价格的数据(静音价格、红色价格和黑色价格),我观察到当产品具有3 个价格。

当我抓取网站时,我只得到两个价格,我认为如果代码等到页面完全加载,我会得到所有价格。

这是我的代码:

url='https://www.exito.com/televisor-led-samsung-55-pulgadas-uhd-4k-smart-tv-serie-7-24449/p'
req = requests.get(url)
soup = BeautifulSoup(req.text, "lxml")

# Muted Price
MutedPrice = soup.find_all("span",'class':'exito-vtex-components-2-x-listPriceValue ph2 dib strike custom-list-price fw5 exito-vtex-component-precio-tachado')[0].text
MutedPrice=pd.to_numeric(MutedPrice[2-len(MutedPrice):].replace('.',''))

# Red Price
RedPrice = soup.find_all("span",'class':'exito-vtex-components-2-x-sellingPrice fw1 f3 custom-selling-price dib ph2 exito-vtex-component-precio-rojo')[0].text
RedPrice=pd.to_numeric(RedPrice[2-len(RedPrice):].replace('.',''))

# black Price
BlackPrice = soup.find_all("span",'class':'exito-vtex-components-2-x-alliedPrice fw1 f3 custom-selling-price dib ph2 exito-vtex-component-precio-negro')[0].text
BlackPrice=pd.to_numeric(BlackPrice[2-len(BlackPrice):].replace('.',''))

print('Muted Price:',MutedPrice)
print('Red Price:',RedPrice)
print('Black Price:',BlackPrice)

实际结果: 静音价格:3199900 红色价格:1649868 黑色价格:0

预期结果: 静音价格:3199900 红色价格:1550032 黑色价格:1649868

【问题讨论】:

你需要 Selenium。请求只会得到初始响应。 【参考方案1】:

您尝试抓取的页面包含 javascript 代码,该代码由您的浏览器执行并在页面下载后修改页面。如果要对页面的“最终状态”执行提取,则需要使用专用于该页面的库在页面上运行 JavaScript 代码。不幸的是,BeautifulSoup 没有这个功能,你需要使用另一个库来完成你的任务。

例如,您可以pip install requests-html 并运行以下命令:

#!/usr/bin/env python3

import re
from requests_html import HTMLSession

def parse_price_text(price_text):
    """Extract just the price digits and dots from the <span> tag text"""
    matches = re.search("([\d\.]+)", price_text)
    if not matches:
        raise RuntimeError(f"Could not parse price text: price_text")

    return matches.group(1)

# Starting a session and running the JavaScript code with render()
# to make sure the DOM is the same as when using the browser.
session = HTMLSession()
exito_url = "https://www.exito.com/televisor-led-samsung-55-pulgadas-uhd-4k-smart-tv-serie-7-24449/p"
response = session.get(exito_url)
response.html.render()

# Define all price types and their associated CSS class
price_types = 
    "listPrice": "exito-vtex-components-2-x-listPriceValue",
    "sellingPrice": "exito-vtex-components-2-x-sellingPrice",
    "alliedPrice": "exito-vtex-components-2-x-alliedPrice"


# Iterate over price types and extract them from the page
for price_type, price_css_class in price_types.items():
    price = parse_price_text(response.html.find(f"span.price_css_class", first=True).text)
    print(f"price_type price: price $")

它打印以下内容:

listPrice price: 3.199.900 $
sellingPrice price: 1.550.032 $
alliedPrice price: 1.649.868 $

【讨论】:

感谢您的快速回复!当我运行代码时显示:RuntimeError:无法在现有事件循环中使用 HTMLSession。请改用 AsyncHTMLSession。 确保使用 Python 解释器直接从终端运行此代码:python exito.py, exito.py 是我给你的代码。我怀疑您正在使用一些具有事件循环的附加软件(大概是 Jupyter?)并且与 requests-html 冲突。 谢谢你,那是 ritgh,我在 jupiter notebook 上运行代码,我会按照你在 .py 文件上说的那样尝试。再次感谢您的帮助。【参考方案2】:

这些值可能是动态呈现的,即这些值可能由页面中的 javascript 填充。

requests.get() 只是返回从服务器接收到的标记,没有任何进一步的客户端更改,因此它不完全是等待。

您也许可以使用Selenium Chrome Webdriver 来加载页面 URL 并获取页面源。 (或者您可以使用 Firefox 驱动程序)。

转到chrome://settings/help 检查您当前的 chrome 版本并从here 下载该版本的驱动程序。确保将驱动程序文件保存在您的 PATH 或您的 python 脚本所在的同一文件夹中。

尝试用以下代码替换现有代码的前 3 行:

from contextlib import closing
from selenium.webdriver import Chrome # pip install selenium

url='https://www.exito.com/televisor-led-samsung-55-pulgadas-uhd-4k-smart-tv-serie-7-24449/p'

# use Chrome to get page with javascript generated content
with closing(Chrome(executable_path="./chromedriver")) as browser:
     browser.get(url)
     page_source = browser.page_source

soup = BeautifulSoup(page_source, "lxml")

输出:

Muted Price: 3199900
Red Price: 1550032
Black Price: 1649868

参考资料:

Get page generated with Javascript in Python

selenium - chromedriver executable needs to be in PATH

【讨论】:

感谢您的快速回复,代码运行良好,我只需要看看是否可以在 arround 11.000 页中运行 :) @Fabiosalinas,您可能需要浏览器在不打开的情况下在后台运行。 Atm,代码打开一个新的浏览器窗口。你可以参考这个使其成为纯粹的无头sqa.stackexchange.com/a/34401 :) 再次感谢您的帮助,现在我正在运行 arround 13.000 页面的代码,并且性能现在可以更好地运行它而无需打开浏览器并避免加载图像,但即使这样我也必须等待60 小时来抓取所有数据,所以我在想如何优化我的代码以每天运行它。

以上是关于如何用 BeautifulSoup 等一秒钟来保存汤元素以让页面中的元素加载完成的主要内容,如果未能解决你的问题,请参考以下文章

如何用 Beautifulsoup 解析“数据文本”? [复制]

如何用beautifulsoup提取网页某个部分的所有链接? [复制]

如何用 BeautifulSoup 抓取 Instagram

如何用 Python 制作 GIF 动图

如何用最暴力的方法改写Liferay的原生portlet

如何用webpack从零搭建一个大型项目