为了在 封装性 和 可访问性 之间提供不同的权衡,Shadow Root 拥有 open 和 closed 两种状态。

在标准的 Shadow DOM 规范中,当一个 Shadow Root 在初始化时设置的是 closed 状态的, 不仅后续无法重新设置为 open 状态,更无法直接获取到该 Shadow Root 实例。这是因为 closed 状态的 Shadow Root 被认为是“不可见”的,“不可见”表现在: 无法使用 element.shadowRoot 直接访问到该 Shadow Root。比如,下面这个页面的 my-component 组件,我们就无法直接获取到 Shadow Root:

如何获取 closed 状态的 Shadow Root?
但当我们在使用 Chrome Extension 或者 Puppeteer 自动化框架抓取数据时,难免会遇到这种情况,那该怎么办呢?
很幸运的是,Chrome Extension 官方就有相关 API 可以直接使用,而 Puppeteer 也可以使用奇技淫巧去强制开启 Shadow Root 来达到目的。
一、Chrome Extension 的 chrome.dom API 方案
Chrome Extension 中 chrome.dom.openOrClosedShadowRoot API 的设计目的就是为了让扩展的 Content Script(内容脚本)能够绕过 Web Component 的封装特性,访问处于 closed 状态的 Shadow Root。
例如,我们可以写一个极简的插件来实现:获取上述 html 中的 internal-span 中的 data-value 属性值。

二、Puppeteer 强制开启 Shadow Root 方案
事实上,Puppeteer 并没有直接提供一个等效于 chrome.dom.openOrClosedShadowRoot 的 API,这是因为它们的工作原理和应用场景有所不同:
浏览器默认行为: 在正常的浏览器环境中,无论是通过页面 JavaScript 还是 Puppeteer 默认的 DOM 查询方法(如
page.$()、page.evaluate()中的document.querySelector()),都无法访问处于closed模式的 Shadow Root。这是 Web Component 规范的安全设计;扩展权限: Chrome 扩展的
chrome.dom.openOrClosedShadowRoot是一个特殊的、高权限的 API,它仅在扩展的 Content Script 中可用,用于解决扩展与 Web Component 交互的问题,它超越了标准的 Web 安全模型;Puppeteer 的定位: Puppeteer 主要是一个通过 DevTools Protocol (CDP) 自动化控制 标准浏览器行为 的库。它通常遵循 Web 页面的标准限制。
但是,为了迎合从第三方网站获取一个非公开数据属性的场景,强制开启 Shadow Root(Monkey Patching)仍然是最有效的方法,虽然该方法其实会带来严重的安全性、稳定性问题(一个封闭的 Shadow Root 环境被强制开启 本就是一个危险的操作)。











