首先这个控件和iframe有异曲同工之妙,也是嵌套的一个html,所以定位不能像普通定位一样
下面实践一下
首先准备一个root.html
<!DOCTYPE html>
<html>
<head>
<title>带有shadow-root的页面</title>
</head>
<body>
<h1 class="test">带有shadow-root的页面</h1>
<template id="shadowRootTemplate">
<style>
/* 在shadow root中定义样式 */
.message {
color: blue;
font-size: 18px;
}
</style>
<div class="message">
这是一个带有shadow-root的页面。
</div>
</template>
<script>
// 获取template元素
const template = document.querySelector('#shadowRootTemplate');
// 在<body>中创建shadow root
const shadowRoot = document.body.attachShadow({ mode: 'open' });
// 将template内容复制到shadow root中
const templateContent = template.content.cloneNode(true);
shadowRoot.appendChild(templateContent);
</script>
</body>
</html>
这里偷个懒,使用python http服务启动一个临时的页面
python -m http.server
成功之后访问 http://localhost:8000/root.html
这样我们就具备了一个临时测试用的页面了
正题
首先 selenium 给元素对象提供了一个shadow_root的方法
我们先来定位到shadow-root元素的父级节点
driver.find_element(By.TAG_NAME, 'body')
然后根据父级节点的元素对象找到该元素下面的shadow-root
root_ele = driver.find_element(By.TAG_NAME, 'body')
ele = root_ele.shadow_root
此时,我们就可以使用ele元素对象去定位ele元素对象下的元素
例如:
ele.find_element(By.CSS_SELECTOR, '.message').get_attribute('innerText')
这样就可以对元素进行操作了
完整代码
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Edge()
driver.get('http://localhost:8000/root.html')
driver.implicitly_wait(10)
# 定位shadow-root的父元素
root_ele = driver.find_element(By.TAG_NAME, 'body')
# 获取shadow-root对象
ele = root_ele.shadow_root
# 使用css 定位 shadow-root 下的元素
print(ele.find_element(By.CSS_SELECTOR, '.message').get_attribute('innerText'))