1. 多窗口处理
1.1 多窗口的概念
selenium里面如何处理多窗口场景
- 多窗口识别
- 多窗口之间的切换
点击某个链接,会重新打开一个窗口,这种情况,想在新页面上操作,就得先切换窗口
selenium里面如何处理frame
- 多个frame识别
- 多个frame之前切换
获取窗口的唯一标识句柄,切换句柄,即可实现多页面的灵活切换
1.2 多窗口的处理步骤
- 首先获取当前窗口句柄(driver.current_window_handle)
- 再获取所有窗口句柄(driver.window_handles)
- 判断是否是想要的操作窗口,如果是,就可以对窗口操作,如果不是,就切换窗口(driver.switch_to_window)操作
案例
- 打开百度
- 点击登录
- 弹框中点击"立即注册",输入账户和密码
- 返回登录页,点击登录
- 输入用户名密码,点击登录
from selenium import webdriver class setupTeardown: def setup(self): self.driver = webdriver.Chrome() self.driver.implicitly_wait(5) self.driver.maximize_window() def teardown(self): self.driver.quit()
from time import sleep from UI.SetupTeardown import setupTearwodn class TestWindows(setupTearwodn): def test_windows(self): self.driver.get(\'https://www.baidu.com/\') print(self.driver.window_handles) print(self.driver.current_window_handle) self.driver.find_element_by_xpath(\'//*[@id="u1"]/a[2]\').click() self.driver.find_element_by_link_text(\'立即注册\').click() print(self.driver.current_window_handle) print(self.driver.window_handles) sleep(1) windows = self.driver.window_handles self.driver.switch_to.window(windows[1]) self.driver.find_element_by_xpath(\'//*[@name="userName"]\').send_keys(\'hi\') sleep(1) self.driver.switch_to.window(windows[0]) self.driver.find_element_by_id(\'TANGRAM__PSP_11__footerULoginBtn\').click() self.driver.find_element_by_name(\'userName\').send_keys(\'hi\') sleep(1)
2. frame
在web自动化中,如果一个元素定位不到,很大可能是在iframe中
2.1 什么是iframe?
frame是HTML中的框架,在html中,所谓的框架就是可以在同一个浏览器中显示不止一个页面
基于HTML的框架,又分为垂直框架和水平框架(cols,rows)
2.2 frame 分类
- frame标签包含:frameset frame iframe三种
- frameset和普通的标签一样,不会影响定位,可以使用index、id、name、webelement任意方式定位frame
- 而frame与iframe对selenium定位而言是一样的,selenium有一组方法对frame进行操作
https://www.w3school.com.cn/tiy/t.asp?f=html_frame_cols
2.3. 多frame切换
frame存在两种:嵌套的,和未嵌套的
处理未嵌套的iframe
- driver.switch_to_frame("frame的 id")
- driver.switch_to_frame("frame-index") frame无ID时依据索引来处理,索引从0开始 driver.switch_to_frame(0)
处理嵌套的iframe
- 对于嵌套的先进入到iframe的父节点,再进入子节点,然后对子节点里的对象进行处理
- driver.switch_to.frame("节点")
切换frame
- driver.switch_to.frame() # 根据元素id或者index切换frame
- driver.switch_to.default_content() #切换到默认frame
2.4 frame嵌套页面元素定位实战
案例:在Frame.html文件种定位搜狗搜索页面,进行搜索操作
#/usr/bin python #-*- coding:UTF-8 -*- #####################嵌套框架##################### from selenium import webdriver from time import sleep driver = webdriver.Chrome() #设置网页文件路径,r代表转译 filr_path = r\'E:\study\python\我要自学网-python+selenium\脚本与课件\4-22~4-32 Script\Frame.html\' driver.get(filr_path) #切换到frame页面内,search 为嵌套页面的id driver.switch_to.frame(\'search\') #定位到搜索框按钮输入关键词 driver.find_element_by_id(\'query\').send_keys(\'selenium 官网\') driver.find_element_by_css_selector(\'#stb\').click() sleep(3) driver.quit()
Frame.xml文件内容
<html> <head> <title>Frame_test</title> </head> <body> <div> <iframe id="search" src="http://www.sogou.com" width="800" height="500"> </div> </body> <html>
switch_to_frame() 默认可以直接取表单的 id 或 name 属性进行切换。
那么如果 iframe 没有可用的 id 和 name 可以通过下面的方式进行定位:
…… #先通过 xpth 定位到 iframe xf = driver.find_element_by_xpath(\'//*[@class="if"]\') #再将定位对象传给 switch_to_frame()方法 driver.switch_to_frame(xf) …… driver.switch_to_default_content()
如果完成了在当前表单上的操作可以通过 switch_to_default_content()方法返回到上一层表单。该方法不用指定某个表单的返回,默认对应与它最近的 switch_to_frame()方法。
2.5 多窗口切换操作
案例:打开我要自学网Selenium课程主页,然后打开4-14课程详情页面,再回到课程主页打开4-15课程详情页面
#/usr/bin python #-*- coding:UTF-8 -*- ######################多窗口切换操作###################### from selenium import webdriver from time import sleep driver = webdriver.Chrome() #打开selenium课程页面 51自学网由于不能保存,暂且切换为百度 driver.get(\'http://www.baidu.com/list.aspx?page=3&cid=615\') # 获取课程主页的窗口句柄 (通过窗口句柄来找到浏览器窗口) selenium_index = driver.current_window_handle sleep(2) driver.find_element_by_partial_link_text(\'4-14\').click() sleep(2) #切换到主页窗口 driver.switch_to.window(selenium_index) sleep(2) driver.find_element_by_partial_link_text(\'4-15\').click() sleep(2) driver.quit()
#encoding=utf-8 import unittest import time import chardet from selenium import webdriver class VisitSogouByIE(unittest.TestCase): def setUp(self): # 启动chrome浏览器 self.driver = webdriver.Chrome() def test_operateWindowHandle(self): url = "http://www.baidu.com" self.driver.get(url) # 获取当前窗口句柄 now_handle = self.driver.current_window_handle # 打印当前获取的窗口句柄 print(now_handle) # 百度搜索输入框中输入“selenium” self.driver.find_element_by_id("kw").send_keys("w3cschool") # 点击搜索按钮 self.driver.find_element_by_id("su").click() # 导入time包 import time # 等待3秒,以便网页加载完成 time.sleep(3) # 点击w3school在线教育链接 self.driver.find_element_by_xpath(\'//*[@id="2"]/h3/a\').click() time.sleep(5) # 获取所有窗口句柄 all_handles = self.driver.window_handles print("++++", self.driver.window_handles[-1]) # 循环遍历所有新打开的窗口句柄,也就是说不包括主窗口 for handle in all_handles: if handle != now_handle: # 切换窗口 self.driver.switch_to.window(handle) # 点击HTML5链接 self.driver.find_element_by_link_text(\'HTML5\').click() time.sleep(3) # 关闭当前的窗口 self.driver.close() time.sleep(3) # 打印主窗口句柄 print(now_handle) # 返回主窗口 self.driver.switch_to.window(now_handle) time.sleep(2) self.driver.find_element_by_id("kw").clear() self.driver.find_element_by_id("kw").send_keys(u"光荣之路自动化测试培训") self.driver.find_element_by_id("su").click() time.sleep(5) def tearDown(self): # 退出IE浏览器 self.driver.quit() if __name__ == \'__main__\': unittest.main()
3. 警告弹框的处理
在页面上操作中有事会遇到JS所生成的alert、confirm、以及prompt弹框,可以使用switch_to.alert()定位到,然后使用text/accept/dismiss/send_keys等方法进行操作
- div : 也是一个弹框,但是上面会有一个复杂的操作,比如百度首页->登录的弹框
- alert: 简单的弹框,一般只有确定和取消按钮, 比如在console中输入 window.alert(\'你好呀\')
- window: 新的窗口, 比如百度首页点击新闻打开一个新的窗口
操作alert的常用方法:
- switch_to.alert() : 获取当前页面上的警告框
- text:返回alert、confirm、以及prompt的文字信息
- accept(): 接受现有的警告框
- dismiss():取消现有的告警框
- send_keys(keysToSend): 方文本到警告框
代码示范:https://github.com/fanpl-sourse/all_study_practice/blob/master/myUIautotest/test_frame.py
案例:点击百度首页设置按钮,然后进入搜索设置页面,点击“保存设置”或“恢复默认”按钮,处理警告弹窗窗口
#/usr/bin python #-*- coding:UTF-8 -*- #####################警告弹窗处理##################### from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get(\'https://www.baidu.com/\') ##点击设置按钮 driver.find_element_by_link_text(\'设置\').click() sleep(2) ##点击搜索设置按钮 # driver.find_element_by_link_text(\'搜索设置\').click() driver.find_element_by_class_name(\'setpref\').click() #这个元素在火狐浏览器定位更清晰一些 sleep(3) ##点击保存设置 # driver.find_element_by_css_selector(\'.prefpanelgo\').click() ##点击恢复设置 driver.find_element_by_link_text(\'恢复默认\').click() sleep(2) ##处理警告窗口 alert = driver.switch_to.alert.accept() sleep(2) driver.quit()
4. 上传文件
input标签可以直接使用send_keys(本地文件地址)上传文件
用法:
- e = driver.find_element(By.XPATH,"上传按钮XPATH")
- e.send_keys(\'文件路径+文件名\')
#/usr/bin python #-*- coding:UTF-8 -*- ####################上传文件#################### from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get(\'https://www.baidu.com/\') driver.find_element_by_css_selector(".soutu-btn").click() sleep(3) driver.find_element_by_css_selector(".upload-pic").send_keys(r"E:\study\python\我要自学网-python+selenium\脚本与课件\4-22~4-32 Script\shuiyin.png") sleep(3) driver.quit()
5. 执行js脚本
5.1 js简介
selenium能执行js,使得selenium拥有更强大的能力,既然能执行js,那么js能做的事情,selenium大部分也可以做
- 直接使用js操作页面,能解决很多click()不生效的问题
- 页面滚动到底部,顶部
- 处理富文本,时间控件的输入
5.2 js用法
js代码示例
windows.alert(\'弹出一个框\') : 在当前页面弹出一个框
document.title:获取当前页面的标题
json.stringify(performance.timing) : 获取当前页面的性能数据
a = document.getElementById(\'kw\').value
document.documentElement.scroll=10000 : 滚动到页面底部
5.3 selenium调用js
- execute_script() : 执行js
- return: 可以返回js的返回结果
- execute_script: arguments传参
driver.execute_script(\'windows.alert("谈个框")\')
driver.execute_script(a = document.getElementById(\'kw\').value)
driver.execute_script(\'return document.getElementById(\'kw\').value\')
场景一: 页面元素太多需要滑倒底部进行查看
滚动条操作控制
案例:打开我要自学网页面,然后将滚动条拖到最底部,然后再拖到顶部
#/usr/bin python #-*- coding:UTF-8 -*- ####################滚动条#################### from selenium import webdriver from time import sleep driver = webdriver.Chrome() # driver.get(\'https://www.baidu.com/\') 网址由51自学改为 百度 driver.get("http://www.baidu.com/") sleep(2) #将滚动调拖到最底部 js="var action=document.documentElement.scrollTop=10000" driver.execute_script(js) sleep(3) #将滚动条拖到最顶部 js="var action=document.documentElement.scrollTop=0" driver.execute_script(js) sleep(3) driver.quit()
一般用到操作滚动条的会两个场景:
- 注册时的法律条文的阅读,判断用户是否阅读完成的标准是:滚动条是否拉到最下方。
- 要操作的页面元素不在视觉范围,无法进行操作,需要拖动滚动条。
用于标识滚动条位置的代码
…… <body onload= "document.body.scrollTop=0 "> <body onload= "document.body.scrollTop=100000 "> ……
document.body.scrollTop网页被卷去的高。scrollTop 设置或获取滚动条与最顶端之间的距离。如果想让滚动条处于顶部,那么可以设置 scrollTop 的值为 0,如果想让滚动条处于最底端,可以将这个值设置的足够大,大个窗口的高度即可。scrollTop 的值以像素为单位。
#将页面滚动条拖到底部 js="var q=document.documentElement.scrollTop=10000" driver.execute_script(js) sleep(3) #将滚动条移动到页面的顶部 js_="var q=document.documentElement.scrollTop=0" driver.execute_script(js_) sleep(3)
场景二:时间控件
大部分时间控件是readonly属性,需要手动选择对应的时间,手工测试很容易做到,自动化中对控件的操作可以用js来实现
操作思路:
- 取消日期的readonly属性
- 给value赋值
- 写js代码来实现以上两点,再webdriver对js处理
# -*- coding: utf-8 -*- # @Time : 2020/10/21 10:00 # @Author : 饭盆里 # @File : test_js.py # @Software: PyCharm # @desc : js相关操作 from time import sleep from selenium import webdriver from selenium.webdriver import TouchActions from selenium.webdriver.common.by import By class TestJs(): def setup(self): option = webdriver.ChromeOptions() option.add_experimental_option(\'w3c\',False) self.driver = webdriver.Chrome(options=option) def teardown(self): self.driver.quit() def test_js_scroll(self): self.driver.get(\'https://www.baidu.com/\') searchelement = self.driver.find_element(By.ID,\'kw\') searchelement.send_keys(\'selenium官网\') self.driver.find_element(By.ID,\'su\').click() sleep(2) """ # 功能同js action = TouchActions(self.driver) action.scroll_from_element(searchelement,0,10000) action.perform() sleep(2) """ js = \'document.documentElement.scroll=10000\' self.driver.execute_script(js) self.driver.find_element(By.XPATH,\'//*[@id="page"]//a[last()]\').click() sleep(2) def test_js_time(self): """ 对时间控件进行赋值 :return: """ self.driver.get(\'https://www.12306.cn/index/\') sleep(2) js = \'a = document.getElementById("train_date"), a.value = "2020-10-06"\' self.driver.execute_script(js) sleep(2)
定位不到的4个原因:
1. 层级没找对, 解决办法:从上一个层级进行定位,一层一层定
2.没等加载出来就定位,解决办法:sleep(2)
3.嵌套了iframe 解决办法:switch_to_frame()
4.动态生成的
6. 多浏览器
import os from time import sleep from selenium import webdriver class Test_browser(): def setup(self): browser = os.getenv(\'browser\') if browser == \'firefox\': self.driver = webdriver.Firefox() elif browser == \'headless\': self.driver = webdriver.PhantomJS() else: self.driver = webdriver.Chrome() self.driver.maximize_window() self.driver.implicitly_wait(5) def teardown(self): self.driver.quit() def test_baidu(self): self.driver.get(\'https://www.baidu.com/\') sleep(2)
命令行运行:browser=\'Chrome\' pytest test_browser.py