使用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
相关产品推荐
相关产品推荐

