Java+Selenium爬取Shadow DOM报错Cannot read properties of null求解
报错原因
这个报错的核心原因是 document.querySelector('pdf-viewer') 执行时没有匹配到对应DOM元素,返回了null,后续调用shadowRoot属性时就触发了空指针异常。你可以按以下步骤排查解决:
解决方案
- 增加元素加载等待逻辑
大部分场景下报错是因为执行JS脚本时,pdf-viewer自定义元素还未完成渲染。你可以先通过Selenium显式等待确认元素已经加载到DOM树中,再执行JS提取属性,同时可以直接把已经定位到的元素传入JS,避免二次查询失败:
// 先等待pdf-viewer元素加载完成 WebElement pdfViewer = new WebDriverWait(driver, Duration.ofSeconds(10)) .until(ExpectedConditions.presenceOfElementLocated(By.tagName("pdf-viewer"))); // 再执行JS脚本获取属性 String pagePdfUrl = (String) js.executeScript("return arguments[0].shadowRoot.getElementById('content').querySelector('embed').getAttribute('original-url')", pdfViewer);
校验选择器与DOM层级正确性
- 确认页面中
pdf-viewer元素确实直接挂载在document下,没有嵌套在<iframe>标签内。如果位于iframe中,需要先调用driver.switchTo().frame()切换到对应iframe后再执行操作。 - 可以先在浏览器控制台手动执行你的JS脚本,确认每一步的返回值是否正常,排查是否是
content元素、embed元素的选择器写错导致的查询失败。
- 确认页面中
优化JS脚本增加空值兼容
你可以把JS脚本改写为带空判断的版本,避免直接抛出异常,同时方便定位哪一步出现了查询失败:
String jsScript = """ const pdfViewer = document.querySelector('pdf-viewer'); if (!pdfViewer || !pdfViewer.shadowRoot) return null; const contentEl = pdfViewer.shadowRoot.getElementById('content'); if (!contentEl) return null; const embedEl = contentEl.querySelector('embed'); return embedEl ? embedEl.getAttribute('original-url') : null; """; String pagePdfUrl = (String) js.executeScript(jsScript);
- 可选方案:使用Selenium原生Shadow DOM API(Selenium 4.0+支持)
如果你使用的是Selenium 4及以上版本,可以不用手写JS脚本,直接通过原生API操作Shadow DOM,写法更易维护:
// 定位pdf-viewer元素 WebElement pdfViewer = new WebDriverWait(driver, Duration.ofSeconds(10)) .until(ExpectedConditions.presenceOfElementLocated(By.tagName("pdf-viewer"))); // 获取ShadowRoot实例 SearchContext shadowRoot = pdfViewer.getShadowRoot(); // 在Shadow DOM中定位元素并提取属性 String pagePdfUrl = shadowRoot.findElement(By.id("content")) .findElement(By.tagName("embed")) .getAttribute("original-url");
内容的提问来源于stack exchange,提问作者NoobCoder
相关产品推荐
相关产品推荐

