为什么选python?
之前的菜鸟系列是基于java的,一年没学其实也忘的差不多了,目前所测的产品部分也是python写的,而且团队也在推广python ,其实就测试人员来说,python也相当受欢迎。易学,易用。翻翻各测试招聘,python出现的概率也颇高。
平台搭建:
前一篇中已经介绍,如果你也想体验一下自动化魅力,那就赶快搭建自己的环境吧~!
第一个脚本:
下面看看python 穿上selenium webdriver 是多么的性感:
# coding = utf-8
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
browser.quit()
from selenium import webdriver
要想使用selenium的webdriver 里的函数,首先把包导进来嘛
browser = webdriver.Firefox()
我们需要操控哪个浏览器呢?Firefox ,当然也可以换成Ie 或 Chrome 。browser可以随便取,但后面要用它操纵各种函数执行。
browser.find_element_by_id("kw").send_keys("selenium")
一个控件有若干属性id 、name、(也可以用其它方式定位),百度输入框的id 叫kw ,我要在输入框里输入 selenium 。多自然语言呀!
browser.find_element_by_id("su").click()
搜索的按钮的id 叫su ,我需要点一下按钮( click() )。
browser.quit()
退出并关闭窗口的每一个相关的驱动程序,它还有个类似的表弟。
browser.close()
关闭当前窗口 ,用哪个看你的需求了。
添加休眠
什么?你说刚才太快没看清浏览器的操作过程。请time出马,让他跑慢点。
# coding = utf-8
from selenium import webdriver
import time #调入time函数
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
time.sleep(0.3) #休眠0.3秒
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3) # 休眠3秒
browser.quit()
time.sleep() 函数随意插,哪里太快插哪里,再也不用担心看不清脚本的运行过程了。
其实,这个函数的真正用途不是给我们看脚本的运行过程的,有时候网络原因,或页面加载慢。假设搜索框输入框输入了selenium ,搜索按钮还没加载出来,那么脚本就报错。在适当的位置加入time.sleep()有助于减少网络原因造成的脚本执行失败;
输出
什么?在运行脚本的时候,上了个厕所,你都不知道刚才的脚本是否运行成功了。把刚才访问页面的title 打印出来。
# coding = utf-8
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://www.baidu.com')
print driver.title # 把页面title 打印出来
driver.quit()
虽然我没看到脚本的执行过程,但我在执行结果里看到了
>>>
百度一下,你就知道
说明页面正确被我打开了。
知识点:
· 打印URL
· 将浏览器最大化
· 设置浏览器固定宽、高
· 操控浏览器前进、后退
打印URL
上一节讲到,可以将浏览器的title打印出来,这里再讲个简单的,把当前URL打印出来。其实也没啥大用,可以做个凑数的用例。
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
url= 'http://www.baidu.com'
#通过get方法获取当前URL打印
print "now access %s" %(url)
browser.get(url)
time.sleep(2)
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
其实,我们可以把这用户登录成功后的URL打印,用于验证用户登录成功。
又或者,我们打印其它信息,比如,一般的登录成功页会出现“欢迎+用户名”,可以将这个信息打印表明用户登录成功。(如何实现,你自己琢磨一下吧~!)
将浏览器最大化
我们知道调用启动的浏览器不是全屏的,这样不会影响脚本的执行,但是有时候会影响我们“观看”脚本的执行。
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
time.sleep(2)
print "浏览器最大化"
browser.maximize_window() #将浏览器最大化显示
time.sleep(2)
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
设置浏览器固定宽、高
最大化还是不够灵活,能不能随意的设置浏览的宽、高显示?当然是可以的。
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
browser.get("http://m.mail.10086.cn")
time.sleep(2)
print "设置浏览器宽480、高800显示"
browser.set_window_size(480, 800) #参数数字为像素点
time.sleep(3)
browser.quit()
这个需求也还是有的,比如我们通过PC浏览器在访问一下手机网站时,调整浏览器为手机屏幕的宽、高,容易发现一些显示问题。(上面的手机邮箱网站就是笔者测试过的一个产品)
操控浏览器前进、后退
浏览器上有一个后退、前进按钮,对于浏览网页的人是比较方便的;对于做web自动化测试的同学来说应该算是一个比较难模拟的问题;其实很简单,下面看看python的实现方式
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
#访问百度首页
first_url= 'http://www.baidu.com'
print "now access %s" %(first_url)
browser.get(first_url)
time.sleep(2)
#访问新闻页面
second_url='http://news.baidu.com'
print "now access %s" %(second_url)
browser.get(second_url)
time.sleep(2)
#返回(后退)到百度首页
print "back to %s "%(first_url)
browser.back()
time.sleep(1)
#前进到新闻页
print "forward to %s"%(second_url)
browser.forward()
time.sleep(2)
browser.quit()
为了使过程让你看得更清晰,在每一步操作上都加了print 和sleep 。
说实话,这两个功能平时不太常用,所能想到的场景就是几个页面来回跳转,但又不想用get url的情况下。
本节重点:
简单对象的定位
对象的定位应该是自动化测试的核心,要想操作一个对象,首先应该识别这个对象。一个对象就是一个人一样,他会有各种的特征(属性),如比我们可以通过一个人的身份证号,姓名,或者他住在哪个街道、楼层、门牌找到这个人。
那么一个对象也有类似的属性,我们可以通过这个属性找到这对象。
定位对象的目的一般有下面几种
· 操作对象
· 获得对象的属性,如获得测试对象的class属性,name属性等等
· 获得对象的text
· 获得对象的数量
webdriver提供了一系列的对象定位方法,常用的有以下几种
· · id
· · name
· · class name
· · link text
· · partial link text
· · tag name
· · xpath
· · css selector
我们可以看到,一个百度的输入框,可以用这么用种方式去定位。
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
time.sleep(2)
#########百度输入框的定位方式##########
#通过id方式定位
browser.find_element_by_id("kw").send_keys("selenium")
#通过name方式定位
browser.find_element_by_name("wd").send_keys("selenium")
#通过tag name方式定位
browser.find_element_by_tag_name("input").send_keys("selenium")
#通过class name 方式定位
browser.find_element_by_class_name("s_ipt").send_keys("selenium")
#通过CSS方式定位
browser.find_element_by_css_selector("#kw").send_keys("selenium")
#通过xphan方式定位
browser.find_element_by_xpath("//input[@id='kw']").send_keys("selenium")
############################################
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
OK~!通过上面一个例子,就帮我们展示了几种定位方式,下面来介绍每种定位方式:
id 和 name
id 和 name 是我们最最常用的定位方式,因为大多数控件都有这两个属性,而且在对控件的id 和name命名时一般使其有意义也会取不同的名字。通过这两个属性使我们找一个页面上的属性变得相当容易
我们通过前端工具,找到了百度输入框的属性信息,如下:
<input id="kw" class="s_ipt" type="text" maxlength="100" name="wd" autocomplete="off">
id=”kw”
通过find_element_by_id("kw") 函数就是捕获到百度输入框
name=”wd”
通过find_element_by_name("wd")函数同样也可以捕获百度输入框
tag name 和class name
从上面的百度输入框的属性信息中,我们看到,不单单只有id 和 name两个属性,比如class 和 tag name(标签名)
<input>
input 就是一个标签的名字,可以通过find_element_by_tag_name("input") 函数来定位。
class="s_ipt"
通过find_element_by_class_name("s_ipt")函数捕获百度输入框。
但是,碰下面的一组控件属性,我们就哭了。
<th width="95"></th>
<th width="">文件名</th>
<th class="c1">创建时间</th>
<th class="c1">状态</th>
<th class="c1">文件大小</th>
<th class="c1">时长</th>
下面的css 和 XPath就没有上面的那么直观,如果不懂前端的话可能不太好理解
CSS定位
CSS(Cascading Style Sheets)是一种语言,它被用来描述HTML和XML文档的表现。CSS使用选择器来为页面元素绑定属性。这些选择器可以被selenium用作另外的定位策略。
CSS的比较灵活可以选择控件的任意属性,上面的例子中:
find_element_by_css_selector("#kw")
通过find_element_by_css_selector( )函数,选择取百度输入框的id属性来定义
也可以取name属性
<a href="http://news.baidu.com" name="tj_news">新 闻</a>
driver.find_element_by_css_selector("a[name=\"tj_news\"]").click()
可以取title属性
<a onclick="queryTab(this);" mon="col=502&pn=0" title="web" href="http://www.baidu.com/">网页</a>
driver.find_element_by_css_selector("a[title=\"web\"]").click()
也可以是取..:
<a class="RecycleBin xz" href="javascript:void(0);">
driver.find_element_by_css_selector("a.RecycleBin").click()
虽然我也没全部理解CSS的定位,但是看上去应该是一种非常灵活和牛X 的定位方式
扩展阅读:
http://www.w3.org/TR/css3-selectors/
http://www.w3school.com.cn/css/css_positioning.asp
XPath
什么是XPath:http://www.w3.org/TR/xpath/
XPath基础教程:http://www.w3schools.com/xpath/default.asp
selenium中被误解的XPath : http://magustest.com/blog/category/webdriver/
XPath是一种在XML文档中定位元素的语言。因为HTML可以看做XML的一种实现,所以selenium用户可是使用这种强大语言在web应用中定位元素。
XPath扩展了上面id和name定位方式,提供了很多种可能性,比如定位页面上的第三个多选框。
xpath:attributer (属性)
driver.find_element_by_xpath("//input[@id='kw']").send_keys("selenium")
#input标签下id =kw的元素
xpath:idRelative (id相关性)
driver.find_element_by_xpath("//div[@id='fm']/form/span/input").send_keys("selenium")
#在/form/span/input 层级标签下有个div标签的id=fm的元素
driver.find_element_by_xpath("//tr[@id='check']/td[2]").click()
# id为'check' 的tr ,定闪他里面的第2个td
xpath:position (位置)
driver.find_element_by_xpath("//input").send_keys("selenium")
driver.find_element_by_xpath("//tr[7]/td[2]").click()
#第7个tr 里面的第2个td
xpath: href (水平参考)
driver.find_element_by_xpath("//a[contains(text(),'网页')]").click()
#在a标签下有个文本(text)包含(contains)'网页' 的元素
xpath:link
driver.find_element_by_xpath("//a[@href='http://www.baidu.com/']").click()
#有个叫a的标签,他有个链接href='http://www.baidu.com/ 的元素
link 定位
有时候不是一个输入框也不是一个按钮,而是一个文字链接,我们可以通过link
#coding=utf-8
from selenium import webdriver
import time
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
time.sleep(2)
browser.find_element_by_link_text("贴 吧").click()
time.sleep(2)
browser.quit()
一般一个那页面上不会出现相同的文件链接,通过文字链接来定位也是一种简单有效的定位方式。
Partial Link Text 定位
通过部分链接定位,这个有时候也会用到,我还没有想到很好的用处。拿上面的例子,我可以只用链接的一部分文字进行匹配:
browser.find_element_by_partial_link_text("贴").click()
#通过find_element_by_partial_link_text() 函数,我只用了“贴”字,脚本一样找到了"贴 吧" 的链接
本节要解决的问题:
如何定位一组元素?
场景
从上一节的例子中可以看出,webdriver可以很方便的使用findElement方法来定位某个特定的对象,不过有时候我们却需要定位一组对象,
这时候就需要使用findElements方法。
定位一组对象一般用于以下场景:
· 批量操作对象,比如将页面上所有的checkbox都勾上
· 先获取一组对象,再在这组对象中过滤出需要具体定位的一些对象。比如定位出页面上所有的checkbox,然后选择最后一个
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Checkbox</title>
<script type="text/javascript" async="" src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</head>
<body>
<h3>checkbox</h3>
<div class="well">
<form class="form-horizontal">
<div class="control-group">
<label class="control-label" for="c1">checkbox1</label>
<div class="controls">
<input type="checkbox" id="c1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c2">checkbox2</label>
<div class="controls">
<input type="checkbox" id="c2" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="c3">checkbox3</label>
<div class="controls">
<input type="checkbox" id="c3" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r1" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="r">radio</label>
<div class="controls">
<input type="radio" id="r2" />
</div>
</div>
</form>
</div>
</body>
</html>
将这段代码保存复制到记事本中,将保存成checkbox.html文件。(注意,这个页面需要和我们的自动化脚本放在同一个目录下)
第一种方法:
通过浏览器打个这个页面我们看到三个复选框和两个单选框。下面我们就来定位这三个复选框。
# -*- coding: utf-8 -*-
from selenium import webdriver
import time
import os
dr = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('checkbox.html')
dr.get(file_path)
# 选择页面上所有的input,然后从中过滤出所有的checkbox并勾选之
inputs = dr.find_elements_by_tag_name('input')
for input in inputs:
if input.get_attribute('type') == 'checkbox':
input.click()
time.sleep(2)
dr.quit()
你可以试着把input.get_attribute('type') == 'checkbox' 中的checkbox 变成radio ,那这个脚本定位的会是两个单选框。
第二种定位方法:
# -*- coding: utf-8 -*-
from selenium import webdriver
import time
import os
dr = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('checkbox.html')
dr.get(file_path)
# 选择所有的checkbox并全部勾上
checkboxes = dr.find_elements_by_css_selector('input[type=checkbox]')
for checkbox in checkboxes:
checkbox.click()
time.sleep(2)
# 打印当前页面上有多少个checkbox
print len(dr.find_elements_by_css_selector('input[type=checkbox]'))
time.sleep(2)
dr.quit()
第二种写法与第一种写法差别不大,都是通过一个循环来勾选控件;如果你学过上一章的话,细心的你一定发现用的定位函数不一样,
第一种用的name ,第二种用的CSS 。
如何去掉勾选:
还有一个问题,有时候我们并不想勾选页面的所有的复选框(checkbox),可以通过下面办法把最后一个被勾选的框去掉。如下:
# -*- coding: utf-8 -*-
from selenium import webdriver
import time
import os
dr = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('checkbox.html')
dr.get(file_path)
# 选择所有的checkbox并全部勾上
checkboxes = dr.find_elements_by_css_selector('input[type=checkbox]')
for checkbox in checkboxes:
checkbox.click()
time.sleep(2)
# 把页面上最后1个checkbox的勾给去掉
dr.find_elements_by_css_selector('input[type=checkbox]').pop().click()
time.sleep(2)
dr.quit()
其实,去掉勾选表也逻辑也非常简单,就是再次点击勾选的按钮。可能我们比较迷惑的是如何找到“最后一个”按钮。pop() 可以实现这个功能。
好吧!在web自动化的学习过程中,我们必须要知道一些前端的东西,这里扩展一下:
http://www.w3school.com.cn/js/jsref_pop.asp
尝试:
把find_elements_by_css_selector('input[type=checkbox]').pop().click() 中的checkbox 变成radio 会是什么效果,自己尝试一下吧!
本节要解决的问题:
· 层级定位
场景:
假如两个控件,他们长的一模样,还都叫“张三”,唯一的不同是一个在北京,一个在上海,那我们就可以通过,他们的城市,区,街道,来找到他们。
在实际的测试中也经常会遇到这种问题:页面上有很多个属性基本相同的元素,现在需要具体定位到其中的一个。由于属性基本相当,所以在定位的时候会有些麻烦,这时候就需要用到层级定位。先定位父元素,然后再通过父元素定位子孙元素。
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>Level Locate</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
</head>
<body>
<h3>Level locate</h3>
<div class="span3">
<div class="well">
<div class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Link1</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" id="dropdown1" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
<div class="span3">
<div class="well">
<div class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Link2</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel" >
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
<li class="divider"></li>
<li><a tabindex="-1" href="#">Separated link</a></li>
</ul>
</div>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
将这段代码保存复制到记事本中,将保存成level_locate.html文件,(注意,这个页面需要和我们的自动化脚本放在同一个目录下)浏览器打开:
这里自制了一个页面,上面有两个文字链接,点击两个链接会弹出一模一样的的两个下拉菜单,这两个菜单的属性基本一样。那么我如何区分找到相应的菜单项呢?
方法如下:
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
import time
import os
dr = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('level_locate.html')
dr.get(file_path)
#点击Link1链接(弹出下拉列表)
dr.find_element_by_link_text('Link1').click()
#找到id 为dropdown1的父元素
WebDriverWait(dr, 10).until(lambda the_driver: the_driver.find_element_by_id('dropdown1').is_displayed())
#在父亲元件下找到link为Action的子元素
menu = dr.find_element_by_id('dropdown1').find_element_by_link_text('Action')
#鼠标定位到子元素上
webdriver.ActionChains(dr).move_to_element(menu).perform()
time.sleep(2)
dr.quit()
定位思路:
具体思路是:先点击显示出1个下拉菜单,然后再定位到该下拉菜单所在的ul,再定位这个ul下的某个具体的link。在这里,我们定位第1个下拉菜单中的Action这个选项。
---------------------------------------------------------------------
虽然我每行代码前叫了注释,但可能还是不太容易理解,因为里面多了不少以前没见过的新东东。
WebDriverWait(dr, 10)
10秒内每隔500毫秒扫描1次页面变化,当出现指定的元素后结束。dr就不解释了,前面操作webdriver.firefox()的句柄
is_displayed()
该元素是否用户可以见
class ActionChains(driver)
driver: 执行用户操作实例webdriver
生成用户的行为。所有的行动都存储在actionchains对象。通过perform()存储的行为。
move_to_element(menu)
移动鼠标到一个元素中,menu上面已经定义了他所指向的哪一个元素
to_element:元件移动到
perform()
执行所有存储的行为
------------------------------需要我们日常工作中细细品味、慢慢消化这些函数的用法
我们只是想达到一种效果,“下拉列表中Action选项处于被选中状态”,通过鼠标移动到选项上就达到到了这种效果,但通过程序模拟确实比较麻烦:
本节知识点:
操作对象:
· · click 点击对象
· · send_keys 在对象上模拟按键输入
· · clear 清除对象的内容,如果可以的话
WebElement 另一些常用方法:
· · text 获取该元素的文本
· · submit 提交表单
· · get_attribute 获得属性值
======================================
操作测试对象
前面讲到了不少知识都是定位元素,定位只是第一步,定位之后需要对这个原素进行操作。
鼠标点击呢还是键盘输入,这要取决于我们定位的是按钮还输入框。
一般来说,webdriver中比较常用的操作对象的方法有下面几个
· click 点击对象
· send_keys 在对象上模拟按键输入
· clear 清除对象的内容,如果可以的话
在我们本系列开篇的第一个例子里就用到了到click 和send_skys ,别翻回去找了,我再贴一下代码:
# coding = utf-8
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("http://www.baidu.com")
browser.find_element_by_id("kw").clear()
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
browser.quit()
send_keys("XX") 用于在一个输入框里输入内容。
click() 用于点击一个按钮。
clear() 用于清除输入框的内容,比如百度输入框里默认有个“请输入关键字”的信息,再比如我们的登陆框一般默认会有“账号”“密码”这样的默认信息。clear可以帮助我们清除这些信息。
WebElement 另一些常用方法:
· text 获取该元素的文本
· submit 提交表单
· get_attribute 获得属性值
text
用于获取元素的文本信息
下面把百度首页底部的声明打印输出
#coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
time.sleep(2)
#id = cp 元素的文本信息
data=driver.find_element_by_id("cp").text
print data #打印信息
time.sleep(3)
driver.quit()
输出:
>>>
©2013 Baidu 使用百度前必读 京ICP证030173号
submit
提交表单
我们把“百度一下”的操作从click 换成submit :
#coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://www.baidu.com")
driver.find_element_by_id("kw").send_keys("selenium")
time.sleep(2)
#通过submit() 来操作
driver.find_element_by_id("su").submit()
time.sleep(3)
driver.quit()
这里用submit 与click的效果一样,我暂时还没想到只能用submit 不能用click的场景。他们之间到底有啥区别,知道的同学请留言告诉我。
get_attribute
获得属性值。
这个函数的用法前面已经有出现过,在定位一组元素的时候有使用到它,只是我们没有做过多的解释。
一般用法:
select = driver.find_element_by_tag_name("select")
allOptions = select.find_elements_by_tag_name("option")
for option in allOptions:
print "Value is: " + option.get_attribute("value")
option.click()
具体应用参考:
定位一组元素:http://www.cnblogs.com/fnng/p/3190966.html
小结:
学到这里我们是不是已经撑握了不少知识,简单的操作浏览器,定位元素,操作元素以及打印一些信息。其实,我们前面的学习中大多使用的是WebElement 里的方法。
WebElement的方法:
一般来说,所有有趣的操作与页面进行交互的有趣的操作,都通过 WebElement 完成
classselenium.webdriver.remote.webelement.WebElement(parent, id_)
这个类代表HTML页面元素
id_
#当前元素的ID
tag_name
#获取元素标签名的属性
text
#获取该元素的文本。
click()
#单击(点击)元素
submit()
#提交表单
clear()
#清除一个文本输入元素的文本
get_attribute(name)
#获得属性值
is_selected(self)
#元素是否被选择
Whether the element is selected.
is_enabled()
#元素是否被启用
find_element_by_id(id_)
find_elements_by_id(id_)
#查找元素的id
find_element_by_name(name)
find_elements_by_name(name)
#查找元素的name
find_element_by_link_text(link_text)
find_elements_by_link_text(link_text)
#查找元素的链接文本
find_element_by_partial_link_text(link_text)
find_elements_by_partial_link_text(link_text)
#查找元素的链接的部分文本
find_element_by_tag_name(name)
find_elements_by_tag_name(name)
#查找元素的标签名
find_element_by_xpath(xpath)
#查找元素的xpath
find_elements_by_xpath(xpath)
#查找元素内的子元素的xpath
find_element_by_class_name(name)
#查找一个元素的类名
find_elements_by_class_name(name)
#查找元素的类名
find_element_by_css_selector(css_selector)
#查找并返回一个元素的CSS 选择器
find_elements_by_css_selector(css_selector)
#查找并返回多个元素的CSS 选择器列表
send_keys(*value)
#模拟输入元素
本节知识点:
多层框架或窗口的定位:
· switch_to_frame()
· switch_to_window()
智能等待:
· implicitly_wait()
对于一个现代的web应用,经常会出现框架(frame) 或窗口(window)的应用,这也就给我们的定位带来了一个难题。
有时候我们定位一个元素,定位器没有问题,但一直定位不了,这时候就要检查这个元素是否在一个frame中,seelnium webdriver 提供了一个switch_to_frame方法,可以很轻松的来解决这个问题。
frame.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>frame</title>
<script type="text/javascript" async=""
src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
});
</script>
</head>
<body>
<div class="row-fluid">
<div class="span10 well">
<h3>frame</h3>
<iframe id="f1" src="inner.html" width="800",
height="600"></iframe>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
inner.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>inner</title>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>inner</h3>
<iframe id="f2" src="http://www.baidu.com" width="700"
height="500"></iframe>
<a href="javascript:alert('watir-webdriver better than
selenium webdriver;')">click</a>
</div>
</div>
</body>
</html>
frame.html 中嵌套inner.html ,两个文件和我们的脚本文件放同一个目录下:
switch_to_frame()
操作上面页面,代码如下:
#coding=utf-8
from selenium import webdriver
import time
import os
browser = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('frame.html')
browser.get(file_path)
browser.implicitly_wait(30)
#先找到到ifrome1(id = f1)
browser.switch_to_frame("f1")
#再找到其下面的ifrome2(id =f2)
browser.switch_to_frame("f2")
#下面就可以正常的操作元素了
browser.find_element_by_id("kw").send_keys("selenium")
browser.find_element_by_id("su").click()
time.sleep(3)
browser.quit()
driver.switch_to_window()
有可能嵌套的不是框架,而是窗口,还有真对窗口的方法:switch_to_window
用法与switch_to_frame 相同:
driver.switch_to_window("windowName")
implicitly_wait()
细心的话会发现上面的例子中有browser.implicitly_wait(30),它的用法应该比time.sleep() 更智能,后者只能选择一个固定的时间的等待,前者可以在一个时间范围内智能的等待。
文档解释:
selenium.webdriver.remote.webdriver.implicitly_wait(time_to_wait)
隐式地等待一个无素被发现或一个命令完成;这个方法每次会话只需要调用一次
time_to_wait: 等待时间
用法:
driver.implicitly_wait(30)
本节重点:
调用js方法
· execute_script(script, *args)
在当前窗口/框架 同步执行javaScript
脚本:JavaScript的执行。
*参数:适用任何JavaScript脚本。
使用:
driver.execute_script(‘document.title’)
使快播登陆用户名输入框标红显示:
#coding=utf-8
from selenium import webdriver
import time
driver = webdriver.Firefox()
driver.get("http://passport.kuaibo.com/login/?referrer=http%3A%2F%2Fvod.kuaibo.com%2F%3Ft%3Dhome")
#给用户名的输入框标红
js="var q=document.getElementById(\"user_name\");q.style.border=\"1px solid red\";"
#调用js
driver.execute_script(js)
time.sleep(3)
driver.find_element_by_id("user_name").send_keys("username")
driver.find_element_by_id("user_pwd").send_keys("password")
driver.find_element_by_id("dl_an_submit").click()
time.sleep(3)
driver.quit()
js解释:
q=document.getElementById(\"user_name\")
元素q的id 为user_name
q.style.border=\"1px solid red\
元素q的样式,边框为1个像素红色
隐藏元素
js.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>js</title>
<script type="text/javascript" async="" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
$(document).ready(function(){
$('#tooltip').tooltip({"placement": "right"});
});
</script>
</head>
<body>
<h3>js</h3>
<div class="row-fluid">
<div class="span6 well">
<a id="tooltip" href="#" data-toggle="tooltip" title=" selenium-webdriver(python)">hover to see tooltip</a>
<a class="btn">Button</a>
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
(保持html文件与执行脚本在同一目录下)
执行js一般有两种场景:
· 一种是在页面上直接执行JS
· 另一种是在某个已经定位的元素上执行JS
#coding=utf-8
from selenium import webdriver
import time,os
driver = webdriver.Firefox()
file_path = 'file:///' + os.path.abspath('js.html')
driver.get(file_path)
#######通过JS 隐藏选中的元素#########
#第一种方法:
driver.execute_script('$("#tooltip").fadeOut();')
time.sleep(5)
#第二种方法:
button = driver.find_element_by_class_name('btn')
driver.execute_script('$(arguments[0]).fadeOut()',button)
time.sleep(5)
driver.quit()
js解释:
arguments对象,它是调用对象的一个特殊属性,用来引用Arguments对象。Arugments对象就像数组。
fadeOut() 方法使用淡出效果来隐藏被选元素,假如该元素是隐藏的。
PS:可以看到js 可以做selenium 做不到的事情,但是在什么样的自动化的时候才能(或必须)要js帮忙,我还没遇到过。不过js可以selenium完成更强大的功能,这是不容置疑的。
另外,之前没有学过JS ,所以js代码很陌生。如果有时间的话也建议各位同学补充这方面的知识。UI自动化离不开前端技术。
本节重点:
· 上传文件
文件上传操作也比较常见功能之一,上传功能没有用到新有方法或函数,关键是思路。
上传过程一般要打开一个本地窗口,从窗口选择本地文件添加。所以,一般会卡在如何操作本地窗口添加上传文件。
其实,在selenium webdriver 没我们想的那么复杂;只要定位上传按钮,通send_keys添加本地文件路径就可以了。绝对路径和相对路径都可以,关键是上传的文件存在。下面通地例子演示。
upload_file.html
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>upload_file</title>
<script type="text/javascript" async=""
src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" />
<script type="text/javascript">
</script>
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file" />
</div>
</div>
</body>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
</html>
upload.py
#coding=utf-8
from selenium import webdriver
import os,time
driver = webdriver.Firefox()
#脚本要与upload_file.html同一目录
file_path = 'file:///' + os.path.abspath('upload_file.html')
driver.get(file_path)
#定位上传按钮,添加本地文件
driver.find_element_by_name("file").send_keys('D:\\selenium_use_case\upload_file.txt')
time.sleep(2)
driver.quit()
其它有些应用不好找,所以就自己创建页面,这样虽然麻烦,但脚本代码突出重点。
这里找一139邮箱的实例,有帐号的同学可以测试一下~!
(登陆基础版的139邮箱,网盘模块上传文件。)
139upload.py
#coding=utf-8
from selenium import webdriver
import os,time
driver = webdriver.Firefox()
driver.get("http://m.mail.10086.cn")
driver.implicitly_wait(30)
#登陆
driver.find_element_by_id("ur").send_keys("手机号")
driver.find_element_by_id("pw").send_keys("密码")
driver.find_element_by_class_name("loading_btn").click()
time.sleep(3)
#进入139网盘模块
driver.find_element_by_xpath("/html/body/div[3]/a[9]/span[2]").click()
time.sleep(3)
#上传文件
driver.find_element_by_id("id_file").send_keys('D:\\selenium_use_case\upload_file.txt')
time.sleep(5)
driver.quit()