窗⼝的切换
在网页上操作的时候,我们经常遇到,点击一个链接 或者 按钮,就会打开一个 新窗口
。
保存sample1.html到本地
后面代码针对此简单页面写小案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>selenium窗口的切换测试</title>
<script>
function appendEle(info) {
var node = document.createElement("LI");
var textnode = document.createTextNode(info);
node.appendChild(textnode);
document.getElementById("add").appendChild(node);
}
function clickbutton() {
appendEle("你点击了外部按钮");
}
</script>
<style class="mpa-style-fix ImageGatherer">.FotorFrame{position:fixed!important}</style>
<style class="mpa-style-fix SideFunctionPanel">.weui-desktop-online-faq__wrp{top:304px!important;bottom:unset!important}.weui-desktop-online-faq__wrp .weui-desktop-online-faq__switch{width:38px!important}</style>
</head>
<body>
<a href="http://www.bing.com/" target="_blank">访问bing网站</a>
<div><button id="outerbutton" onclick="clickbutton()">功能按钮</button></div>
<br>
<div id="add"><li>你点击了外部按钮</li></div>
</body>
</html>
在打开的网页中,点击 链接 “访问bing网站” , 就会弹出一个新窗口,访问bing网址。
如果我们用Selenium写自动化程序 在新窗口里面 打开一个新网址, 并且去自动化操作新窗口里面的元素,会有什么问题呢?
问题就在于,即使新窗口打开了, 这时候,我们的 WebDriver
对象对应的 还是老窗口,自动化操作也还是在老窗口进行,
我们可以运行如下代码验证一下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/1/6 20:50
# @Author : shisuiyi
# @File : windows_switch.py
# @Software: win10 Tensorflow1.13.1 python3.9
from selenium import webdriver
wd = webdriver.Chrome()
wd.implicitly_wait(10)
wd.get('D:\Lemon\py45\webatuo\selenium切换测试.html')
# 点击打开新窗口的链接
link = wd.find_element("xpath", "//a")
link.click()
# wd.title属性是当前窗口的标题栏 文本
print(wd.title)
运行完程序后,最后一行 打印当前窗口的标题栏 文本, 输出内容是
selenium窗口的切换测试
说明, 我们的 WebDriver
对象指向的还是老窗口,否则的话,运行结果就应该新窗口的标题栏 “微软Bing搜索”
如果我们要到新的窗口里面操作,该怎么做呢?
可以使用Webdriver
对象的switch_to属性的 window方法,如下所示:
wd.switch_to.window(handle)
其中,参数handle需要传入什么呢?
WebDriver
对象有window_handles 属性,这是一个列表对象, 里面包括了当前浏览器里面所有的窗口句柄。
所谓句柄,大家可以想象成对应网页窗口的一个ID,
那么我们就可以通过 类似下面的代码,
# 获取当前所有的窗口
print(wd.window_handles)
for handle in wd.window_handles:
# 先切换到该窗口
wd.switch_to.window(handle)
# 得到该窗口的标题栏字符串,判断是不是我们要操作的那个窗口
if '必应' in wd.title:
# 如果是,那么这时候WebDriver对象就是对应的该该窗口,正好,跳出循环,
break
print(wd.title)
wd.quit()
输出
['CDwindow-42AA7086CC3137F8598456F402B9CB88', 'CDwindow-3C19EE398970DB8D348DB5AA0AA786CD']
必应
上面代码的用意就是:
我们依次获取 wd.window_handles
里面的所有 句柄 对象, 并且调用 wd.switch_to.window(handle)
方法,切入到每个窗口,
然后检查里面该窗口对象的属性(可以是标题栏,地址栏),判断是不是我们要操作的那个窗口,如果是,就跳出循环。
同样的,如果我们在新窗口 操作结束后, 还要回到原来的窗口,该怎么办?
我们可以仍然使用上面的方法,依次切入窗口,然后根据 标题栏 之类的属性值判断。
还有更省事的方法。
因为我们一开始就在 原来的窗口里面,我们知道 进入新窗口操作完后,还要回来,可以事先 保存该老窗口的 句柄,使用如下方法
# mainWindow变量保存当前窗口的句柄
mainWindow = wd.current_window_handle
wd.switch_to.window(wd.window_handles[-1])
print(wd.current_url)
# 通过前面保存的老窗口的句柄,自己切换到老窗口
wd.switch_to.window(mainWindow)
print(wd.title)
输出
https://cn.bing.com/
selenium窗口的切换测试
切换到新窗口操作完后,就可以直接像下面这样,将driver对应的对象返回到原来的窗口
iframe切换
iframe操作有哪些?
切换到iframe
切换回主页面
切换回上一级
切换到frame
如果我们要 选择 下图方框中 所有的 蔬菜,使用css选择,怎么写表达式?
当然,要先查看到它们的html元素特征
大家可能会照旧写出如下代码:
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('http://cdn1.python3.vip/files/selenium/sample2.html')
# 根据 class name 选择元素,返回的是 一个列表
elements = wd.find_elements(By.CLASS_NAME, 'plant')
for element in elements:
print(element.text)
运行一下,你就会发现,运行结果打印内容为空白,说明没有选择到 class 属性值为 plant 的元素。
为什么呢?
因为仔细看,你可以发现, 这些元素是在一个叫 iframe的 元素中的。
这个 iframe 元素非常的特殊, 在html语法中,frame 元素 或者iframe元素的内部 会包含一个 被嵌入的 另一份html文档。
在我们使用selenium打开一个网页是, 我们的操作范围 缺省是当前的 html , 并不包含被嵌入的html文档里面的内容。
如果我们要 操作 被嵌入的 html 文档 中的元素, 就必须 切换操作范围
到 被嵌入的文档中。
怎么切换呢?
使用WebDriver
对象的 switch_to 属性,像这样
wd.switch_to.frame(frame_reference)
其中, frame_reference 可以是 frame 元素的属性 name 或者 ID 。
比如这里,就可以填写 iframe元素的id ‘frame1’ 或者 name属性值 ‘innerFrame’。
像这样
wd.switch_to.frame('frame1')
或者
wd.switch_to.frame('innerFrame')
也可以填写frame 所对应的 WebElement
对象。
我们可以根据frame的元素位置或者属性特性,使用find系列的方法,选择到该元素,得到对应的WebElement
对象
比如,这里就可以写
wd.switch_to.frame(wd.find_element(By.TAG_NAME, "iframe"))
然后,就可以进行后续操作frame里面的元素了。
上面的例子的正确代码如下
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('http://cdn1.python3.vip/files/selenium/sample2.html')
# 先根据name属性值 'innerFrame',切换到iframe中
wd.switch_to.frame('innerFrame')
# 根据 class name 选择元素,返回的是 一个列表
elements = wd.find_elements(By.CLASS_NAME, 'plant')
for element in elements:
print(element.text)
# 输出
土豆
洋葱
白菜
如果我们已经切换到某个iframe里面进行操作了,那么后续选择和操作界面元素 就都是在这个frame里面进行的。
这时候,如果我们又需要操作 主html(我们把最外部的html称之为主html) 里面的元素了呢?
怎么切换回原来的主html呢?
很简单,写如下代码即可
wd.switch_to.default_content()
例如,在上面 代码 操作完 frame里面的元素后, 需要 点击 主html 里面的按钮,就可以这样写
from selenium import webdriver
from selenium.webdriver.common.by import By
wd = webdriver.Chrome()
wd.get('http://cdn1.python3.vip/files/selenium/sample2.html')
# 先根据name属性值 'innerFrame',切换到iframe中
wd.switch_to.frame('innerFrame')
# 根据 class name 选择元素,返回的是 一个列表
elements = wd.find_elements(By.CLASS_NAME, 'plant')
for element in elements:
print(element.text)
# 切换回 最外部的 HTML 中
wd.switch_to.default_content()
# 然后再 选择操作 外部的 HTML 中 的元素
wd.find_element_by_id('outerbutton').click()
wd.quit()
嵌套frame的操作
有时候我们会遇到嵌套的frame,如下:
<html>
<iframe id="frame1">
<iframe id="frame2" / >
</iframe>
</html>
从主文档切到frame2,一层层切进去
driver.switch_to.frame("frame1")
driver.switch_to.frame("frame2")
从frame2再切回frame1,这里selenium给我们提供了一个方法能够从子frame切回到父frame,而不用我们切回主文档再切进来。
driver.switch_to.parent_frame()
# 如果当前已是主文档,则无效果
有了parent_frame()这个相当于后退的方法,我们可以随意切换不同的frame,随意的跳来跳去了。
所以只要善用以下三个方法,遇到frame分分钟搞定:
driver.switch_to.frame(reference)
driver.switch_to.parent_frame()
driver.switch_to.default_content()
弹出对话框
有的时候,我们经常会在操作界面的时候,出现一些弹出的对话框。
首先,将下面html代码保存到一个文件中
后续的代码小案例都是访问此html的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>警告框处理</title>
<script type="text/javascript">
function duihua() {
alert("这个窗口是对话框!");
print('你点击了确认');
}
function queren() {
var se = confirm("确认框!");
if (se == true) {
print('你点击了确认1');
} else {
print('你点击了取消1');
}
}
function tishi() {
var se = prompt("请输入你想学习的Python课程", "Python基础")
if (se == null) {
print('取消操作');
} else {
print('你想学习'+ se);
}
}
function print(text) {
var dom = document.createElement('div')
dom.innerText = text
document.getElementsByTagName('body')[0].appendChild(dom)
}
</script>
</head>
<body>
<input id="bu1" type="button" onclick="duihua()" value="alert"/>
<br>
<br>
<input id="bu2" type="button" onclick="queren()" value="confirm"/>
<br>
<br>
<input id="bu3" type="button" onclick="tishi()" value="prompt"/>
</body>
</html>
分别点击界面的3个按钮,你可以发现:
弹出的对话框有三种类型,分别是 Alert(警告信息)、confirm(确认信息)和prompt(提示输入)
Alert
Alert 弹出框,目的就是显示通知信息,只需用户看完信息后,点击 OK(确定) 就可以了。
那么,自动化的时候,代码怎么模拟用户点击 OK 按钮呢?
selenium提供如下方法进行操作
driver.switch_to.alert.accept()
注意:如果我们不去点击它,页面的其它元素是不能操作的。
如果程序要获取弹出对话框中的信息内容, 可以通过 如下代码
driver.switch_to.alert.text
示例代码如下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/1/6 21:57
# @Author : shisuiyi
# @File : 警告框.py
# @Software: win10 Tensorflow1.13.1 python3.9
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('D:\Lemon\py45\webatuo\警告框.html')
# --- alert ---
driver.find_element(By.ID, 'bu1').click()
# 打印 弹出框 提示信息
print(driver.switch_to.alert.text)
# 点击 OK 按钮
driver.switch_to.alert.accept()
Confirm
Confirm弹出框,主要是让用户确认是否要进行某个操作。
比如:当管理员在网站上选择删除某个账号时,就可能会弹出 Confirm弹出框, 要求确认是否确定要删除。
Confirm弹出框 有两个选择供用户选择,分别是 OK 和 Cancel, 分别代表 确定 和 取消 操作。
那么,自动化的时候,代码怎么模拟用户点击 OK 或者 Cancel 按钮呢?
selenium提供如下方法进行操作
如果我们想点击 OK 按钮, 还是用刚才的 accept方法,如下
driver.switch_to.alert.accept()
如果我们想点击 Cancel 按钮, 可以用 dismiss方法,如下
driver.switch_to.alert.dismiss()
示例代码如下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/1/6 21:57
# @Author : shisuiyi
# @File : 警告框.py
# @Software: win10 Tensorflow1.13.1 python3.9
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('D:\Lemon\py45\webatuo\警告框.html')
# --- confirm ---
driver.find_element(By.ID, 'bu2').click()
# 打印 弹出框 提示信息
print(driver.switch_to.alert.text)
# 点击 OK 按钮
driver.switch_to.alert.accept()
driver.find_element(By.ID, 'bu2').click()
# 点击 取消 按钮
driver.switch_to.alert.dismiss()
Prompt
出现 Prompt 弹出框 是需要用户输入一些信息,提交上去。
可以调用如下方法
driver.switch_to.alert.send_keys()
示例代码如下
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(5)
driver.get('D:\Lemon\py45\webatuo\警告框.html')
# --- prompt ---
driver.find_element(By.ID, 'bu3').click()
# 获取 alert 对象
alert = driver.switch_to.alert
# 打印 弹出框 提示信息
print(alert.text)
# 输入信息,并且点击 OK 按钮 提交
alert.send_keys('web自动化 - selenium')
alert.accept()
# 点击 Cancel 按钮 取消
driver.find_element(By.ID, 'bu3').click()
alert = driver.switch_to.alert
alert.dismiss()
注意 : 有些弹窗并非浏览器的alert 窗口,而是html元素,这种对话框,只需要通过之前介绍的选择器选中并进行相应的操作就可以了。
切换到shadow-root
在做web自动化的时候,一些元素在shadow-root的节点下,使得selenium中无法通过xpath来定位
这里的 #shadow-root 所包含的内容其实就是所谓的 shadow-dom 。
shadow-dom 其实是浏览器的一种能力,它允许在浏览器渲染文档(document)的时候向其中的 Dom 结构中插入一棵 DOM 元素子树,但是特殊的是,这棵子树(shadow-dom)并不在主 DOM 树中。
操作shadow-root内的元素
您必须使用shadowRoot.querySelector(),并且可以使用以下定位器策略:
实现步骤:
先定位到shadow-root的宿主节点
在切换到shadow-root中
在选择shadow-root下的标签:
案例如下
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2023/3/11 8:31
# @Author : shisuiyi
# @File : 13_#shadow-root.py
# @Software: win10 Tensorflow1.13.1 python3.9
from selenium import webdriver # 引入webdriver
from webdriver_manager.chrome import ChromeDriverManager
import time # time模块
browser = webdriver.Chrome(ChromeDriverManager().install())
url = "https://www.immowelt.de/immobilienpreise"
print('url is ' + url)
browser.maximize_window()
browser.get(url) # 发送url请求
time.sleep(5) # 等待时间
element = browser.execute_script("""return document.querySelector('#usercentrics-root').shadowRoot.querySelector(
"button[data-testid='uc-accept-all-button']")""")
element.click()
"""
要单击OK,您必须使用shadowRoot.querySelector(),并且可以使用以下定位器策略:
实现步骤:
1.先定位到shadow-root的宿主节点:document.querySelector('#usercentrics-root')
2.在切换到shadow-root中:shadowRoot.querySelector(button[data-testid='uc-accept-all-button'])
3.在选择shadow-root下的标签:
"""
time.sleep(4)
browser.quit() # 关闭所有与当前driver相关的窗口
# browser.close() #关闭当前窗口
评论