You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Selenium无法提取JS渲染的超市优惠文本(元素未在检查面板显示)

提取BM超市隐藏优惠文本及脚本性能优化方案

一、隐藏优惠文本的提取方法

1. 提取CSS伪元素内容

部分悬停显示的"AHORRAS X%"文本可能由CSS伪元素(如::after/::before)生成,这类内容不会出现在DOM结构中,但可通过JavaScript获取计算后的样式:

from selenium.webdriver.common.action_chains import ActionChains

# 定位黄色BM图标元素(需替换为实际页面选择器)
bm_icon = driver.find_element(By.CSS_SELECTOR, ".product-detail__bm-icon")
# 执行JS获取伪元素content属性
offer_text = driver.execute_script("""
    return window.getComputedStyle(arguments[0], '::after').content;
""", bm_icon).strip('"')  # 去除文本首尾的引号

2. 模拟鼠标悬停触发元素显示

若文本存在于默认隐藏的DOM元素中(悬停时切换显示状态),可通过ActionChains模拟悬停后提取:

from selenium.webdriver.common.action_chains import ActionChains

# 定位目标商品容器
product_item = driver.find_element(By.CSS_SELECTOR, f".product-detail:nth-child({index})")
# 模拟鼠标悬停
ActionChains(driver).move_to_element(product_item).perform()
# 提取显示的优惠文本
offer_text = driver.find_element(By.CSS_SELECTOR, ".hover-show-offer-text").text.strip()

3. 直接定位隐藏元素

部分隐藏元素的文本本身已存在于DOM中,仅通过CSS控制显示/隐藏,可直接定位提取:

# 查找所有隐藏的会员优惠文本
hidden_offers = driver.find_elements(By.CSS_SELECTOR, ".panel--check__deferred[style*='display:none']")
for offer in hidden_offers:
    print(offer.text.strip())

二、脚本性能优化方案

1. 复用浏览器实例

原脚本每次请求都新建/关闭浏览器,这是耗时核心。改为全局复用浏览器:

# 初始化浏览器(仅执行一次)
driver = webdriver.Chrome()

def load_page(url):
    driver.get(url)
    # 等待所有商品加载完成
    WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".product-detail")))

# 处理完所有页面后关闭
# driver.quit()

2. 跳过BeautifulSoup中转,直接用Selenium提取

BeautifulSoup解析会增加额外开销,直接通过Selenium定位元素提取文本:

# 获取当前页所有商品元素
products = driver.find_elements(By.CSS_SELECTOR, ".product-detail")
offers = []
member_offer_idx = 0
# 预加载所有会员优惠元素
member_offers = driver.find_elements(By.CSS_SELECTOR, ".panel--check.panel--check__deferred.u-width--50.ng-star-inserted")

for product in products:
    # 尝试提取普通优惠
    normal_offer = product.find_elements(By.CSS_SELECTOR, ".product-detail__pictos--offer.ng-star-inserted")
    if normal_offer and normal_offer[0].text.strip():
        offers.append(normal_offer[0].text.strip())
    else:
        # 提取会员优惠
        offers.append(member_offers[member_offer_idx].text.strip())
        member_offer_idx += 1

print('\n'.join(offers))

3. 优化页面加载速度

通过ChromeOptions禁用不必要的资源加载,加速页面渲染:

options = webdriver.ChromeOptions()
options.add_argument("--blink-settings=imagesEnabled=false")  # 禁用图片
options.add_argument("--disable-extensions")  # 禁用扩展
options.add_argument("--headless=new")  # 无头模式(可选,无界面运行)
driver = webdriver.Chrome(options=options)

4. 精准等待策略

使用presence_of_all_elements_located等待所有商品加载完成,而非单个分页元素,确保数据完整:

WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".product-detail")))

三、整合后的完整示例代码

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains

# 初始化浏览器(带性能优化配置)
options = webdriver.ChromeOptions()
options.add_argument("--blink-settings=imagesEnabled=false")
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)

def extract_page_offers(url):
    driver.get(url)
    # 等待所有商品加载完成
    WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, ".product-detail")))
    
    products = driver.find_elements(By.CSS_SELECTOR, ".product-detail")
    offers = []
    member_offer_idx = 0
    member_offers = driver.find_elements(By.CSS_SELECTOR, ".panel--check.panel--check__deferred.u-width--50.ng-star-inserted")
    
    for product in products:
        # 尝试提取普通优惠
        normal_offer = product.find_elements(By.CSS_SELECTOR, ".product-detail__pictos--offer.ng-star-inserted")
        if normal_offer and normal_offer[0].text.strip():
            offers.append(normal_offer[0].text.strip())
        else:
            # 尝试提取悬停显示的伪元素内容
            bm_icon = product.find_elements(By.CSS_SELECTOR, ".product-detail__bm-icon")
            if bm_icon:
                offer_text = driver.execute_script("""
                    return window.getComputedStyle(arguments[0], '::after').content;
                """, bm_icon[0]).strip('"')
                offers.append(offer_text)
            else:
                # 备用:提取预加载的会员优惠文本
                offers.append(member_offers[member_offer_idx].text.strip())
                member_offer_idx += 1
    return offers

# 提取目标页面优惠
target_url = "https://www.online.bmsupermercados.es/es/c/ofertas/99999?orderById=5&page=7"
page_offers = extract_page_offers(target_url)
print('\n'.join(page_offers))

# 关闭浏览器
driver.quit()

注意:需将代码中的.product-detail__bm-icon等选择器替换为实际页面的CSS选择器,可通过浏览器开发者工具定位获取。

内容的提问来源于stack exchange,提问作者Fernando

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:36:09