Python Selenium爬取施耐德网站遇NoSuchElementException报错求解
Selenium无法定位Shadow DOM内元素问题解决方案
问题原因
你遇到的NoSuchElementException报错核心原因是:普通Selenium定位方法(XPath、CSS选择器等)无法直接穿透#shadow-root (open)边界。该施耐德页面使用了Web Component技术,<product-cards-wrapper>、<product-card>、<product-card-main-info>这类自定义标签都是Shadow DOM的宿主元素,直接跨宿主写XPath是完全找不到内部元素的。
另外你的代码还存在两个额外问题:
- 绝对XPath过于脆弱,页面DOM结构稍有调整就会失效
- 翻页按钮的定位使用
By.CLASS_NAME传了多类名(带空格),本身也会触发定位失败
解决步骤
1. 逐层穿透Shadow DOM获取元素
Selenium 4.0+已经原生支持Shadow DOM操作,只要逐层获取每个宿主的shadow_root属性,就可以在对应的Shadow DOM树内查找子元素。
2. 改用相对定位+显式等待
替换绝对XPath为更稳定的CSS选择器,使用显式等待替代固定隐式等待,避免元素未加载完成就执行定位。
3. 修复翻页按钮定位逻辑
多类名定位改用CSS选择器格式。
可运行修改代码示例
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 初始化driver driver = webdriver.Chrome() driver.implicitly_wait(5) wait = WebDriverWait(driver, 10) # 封装穿透Shadow DOM的元素获取工具 def get_shadow_element(parent, selector): # parent可以是普通WebElement,也可以是ShadowRoot对象 if hasattr(parent, 'shadow_root'): shadow_root = parent.shadow_root else: shadow_root = parent return wait.until(lambda d: shadow_root.find_element(By.CSS_SELECTOR, selector)) def page_function(): driver.get('https://www.se.com/us/en/product-range/63426-powerlogic-accusine-pcs%2B/?N=4176697776&No=0&Nrpp=12') driver.maximize_window() total = 69 print("Number of products:", total) description = [] unit_price = [] name = [] for page in range(0, (total//12)+1): # 等待当前页产品列表加载完成 cards_wrapper = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'product-cards-wrapper'))) # 穿透第一层shadow root,拿到产品列表 cards_wrapper_shadow = cards_wrapper.shadow_root product_items = wait.until(lambda d: cards_wrapper_shadow.find_elements(By.CSS_SELECTOR, 'ul.product-cards > li')) for item in product_items: # 穿透product-card的shadow root product_card = item.find_element(By.CSS_SELECTOR, 'product-card') card_shadow = product_card.shadow_root # 穿透product-card-main-info的shadow root main_info = card_shadow.find_element(By.CSS_SELECTOR, 'product-card-main-info') main_info_shadow = main_info.shadow_root # 提取所需字段 des_ele = main_info_shadow.find_element(By.CSS_SELECTOR, 'pes-router-link:nth-child(2) a h3') description.append(des_ele.text) name_ele = main_info_shadow.find_element(By.CSS_SELECTOR, 'pes-router-link:nth-child(1) a') name.append(name_ele.text) # 提取价格 price_ele = card_shadow.find_element(By.CSS_SELECTOR, 'pes-product-price p span:first-child') unit_price.append(price_ele.text) # 翻页逻辑 if len(name) >= total: break next_btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.page-links__arrow.page-links__arrow--next.js-page-link.js-page-link-next'))) driver.execute_script("arguments[0].click();", next_btn) # 等待翻页后内容刷新 wait.until(EC.staleness_of(cards_wrapper)) print("名称列表:", name) print("描述列表:", description) print("价格列表:", unit_price) if __name__ == '__main__': page_function() driver.quit()
注意事项
- 请确保你的Selenium版本升级到4.0以上,低版本不支持原生
shadow_root属性操作 - 代码内的CSS选择器可以根据页面实际结构微调,比绝对XPath稳定性高很多
- 抓取过程中可以适当增加延迟,避免触发网站反爬机制
内容的提问来源于stack exchange,提问作者Jorge Jurado-Garcia
相关产品推荐
相关产品推荐

