資料來源:
- Shadow DOM :獨立的Web組件
https://www.gss.com.tw/blog/shadow-dom-%EF%BC%9A%E7%8D%A8%E7%AB%8B%E7%9A%84web%E7%B5%84%E4%BB%B6 - Using shadow DOM
https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM - ShadowRoot
https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot
測試 #host 內容為空值, 無法存取到 table tag, 在 browser console 看到的內容:

使用 nodriver 取得的 shadow root tag 裡的內容:

demo source code:
#!/usr/bin/env python3
#encoding=utf-8
import asyncio
import nodriver as uc
async def main():
driver = await uc.start()
URL1 = "https://stackoverflow.max-everyday.com/2025/07/javascript-shadowroot-demo/"
if not driver is None:
await driver.get(URL1)
await driver.sleep(1)
demo_tab = driver.main_tab
try:
select_query = "#host"
div_host: Element = await demo_tab.query_selector(select_query)
if div_host:
if div_host.shadow_roots:
iframe: Node = div_host.shadow_roots[0]
if iframe:
for node_table in iframe.children:
if node_table.local_name=='table':
for node_tbody in node_table.children:
if node_tbody.local_name=='tbody':
for node_tr in node_tbody.children:
if node_tr.local_name=='tr':
for node_td in node_tr.children:
if node_td.local_name=='td':
for node_text in node_td.children:
if node_text.node_name=='#text':
print("node value:", node_text.node_value)
except Exception as exc:
print(exc)
pass
if __name__ == "__main__":
uc.loop().run_until_complete(main())