Python Selenium用JS定位#shadow-root (open)中PDF下载按钮失败问题
Selenium多层Shadow DOM元素定位报错解决方案
报错原因
你遇到的JavascriptException: Message: javascript error: Cannot read properties of null (reading 'shadowRoot')错误,核心是执行JS查询时,某一层的自定义DOM节点尚未加载完成,querySelector返回了null,读取null的shadowRoot属性触发了报错。
还有两个前置问题也会导致该错误:
- 点击PDF查看按钮后页面可能新开标签页,你没有切换到对应标签页执行查询
- 前置步骤的元素定位写法有误,导致流程根本没有走到PDF加载的环节
修复步骤
1. 修复前置步骤的元素定位错误
原代码中driver.find_elements_by_class_name("list_2[href]")写法不符合API规范,class_name方法只能传入纯类名,不能带属性筛选条件,要改为CSS选择器写法:
# 修复前 # url_list = driver.find_elements_by_class_name("list_2[href]") # 修复后 url_list = driver.find_elements_by_css_selector(".list_2[href]")
2. 确认上下文是否正确
点击view_pdf按钮后如果浏览器新开了PDF预览标签页,需要先切换到新标签页再执行DOM查询:
# 切换到最新打开的标签页 window_handles = driver.window_handles driver.switch_to.window(window_handles[-1])
3. 增加加载等待+优化穿透JS的鲁棒性
PDF阅读器的自定义元素需要等PDF资源加载完成后才会渲染到DOM树,要增加等待时间,同时JS脚本每一层都做非空判断,避免空指针报错:
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待PDF页面加载完成,也可以替换为time.sleep(3)做简单测试 WebDriverWait(driver, 10).until(lambda d: d.execute_script("return document.querySelector('pdf-viewer') != null")) # 逐层穿透shadow DOM,每层做非空校验 download_controls = driver.execute_script(""" // 第一层:找pdf-viewer const pdfViewer = document.querySelector('pdf-viewer'); if (!pdfViewer) return null; // 第二层:穿透找viewer-toolbar const toolbar = pdfViewer.shadowRoot.querySelector('viewer-toolbar'); if (!toolbar) return null; // 第三层:穿透找下载控件 return toolbar.shadowRoot.querySelector('viewer-download-controls'); """) if download_controls: # 触发下载操作 download_controls.click() else: print("未找到下载控件,请检查页面结构是否发生变化")
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

