如何用 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提取网页某个部分的所有链接? [复制]