基于python的Selenuim自动化UI测试
1.环境配置
-
给python安装selenuim
-
python:
pip3 install selenium
-
Pycharm:
pycharm->perferences->project interpreter->+号->搜索selenium->左下角install package
-
-
安装驱动
-
驱动下载:Goole驱动下载地址 搜狐驱动下载地址
-
下载的驱动版本要和浏览器的版本一致,Goole浏览器在
帮助->关于Goole->版本 85.0.4183.102(正式版本)
,下载时就需要下载85.0.4183版本对应的驱动。 -
驱动安装路径:
下载完驱动后接压缩,将解压缩后的
Chromedriver
放置在苹果电脑的Gooleusr->local->bin
路径下。依旧打不开时将
系统偏好设置->安全性与隐私->点击锁按钮允许更改->允许app运行
来允许该驱动运行。
-
2.编写第一个自动化脚本
from selenium import webdriver#导入selenium的webdriver包,调用webdriver API接口
import time
driver = webdriver.Chrome()#初始化Goole浏览器对象,启动浏览器
driver.get("http://www.baidu.com")#通过get()方法向浏览器发送网址
#通过元素id=kw定位到搜索框,键盘输入方法send_keys()输入关键字Selenium2
driver.find_element_by_id("kw").send_keys("Selenium2")
#通过元素id=kw定位到“百度一下”搜索按钮,并向其发送单击事件click()
driver.find_element_by_id("su").click()
time.sleep(10)
driver.quit()#退出并关闭浏览器及相关驱动
3.元素定位
1.python中元素定位的方法:
-
id
-
Class name
-
link text
-
Xpath
-
find_element_by_id()
-
``find_element_by_class_name()`
-
``find_element_by_link_text()`
-
``find_element_by_xpath()`
-
通过
打开Goole浏览器-> 更多工具->开发者工具->使用左上角按钮,点击百度搜索框,会自动显示对应HTML代码,可以看到id=‘kw’
2.id、name、class定位
- id属性
- 在HTML文档中必须是唯一的
find_element_by_id("kw")
方法通过id属性定位搜索
元素
- name属性
- 在HTML文档中可以不唯一
find_element_by_name("wd")
方法通过name属性定位搜索
元素
- class属性
find_element_by_class_name("s_ipt")
方法通过class属性定位搜索
元素
3.tag 定位
- tagname其实就是HTML的标签。不过一个HTML文件里面相同的标签肯定很多,一般很少用到。
- 基本都是定位父元素,然后父元素定位下面所有tagname元素,再根绝其他条件去操作。比如表格啥的。
find_element_by_tag_name("")
方法通过tagname属性定位元素
4.link定位
-
这是用来定位文字超链接的,可以通过文字链接部分的文字描述,定位百度首页上的更多按钮
-
find_element_by_link_text("更多").cilck()
方法通过link属性定位更多
元素
5.partil link定位
- partil link定位是对link定位的一种补充,和link_text区别在于,有些文本链接比较长,这个相当于模糊搜索,只输入部分文字描述就可以了。
driver.find_element_by_partial_link_text("更").click()
方法通过partial_link属性定位更多
元素
6.Xpath定位
-
find_element_by_xpath()
-
XPath是在XML文档中定位元素的语言,可参考考:http://www.w3school.com.cn/xpath/index.asp
-
绝对路径定位
- 参考baidu.html前端工具所展示的代码,我们可以通过下面的方式找到百度输入框和搜索按钮。
- find_element_by_xpath()方法使用XPath语言来定位元素。XPath主要用标签名的层级关系来定位元素的绝对路径,最外层为html语言。在body文本内,一级一级往下查找,如果一个层级下有多个相同的标签名,那么就按上下顺序确定是第几个,例如,div[5]表示当前层级下的第二个div标签
#找到输入按钮
driver.find_element_by_xpath("/html/body/div/div/div[5]/div/div/form/span/input").send_keys("Selenium2")
#搜索按钮
driver.find_element_by_xpath("/html/body/div/div/div[5]/div/div/form/span[2]/input").click()
-
利用元素属性定位
- 除了使用绝对路径外,XPath 也可以使用元素的属性值来定位。同样以百度输入框和搜索按钮为例:
- //表示当前页面某个目录下,input 表示定位元素的标签名,[@id="kw"]表示这个元素的 id 属性值等于 kw。下面通过name和class属性值来定位。
- 可以直接在开发者工具中复制xpath,注意外层 " 符号和内层 ‘ 符号,两者相同会因无法区分而报错
#输入按钮
find_element_by_xpath("//*[@id='kw']")
#搜索按钮
find_element_by_xpath("//*[@id='su']")
- 层级与属性结合
- 如果一个元素本身没有可以唯一标识这个元素的属性值,我们可以找其上一级元素,如果它的上一级元素有可以唯一标识属性的值。也可以拿来使用。
- 通过
form
属性定位到输入按钮的父元素,后面的span[1]
和input
表示父元素下的子元素,
#输入按钮
driver.find_element_by_xpath('//*[@id="form"]/span[1]/input').send_keys("Selenium2")
#搜索按钮
driver.find_element_by_xpath('//*[@id="form"]/span[2]/input').click()
- 使用逻辑运算符
- 如果一个属性不能唯一地区分一个元素,可以使用逻辑运算符and链接多个属性来查找元素。
<input type="text" id="kw" class="su" name="ie">
<input type="text" id="kw" class="aa" name="ie">
<input type="text" id="bb" class="su" name="ie">
如上面的三行元素,假设我们现在要定位第一行元素,如果使用 id 将会与第二行元素重名,如果使用 class 将会与第三行元素重名,如果同时使用 id 和 class 就会唯一地标识这个元素,这个时候就可以通过逻辑运算符 “and” 来连接两个条件。
当然,我们也可以用“and”连接更多的属性来唯一地标识一个元素。
#输入按钮
#//input[@]选取所有id属性的input元素
driver.find_element_by_xpath('//*[@id="kw" and @class="s_ipt"]').send_keys("Selenium2")
#搜索按钮
driver.find_element_by_xpath('//*[@id="su" and @class="bg s_btn" ]').click()
7.CSS定位
find_element_by_css_selector()
- CSS可以较为灵活地选择空间的任意属性,一般情况下定位速度要比XPath快
选择器 | 描述 |
---|---|
.class | class选择器,选择class=‘ ’的所有元素 |
#id | Id选择器,选择id=‘ ’的所有元素 |
* | 选择所有元素 |
element | 元素所有的element元素 |
element1>element2 | 选择父元素为element1的所有element2元素 |
element1+element2 | 选择在同一级中紧接在element1元素之后的所有element2元素 |
[attribute=value] | 选择attribute=value的所有元素 |
- (1) 通过 class 属性定位
find_element_by_css_selector(".s_ipt")
find_element_by_css_selector(".bg s_btn")
- (2) 通过 id 属性定位
find_element_by_css_selector("#kw")
find_element_by_css_selector("#su")
-
(3)定位元素
- 通过标签名定位:
find_element_by_css_selector("input")
- 通过父子关系定位
#定位到搜索框 driver.find_element_by_css_selector('#form>span>input')\ .send_keys("Selenium2") #定位到搜索按钮 driver.find_element_by_css_selector("#form>span+span>input").click()
- 其他属性定位
#定位到搜索框 driver.find_element_by_css_selector('[name=wd]').send_keys("Selenium2") #定位到搜索按钮 driver.find_element_by_css_selector("[type=submit]").click()
- 组合定位
#定位到搜索框 driver.find_element_by_css_selector('#form.fm>span>input.s_ipt').\ send_keys("Selenium2") #定位到搜索按钮(span的class属性不可见,无法用class定位) driver.find_element_by_css_selector("form.fm>span>input#su").click()
8.By定位
-
统一调用 find_element()方法,通过 By 来声明定位的方法,并且传入对应定位方法的定位参数
-
先通过
from selenium.webdriver.common.by import By
导入By类 -
find_element(By.ID,"kw") find_element(By.NAME,"wd") find_element(By.CLASS_NAME,"s_ipt") find_element(By.TAG_NAME,"input") find_element(By.LINK_TEXT,"更多") find_element(By.PARTIAL_LINK_TEXT,"更") find_element(By.XPATH,"//*[@class='s_ipt']") find_element(By.CSS_SELECTOR,"#form.fm>span>input.s_ipt")
4.控制浏览器
1.控制浏览器窗口大小
-
maximize_window()
- 使打开的浏览器全屏显示,不需要参数
-
**set-window_size() **
-
设置打开的浏览器的大小,需要宽和高的像素点参数
-
print("设置浏览器宽800、高480显示") driver.set_window_size(800,480)
-
2.控制浏览器后退、前进
-
back() 和 forward() 方法来模拟后退和前进按钮
-
from selenium import webdriver import time driver = webdriver.Chrome() #访问百度首页 first_url="http://www.baidu.com" print("进入 %s" %(first_url)) driver.get(first_url) #访问新闻页面 second_url="http://news.baidu.com" print("进入 %s" %(second_url)) driver.get(second_url) #返回(后退)到百度首页 print("回到 %s" %(first_url)) driver.back() #前进到新闻页 print("前往 %s" %(second_url)) driver.forward() time.sleep(3) driver.quit()
3.模拟浏览器刷新
-
driver.refresh()刷新当前页面
-
from selenium import webdriver import time driver = webdriver.Chrome() #访问百度首页 first_url="http://www.baidu.com" print("进入 %s" %(first_url)) driver.get(first_url) time.sleep(3) driver.refresh() time.sleep(3) driver.quit()
4.显示浏览器信息
driver.title
打印当前页面titledriver.current_url
打印当前页面URLdriver.find_element_by_id("useraddr").text
获取当前元素文本信息定位的元素.get_attribute('innerHTML')
:会返回元素的内部 HTML, 包含所有的HTML标签。- ``定位的元素.get_attribute('textContent')`:获取 HTML 文本,需要注意的是 textContent 是 W3C 兼容的文字内容属性,不支持 IE 浏览器。
定位的元素.get_attribute('innerText')
:获取 HTML 文本,与 textContent 不同的是 innerText 不是 W3C DOM 的指定内容,不支持 FireFox 浏览器。定位的元素.get_attribute('value’)
:获取带有 value 属性的值
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get("https://mail.qq.com/")
#iframe有name或id
#driver.switch_to.frame('login_frame')
#iframe无name或id
elementi= driver.find_element_by_xpath('//*[@id="login_frame"]')
driver.switch_to.frame(elementi)
print("Before login==========")
# 打印当前页面title
now_title = driver.title
print(now_title)
# 打印当前页面URL
now_url = driver.current_url
print(now_url)
driver.find_element_by_xpath('//*[@id="u"]').clear()
driver.find_element_by_xpath('//*[@id="u"]').send_keys("*******")
driver.find_element_by_xpath('//*[@id="p"]').send_keys("*******")
driver.find_element_by_xpath('//*[@id="login_button"]').click()
#time.sleep(10)
print("After login==========")
# 获取登录的用户名
user = WebDriverWait(driver,20,1).until\
(EC.presence_of_all_elements_located((By.ID,"useraddr")))
# 再次打印当前页面title
now_title = driver.title
print(now_title)
# 再次打印当前页面URL
now_url = driver.current_url
print(now_url)
# 打印登录的用户名
for i in user:
print(i.get_attribute('textContent'))
time.sleep(3)
driver.quit(
5.简单元素操作
1.几种常见方法
-
clear(): 清除文本输入框文本
-
send_keys(*value): 模拟按键输入
-
click(): 单击元素,可用于单击一个按钮和任何可以单击的文字/图片链接、复选框、单选框、下拉框等
-
from selenium import webdriver import time driver = webdriver.Chrome() driver.get("https://mail.qq.com/") driver.find_element_by_xpath('//*[@id="u"]').clear() driver.find_element_by_xpath('//*[@id="u"]').send_keys("578389018@qq.com") driver.find_element_by_xpath('//*[@id="p"]').send_keys("*******") driver.find_element_by_xpath('//*[@id="login_button"]').click() time.sleep(3) driver.quit() #会报错,表示找不到元素
2.找不到元素的可能
-
Frame/Iframe原因定位不到元素
-
-
frame中实际上是嵌入了另一个页面,而webdriver每次只能在一个页面识别,因此需要先定位到相应的frame,对那个页面里的元素进行定位
-
如果 iframe有name或id的话,直接使用
switch_to.frame("name值")
或switch_to.frame("id值")
。 -
如果iframe没有name或id,先定位到iframe,再将定位对象传给
switch_to.frame()
方法 -
完成操作后,可以通过
switch_to.parent_content()
方法跳出当前一级iframe,或者还可以通过switch_to.default_content()
方法跳回最外层的页面。 -
from selenium import webdriver import time driver = webdriver.Chrome() driver.get("https://mail.qq.com/") #iframe有name或id #driver.switch_to.frame('login_frame') #iframe无name或id elementi= driver.find_element_by_xpath('//*[@id="login_frame"]') driver.switch_to.frame(elementi) driver.find_element_by_xpath('//*[@id="u"]').clear() driver.find_element_by_xpath('//*[@id="u"]').send_keys("*******") driver.find_element_by_xpath('//*[@id="p"]').send_keys("*******") driver.find_element_by_xpath('//*[@id="login_button"]').click() time.sleep(3) driver.quit()
-
switch_to包的方法详解
1. driver.switch_to.active_element() ---------------替换-------------- driver.switch_to_active_element()
定位到当前聚焦的元素上 聚焦这部分参考:https://blog.csdn.net/huilan_same/article/details/52338073
2. driver.switch_to.alert() *---------------**替换**--------------* driver.switch_to_alert()
切换到alert弹窗
3. driver.switch_to.default_content() *---------------替换--------------* driver.switch_to_default_content()
切换到最上层页面
4. driver.switch_to.frame(frame_reference) *---------------替换--------------*driver.switch_to_frame(frame_reference)
通过id、name、element(定位的某个元素)、索引来切换到某个frame
5. driver.switch_to.parent_frame()
这是switch_to中独有的方法,可以切换到上一层的frame,对于层层嵌套的frame很有用
6. driver.switch_to.window(window_name) 等同于 driver.switch_to_window(window_name)
切换到制定的window_name页面
-
-
Xpath描述错误原因
-
由于Xpath层级太复杂容易犯错,可以复制xpath路径。该方式容易因为层级改变而需要重新编写过xpath路径,不建议使用,初学者可以先复制路径,然后尝试去修改它。
-
页面还没有加载出来,就对页面上的元素进行的操作
-
这种情况一般说来,可以设置等待,等待页面显示之后再操作:
-
-
设置等待时间;缺点是需要设置较长的等待时间,案例多了测试就很慢;
导入时间模块import time, time.sleep(3)
-
设置等待页面的某个元素出现,比如一个文本、一个输入框都可以,一旦指定的元素出现,就可以做操作。
-
使用implicitly_wait()隐形等待
driver.implicitly_wait(20)
- 整个运行过程有效,加载到整个页面才执行代码
- 元素到时间没加载出来汇报ElementNotVisibleException
-
用WebDriverWait()显性等待,配合该类的until(method, message=' ')和until_not()方法
-
from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC
-
WebDriverWait(driver,10,1).until(EC.presence_of_all_elements_located((By.ID,"TANGRAM__PSP_4__content")))
等待10s,每隔1s去检查元素是否存在
出现执行下一步,10s结束不出现抛出异常 -
expected_conditions 类所提供的预期条件判断的方法如下表所示
-
-
-
在调试的过程中可以把页面的html代码打印出来,以便分析。
print(driver.page_source)
-
-
-
动态id定位不到元素
- 如果发现是动态id,直接用xpath定位或其他方式定位。
-
二次定位,如弹出框登录
- 如百度登录弹出框登录百度账号,需先定位到百度弹出框,然后再定位到用户名密码登录。
-
不可见元素定位
- 如上百度登录代码,通过名称为tj_login查找的登录元素,有些是不可见的,所以加一个循环判断,找到可见元素(is_displayed())点击登录即可.
from selenium import webdriver import time from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() ''' 1使用implicitly_wait()隐形等待, 整个运行过程有效,加载到整个页面才执行代码 元素到时间没加载出来汇报ElementNotVisibleException ''' #driver.implicitly_wait(20) driver.get("http://www.baidu.com/") time.sleep(3) #点击登录:有些name为tj_login的元素为不可见的,点击可见的那个登录按钮即可。 #否则会报:ElementNotVisibleException element0=driver.find_elements_by_name("tj_login") for ele0 in element0: if ele0.is_displayed(): ele0.click() #在登录弹出框,需先等登陆弹出框出现 #否则会报:NoSuchElementException ''' 2用sleep time.sleep(3) ''' ''' 3用WebDriverWait()显性等待,配合该类的until()和until_not()方法 等待10s,每隔1s去检查元素是否存在 出现执行下一步,10s结束不出现抛出异常 ''' element1=WebDriverWait(driver,10,1).until\ (EC.presence_of_all_elements_located((By.ID,"TANGRAM__PSP_4__content"))) element11=driver.find_element_by_id("TANGRAM__PSP_11__footerULoginBtn").click() #输入登录名和密码并提交 element2=driver.find_element_by_id("TANGRAM__PSP_11__userName") element2.send_keys("登录名") element3=driver.find_element_by_id("TANGRAM__PSP_11__password") element3.clear() element3.send_keys("密码") element4=driver.find_element_by_id("TANGRAM__PSP_11__submit") element4.click() element4.submit() try: assert "登录名" in driver.page_source except AssertionError: print("登录失败") else: print("登录成功") time.sleep(3) finally: print("测试记录:已测试") driver.close()
3.WebElement 接口常用方法
-
submit()
- 用于提交表单。例如,在搜索框输入关键字之后的“回车”操作,就可以通过submit() 方法模拟
- 有时候 submit() 可以与 click() 方法互换来使用,但 submit() 的应用范围远不及 click() 广泛
-
size: 返回元素的尺寸
-
text: 获取元素的文本
-
get_attribute(name): 获取属性值
-
is_dispalyed(): 设置该元素是否用户可见,注意,是不可见,不是不存在
-
from selenium import webdriver import time from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("http://www.baidu.com") # 获取输入框的尺寸 size = driver.find_element_by_id("kw").size print(size) # 返回百度页面底部备案信息 text = driver.find_element_by_id("s-bottom-layer-right").text print(text) # 返回元素的属性值,可以是id、name、type或其他任意属性 attribute = driver.find_element_by_id("kw").get_attribute("type") print(attribute) # 返回元素的结果是否可见,返回结果为True或False result = driver.find_element_by_id("kw").is_displayed() # 注意,是不可见,不是不存在。不存在会直接报错 print(result) driver.quit() ''' {'height': 44, 'width': 548} ©2020 Baidu (京)-经营性-2017-0020京公网安备11000002000001号京ICP证030173号 text True '''
6.鼠标事件
- ActionChains 类提供了鼠标操作的常用方法:
from selenium.webdriver.common.action_chains import ActionChains
- perform(): 执行所有ActionChains中存储的行为
- context_click(): 右击
ActionChains(driver).context_click(right_click).perform()
- ActionChains(driver) 调用 ActionChains() 类,将浏览器驱动 driver 作为参数传入
- context_click(right_click) context_click() 方法用于模拟鼠标右键操作,在调用时需要指定元素定位。
- perform() 执行所有 ActionChains 中储存的行为,可以理解成是对整个操作的提交动作
- double_click(): 双击
ActionChains(driver).double_click(double_click).perform()
- drag_and_drop(): 拖动
ActionChains(driver).drag_and_drop(source,target).perform()
- source:鼠标拖动的源元素,target:鼠标释放的目标元素,在源元素上按住鼠标左键,然后移动到目标元素上释放。
- move_to_element(): 鼠标悬停
ActionChains(driver).move_to_element(above).perform()
- click_and_hold(): 鼠标左键按下不放
- ``ActionChains(driver).click_and_hold(above).perform()`
- release(): 释放鼠标
ActionChains(driver).release().perform()
- reset_action():重置action
- ``ActionChains(driver).reset_action()`
- move_by_offset(x,y):移动鼠标
ActionChains(driver).move_by_offset(x,y).perform()
7.键盘事件
from selenium.webdriver.common.keys import Keys
- send_keys()方法可以用来模拟键盘输入,除此之外,我们还可以用它来输入键盘上的按键,甚至是组合键,如 Ctrl + A ,Ctrl + C等
- send_keys(Keys.BACK_SPACE) 删除键(BackSpace)
- send_keys(Keys.SPACE) 空格键(Space)
- send_keys(Keys.TAB) 制表键(Tab)
- send_keys(Keys.ESCAPE) 回退键(Esc)
- send_keys(Keys.ENTER) 回车键(Enter)
- send_keys(Keys.CONTROL,"a") 全选(Ctrl+A)
- send_keys(Keys.CONTROL,"c") 复制(Ctrl+C)
- send_keys(Keys.CONTROL,"x") 剪切(Ctrl+X)
- send_keys(Keys.CONTROL,"v") 粘贴(Ctrl+V)
- send_keys(Keys.F1) 键盘F1
- send_keys(Keys.F12) 键盘F12
8.定位一组元素
-
定位一组元素的方法与定位单个元素的方法类似,唯一的区别是在单词element后面多了一个s表示复数
-
find_elements_by_id()
find_elements_by_name()
find_elements_by_class_name()
find_elements_by_tag_name()
find_elements_by_link_text()
find_elements_by_partial_link_text()
find_elements_by_xpath
find_elements_by_css_selector() -
定位一组元素一般用于以下场景:
- 批量操作元素,例如勾选页面上所有的多选框
- 先获取一组元素,再从这组对象中过滤出需要操作的元素。例如定位出页面上所有的checkbox然后选择其中的一个进行操作。
<!DOCTYPE html> <html> <meta charset="UTF-8"> <body> <form > <p>测试多选框</p> <p><input type="checkbox" name="vehicle" value="Bike" /> 选择1 </p> <p><input type="checkbox" name="vehicle" value="Car"/> 选择2 </p> <p><input type="checkbox" name="vehicle" value="name"/> 选择3 </p> </form> </body> </html>
from selenium import webdriver import time import os driver = webdriver.Chrome() file_path = "file:///" + os.path.abspath("checkbox.html") driver.get(file_path) # 通过XPath找到type=checkbox的元素 # checkboxes = driver.find_elements_by_xpath("//input[@type='checkbox']") # 通过CSS找到type=checkbox的元素 checkboxes = driver.find_elements_by_css_selector("input[type=checkbox]") for checkbox in checkboxes: checkbox.click() time.sleep(1) # 打印当前页面上的type为checkbox的个数 print(len(checkboxes)) # 把页面上第一个1个checkbox的钩给去掉 driver.find_elements_by_css_selector("input[type=checkbox]").pop(0).click() time.sleep(3) driver.quit()
-
勾选页面的复选框或下拉框
select = Select(定位元素)
获取相应的元素select.deselect_all()
取消选择所有的选项select.select_by_visible_text(" ")
通过文本选中选项1select.select_by_value(" ")
通过 value 值选中选项2select.select_by_index(4
通过索引选中选项4- HTML文档如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <p>下拉框测试</p> <select id="selectdemo" onchange="change()" style="width:272px;"> <option id="1" value="选项1">a</option> <option id="2" value="选项2">b</option> <option id="3" value="选项3">c</option> </select> <script language="javascript"> function change() { var obj=document.getElementsByName("select").value; this.focus(); document.getElementById("div1").innerHTML=obj } </script> </head> <body> <p>复选框测试</p> <select id="select" multiple> <option value="xz1">选项1</option> <option value="xz2">选项2</option> <option value="xz3" selected="selected">选项3</option> <option value="xz4">选项4</option> </select> </body> </html>
- 测试文件如下
from selenium import webdriver import time import os from selenium.webdriver.support.ui import Select driver = webdriver.Chrome() file_path = "file:///" + os.path.abspath("checkbox.html") driver.get(file_path) # 通过Select找到id为select的元素 select1 = Select(driver.find_element_by_id("select")) # 先取消选择所有的选项 select1.deselect_all() # 通过文本选中选项1 select1.select_by_visible_text("选项1") # 通过 value 值选中选项2 select1.select_by_value("xz2") # 通过 index 选择元素,索引从0开始 select1.select_by_index(3) time.sleep(3) select1.deselect_all() time.sleep(3) select2=Select(driver.find_element_by_id("selectdemo")) select2.select_by_visible_text("c") time.sleep(3) driver.quit()
9.多窗口切换
driver.current_window_handle
获得当前窗口句柄driver.window_handles
获得当前所有打开的窗口的句柄driver.switch_to.window(窗口句柄)
跳转到该窗口
from selenium import webdriver
import time
import os
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
# 获得百度搜索窗口句柄
sreach_windows = driver.current_window_handle
driver.find_element_by_link_text("登录").click()
driver.find_element_by_link_text("立即注册").click()
# 获得当前所有打开的窗口的句柄
all_handles = driver.window_handles
# 进入注册窗口
for handle in all_handles:
if handle != sreach_windows:
driver.switch_to.window(handle)
print("now register window!")
time.sleep(2)
# 回到搜索窗口
for handle in all_handles:
if handle == sreach_windows:
driver.switch_to.window(handle)
print("now sreach window!")
# 会跳出来一个让你下载APP的弹窗,把这个弹窗给点掉
try:
driver.find_element_by_id("TANGRAM__PSP_4__closeBtn")
except:
break
else:
driver.find_element_by_id("TANGRAM__PSP_4__closeBtn").click()
# 弹窗消失后,再去查找
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(2)
driver.quit()
10.警告框处理
-
在WebDriver 中处理JavaScript所生成的alert、confirm以及prompt十分简单,具体做法是使用
dirver.switch_to.alert
方法定位到 alert/confirm/prompt,然后使用text/accept/dismiss/send_keys等方法进行操作。- text:返回 alert/confirm/prompt中的文字信息。
- accept():接受现有警告框
- dismiss():解散现有警告框
- send_keys(keysToSend):发送文本至警告框。keysToSend:将文本发送至警告框。
from selenium import webdriver import time import os from selenium.webdriver.common.action_chains import ActionChains driver = webdriver.Chrome() driver.implicitly_wait(10) driver.get("http://www.baidu.com") # 鼠标悬停至“设置”链接 link = driver.find_element_by_xpath('//*[@id="s-usersetting-top"]') ActionChains(driver).move_to_element(link).perform() time.sleep(1) # 打开搜索设置 driver.find_element_by_link_text("搜索设置").click() time.sleep(1) # 没有这个延迟会出现问题 # 保存设置 driver.find_element_by_link_text('保存设置').click() time.sleep(1) # 接受警告框 alarm=driver.switch_to.alert alarm.accept() time.sleep(1) driver.quit()
11.文件
1.上传文件
-
普通上传:普通的附件上传是将本地文件的路径作为一个值放在input标签中,通过form表单将这个值提交给服务器。
-
插件上传:一般是指基于Flash、JavaScript或Ajax等技术所实现的上传功能
-
send_keys 实现上传
- 对于通过input标签实现的上传功能,可以将其看做是一个输入框,即通过send_keys()指定本地文件路径的方式实现文件上传。
- HTML文件
<!DOCTYPE html> <html> <head> </head> <body> <form action="demo_form.php"> <input type="file" name="pic" accept="image/*"> <input type="submit"> </form> </body> </html>
- Python文件:
from selenium import webdriver import time import os driver = webdriver.Chrome() driver.implicitly_wait(10) file_path = "file:///" + os.path.abspath("file.html") driver.get(file_path) link = driver.find_element_by_name('pic').send_keys('文件路径') time.sleep(3) driver.quit()
2.下载文件
-
WebDriver 允许我们设置默认的文件下载路径,也就是说,文件会自动下载并且存放到设置的目录中。下面以Firefox浏览器为例,执行文件的下载
-
Chrome文件下载
webdriver.ChromeOptions().add_experimental_option('', prefs)
给浏览器的启动选项添加下载的实验选项- ChromeOptions常用属性及方法为:
- binary_location=‘‘:指定Chrome浏览器路径
- debuger_address=‘:指定调试路径
- headless: 无界面模式
- add_argument():添加启动参数
- add_extension:添加本地插件
- add_experimental_option:添加实验选项
- to_capablilities:将options转为标准的capablitiies格式
- ChromeOptions常用属性及方法为:
download.default_directory
:设置下载路径profile.default_content_settings.popups
:设置为0禁止弹出窗口- 在网页中选取要下载的元素下载
from selenium import webdriver import time #支持的浏览器启动选项 options = webdriver.ChromeOptions() prefs = {'profile.default_content_settings.popups': 0, 'download.default_directory': '/Users/Jay/Downloads'} #add_experimental_option:添加实验选项 options.add_experimental_option('prefs', prefs) driver = webdriver.Chrome(chrome_options=options) driver.get('http://sahitest.com/demo/saveAs.htm') driver.find_element_by_xpath('//a[text()="testsaveas.zip"]').click() time.sleep(3) driver.quit()
-
Firefox文件下载
-
通过FirefoxProfile()对其做一些设置。
-
browser.download.folderList
设置成0代表下载到浏览器默认下载路径,设置成2则可以保存到制定目录
-
browser.download.manager.showWhenStarting
是否显示开始:True为显示,Flase为不显示
-
browser.download.dir
用于指定所下载文件的目录。os.getcwd()函数不需要传递参数,用于返回当前的目录
-
browser.helperApps.neverAsk.saveToDisk
指定要下载页面的Content_type值,“application/octet-stream”为文件的类型
fp = webdriver.FirefoxProfile() #保存到指定目录 fp.set_preference("browser.download.folderList",2) #不显示开始 fp.set_preference("browser.download.manager.showWhenStarting",False) #指定所下载文件的目录 fp.set_preference("browser.download.manager.dir",os.getcwd()) fp.set_preference("browser.helperApps.neverAsk.saveToDisk","application/octet-stream") # 下载文件的类型 driver = webdriver.Firefox(firefox_profile=fp) driver.get("http://pypi.Python.org/pypi/selenium") driver.find_element_by_partial_link_text("selenium-2").click()
-
12.操作cookie
- get_cookies(): 获得所有cookie信息
- get_cookie(name): 返回字典的key为“name”的cookie信息
- add_cookie(cookie_dict): 添加cookie。“cookie_dict”指字典对象,必须有name和value值
- delete_cookie(name,optionsString): 删除cookie信息。“name”是要删除的cookie的名称,“optionString”是该cookie的选项,目前支持的选项包括“路径”,“域”。
- delete_all_cookies(): 删除所有cookie信息
13.调用JavaScript
-
driver.execute_script()
执行JavaScript代码 -
window.scrollTo()
方法- 用于设置浏览器窗口滚动条的水平和垂直位置。方法的第一个参数表示水平的左间距,第二个参数表示垂直的上边距
-
document.getElementById('id').scrollTop=0
或者document.documentElement.scrollTop=0
滚动条回到顶部 -
document.getElementById('id').scrollTop=10000"
或者document.documentElement.scrollTop=10000
滚动条拉到底部 -
driver.execute_script("arguments[0].scrollIntoView();", 定位元素)
滚动条拉到指定位置(具体元素) -
window.scrollTo()
函数内置方法- document.body.scrollHeight 获取对象的滚动高度。
- document.body.scrollLeft 设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离。
- document.body.scrollTop 设置或获取位于对象最顶端和窗口中可见内容的最顶端之间的距离。
- document.body.scrollWidth 获取对象的滚动宽度
-
通过id的方式将其进行定位,但却不能通过send_keys()向文本框中输入文本信息。这种情况下,就需要借助JavaScript代码完成输入
-
text = "input text" js = "var sum=document.getElementById("id"); sum.value = '" + text + "';" driver.execute_script(js)
-
14.视频播放
- HTML5定义了一个元素
- JavaScript 函数有个内置的对象叫做 arguments。arguments对象包含了函数调用的参数数组,[0]表示取对象的第1个值。
- arguments[0].currentSrc 熟悉返回当前的URL。如果未设置地址元素,则返回空字符串。
- arguments[0].load() 、arguments[0].play() 、arguments[0].pause() 、等控制着视频的加载、播放和暂停。
from selenium import webdriver
import time
import os
driver=webdriver.Chrome()
driver.get("http://videojs.com/")
time.sleep(5)
video = driver.find_element_by_id('preview-player_html5_api')
# 返回播放文件地址
url = driver.execute_script("return arguments[0].currentSrc;",video)
print(url)
# 播放视频
print("start")
driver.execute_script("arguments[0].play()",video)
# 播放15秒钟
time.sleep(5)
# 暂停视频
print("stop")
driver.execute_script("arguments[0].pause()",video)
time.sleep(3)
driver.quit()
15.窗口截图
driver.get_screenshot_as_file(‘截图保存路径.图片格式’)
来截取当前窗口- 自动化用例是由程序去执行的,因此有时候打印的错误信息并不十分明确。如果在脚本执行出错的时候能对当前窗口截图保存,那么通过图片就可以非常直观地看出出错的原因。
from selenium import webdriver
import time
driver=webdriver.Chrome()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").send_keys("selenium")
driver.find_element_by_id("su").click()
time.sleep(2)
# 截图当前窗口,并制定截图图片的保存位置
driver.get_screenshot_as_file("/Users/Jay/Downloads/baidu.png") # png格式
driver.quit()
time.sleep(3)
driver.quit()
16.验证码的处理
-
cookie绕过登陆
-
通过add_cookie({‘key’:’value'}) 方法将用户名密码写入浏览器cookie,当再次访问网站时,服务器将直接读取浏览器的cookie进行登录,再次访问xx网站driver.get("http://www.xx.cn/"),将会自动登录
-
get_cookies():获得cookie所有信息,返回的是一个字典
get_cookie(key):获取返回cookie中,某一个key的值
add_cookie(cookie_dict):手动添加cookie,需要传一个字典进去,用cookie_dict来接收,字典的键必须要有‘name’和‘value’
delete_cookie(name):删除cookie信息,name是要删除的cookie名称
delete_all_cookies():删除所有cookie信息
from selenium import webdriver import time import os from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.keys import Keys #给Google添加cookie profile_dir=r"/Users/Jay/Library/Application\ Support/Google/Chrome/Default" # 对应你的chrome的用户数据存放路径 chrome_options=webdriver.ChromeOptions() chrome_options.add_argument("user-data-dir="+os.path.abspath(profile_dir)) driver = webdriver.Chrome() driver.get("https://mail.qq.com/") #iframe有name或id #driver.switch_to.frame('login_frame') #iframe无name或id elementi= driver.find_element_by_xpath('//*[@id="login_frame"]') driver.switch_to.frame(elementi) print("Before login==========") # 打印当前页面title now_title = driver.title print(now_title) # 打印当前页面URL now_url = driver.current_url print(now_url) driver.find_element_by_xpath('//*[@id="u"]').clear() driver.find_element_by_xpath('//*[@id="u"]').send_keys("***") driver.find_element_by_xpath('//*[@id="p"]').send_keys("***") time.sleep(1) driver.find_element_by_xpath('//*[@id="login_button"]').click() #通过进入登陆成功后的页面,通过driver.get_cookies()获得其cookie cookie_get = [{'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'tinfo', 'path': '/', 'secure': False, 'value': '1604393486.0000'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_ptsk', 'path': '/', 'secure': False, 'value': '1932791597&@G6PjTrqGY'}, {'domain': '.mail.qq.com', 'expiry': 1606985276, 'httpOnly': False, 'name': 'qm_logintype', 'path': '/', 'secure': False, 'value': 'qq'}, {'domain': '.mail.qq.com', 'expiry': 1606985276, 'httpOnly': False, 'name': 'edition', 'path': '/', 'secure': False, 'value': 'mail.qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_loginfrom', 'path': '/', 'secure': False, 'value': '1932791597&wsk'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_domain', 'path': '/', 'secure': False, 'value': 'https://mail.qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'xm_uin', 'path': '/', 'secure': True, 'value': '13102662957666093'}, {'domain': '.qq.com', 'expiry': 1604393306, 'httpOnly': False, 'name': 'qm_lg', 'path': '/', 'secure': False, 'value': 'qm_lg'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'username', 'path': '/', 'secure': False, 'value': '1932791597&1932791597'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_username', 'path': '/', 'secure': False, 'value': '1932791597'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'xm_skey', 'path': '/', 'secure': True, 'value': '13102662957666093&3d414a0498da32571b39397536fda73b'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'sid', 'path': '/', 'secure': False, 'value': '1932791597&9fd715cd79f08f79e96f3591dd09e44c,qQkI1NjRleWFFWVRTUnJwZVU0LVRVQVN3M21KYmtacjVZNG1vdUY2SGVIY18.'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'p_uin', 'path': '/', 'secure': False, 'value': 'o1932791597'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qqmail_alias', 'path': '/', 'secure': False, 'value': '1932791597@qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'p_skey', 'path': '/', 'secure': False, 'value': 'BB564eyaEYTSRrpeU4-TUASw3mJbkZr5Y4mouF6HeHc_'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'foxacc', 'path': '/', 'secure': False, 'value': '1932791597&0'}, {'domain': '.mail.qq.com', 'expiry': 1606985277, 'httpOnly': False, 'name': 'CCSHOW', 'path': '/', 'secure': False, 'value': '000001'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'pt4_token', 'path': '/', 'secure': False, 'value': 'ebJ5K28JPz4eSfUv0mGoIEkiilKEwej93KO18-GImzo_'}, {'domain': '.qq.com', 'httpOnly': False, 'name': 'uin', 'path': '/', 'secure': False, 'value': 'o1932791597'}, {'domain': '.qq.com', 'httpOnly': False, 'name': 'skey', 'path': '/', 'secure': False, 'value': '@G6PjTrqGY'}, {'domain': '.qq.com', 'expiry': 2147483437, 'httpOnly': False, 'name': 'ptcz', 'path': '/', 'secure': False, 'value': '2c72c4c3127f1ca12f0eb04c2298f08c8d738f2eefe8e93b9110b3eb043d3284'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'qm_flag', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'new_mail_num', 'path': '/', 'secure': False, 'value': '1932791597&45'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'ssl_edition', 'path': '/', 'secure': False, 'value': 'sail.qq.com'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'xm_sid', 'path': '/', 'secure': True, 'value': 'zS0wTYwPUXguNFVPAHMwNwAA'}, {'domain': '.qq.com', 'expiry': 2147483437, 'httpOnly': False, 'name': 'RK', 'path': '/', 'secure': False, 'value': 'WvBENmHXPC'}, {'domain': '.mail.qq.com', 'httpOnly': False, 'name': 'wimrefreshrun', 'path': '/', 'secure': False, 'value': '0&'}, {'domain': '.qq.com', 'expiry': 1606985272, 'httpOnly': False, 'name': 'ptui_loginuin', 'path': '/', 'secure': False, 'value': '1932791597@qq.com'}] print(cookie_get) #清除浏览器cookie driver.delete_all_cookies() cookies = cookie_get for cookie in cookies: #去除无效cookie if 'expiry' in cookie: del cookie['expiry'] #添加cookie driver.add_cookie(cookie) #刷新页面 driver.refresh() time.sleep(3) print("After login==========") # 获取登录的用户名 user = WebDriverWait(driver,20,1).until\ (EC.presence_of_all_elements_located((By.ID,"useraddr"))) # 再次打印当前页面title now_title = driver.title print(now_title) # 再次打印当前页面URL now_url = driver.current_url print(now_url) # 打印登录的用户名 for i in user: print(i.get_attribute('textContent')) time.sleep(3) driver.quit()
-