1. Selenium
Selenium是最广 泛使用的开源Web UI(用户界面)自动化测试套件之一。它最初由Jason Huggins于2004年开发,作为Thought Works的内部工具。 Selenium支持跨不同浏览器,平台和编程语言的自动化。
Selenium可以轻松部署在Windows,Linux,Solaris和Macintosh等平台上。 此外,它支持iOS(iOS,Windows Mobile和Android)等移动应用程序的OS(操作系统)。
Selenium通过使用特定于每种语言的驱动程序支持各种编程语言。Selenium支持的语言包括C#,Java,Perl,PHP,Python和Ruby。目前,Selenium Web驱动程序最受Python和C#欢迎。 Selenium测试脚本可以使用任何支持的编程语言进行编码,并且可以直接在大多数现代Web浏览器中运行。 Selenium支持的浏览器包括Internet Explorer,Mozilla Firefox,Google Chrome和Safari。
架构图

Selenium可用于自动化功能测试,并可与Maven,Jenkins和Docker等自动化测试工具集成,以实现持续测试。 它还可以与TestNG和JUnit等工具集成,以管理测试用例和生成报告。
2. Selenium功能特性
Selenium有以下功能特性:
- Selenium是一个开源和可移植的Web测试框架。
- Selenium IDE为创作测试提供了回放和录制功能,而无需学习测试脚本语言。
- 它可以被视为领先的基于云的测试平台,可帮助测试人员记录他们的操作并将其导出为可重复使用的脚本,并具有易于理解且易于使用的界面。
- Selenium支持各种操作系统,浏览器和编程语言。如下列表:
- 编程语言: C# ,Java,Python,PHP,Ruby,Perl和JavaScript
- 操作系统:Android,iOS,Windows,Linux,Mac,Solaris。
- 浏览器:谷歌浏览器,Mozilla Firefox,Internet Explorer,Edge,Opera,Safari等。
- 它还支持并行测试执行,从而减少了时间并提高了测试效率。
- Selenium可以与Ant和Maven等框架集成,用于源代码编译。
- Selenium还可以与TestNG等测试框架集成,以进行应用程序测试和生成报告。
- 与其他自动化测试工具相比,Selenium需要的资源更少。
- WebDriver API已经尝试集于Selenium中,这是对Selenium进行的最重要的修改之一。
- Selenium Web驱动程序不需要服务器安装,测试脚本直接与浏览器交互。
- Selenium命令根据不同的类进行分类,使其更易于理解和实现。
- Selenium Remote Control(RC)与WebDriver API一起被称为Selenium 2.0。 此版本旨在支持充满活力的网页和Ajax。
3. Selenium与QTP比较
Selenium和QTP是市场上最常用的自动化测试工具。 因此,我们比较了Selenium与QTP的一些特征。
| 特征 | Selenium | HP QTP |
|---|---|---|
| 许可 | 开源工具 | 有版权 |
| 客户支持 | Selenium社区论坛 | 专门的HP支持 |
| 测试支持 | 仅支持基于Web的应用程序的自动化。 | 支持基于Web和桌面的应用程序的测试。 |
| 测试脚本执行期间的资源消耗 | 资源消耗低 | 资源消耗高 |
| 支持的编程语言 | Java, C#, Ruby, Python, Perl, PHP and JavaScript | VB Script |
| 支持的环境 | Android, iOS, Windows, Linux, Mac, Solaris. | 仅适用于Windows |
| 支持的浏览器 | 谷歌浏览器,Mozilla Firefox,Internet Explorer,Edge,Opera,Safari等 | 特定版本的Google Chrome,Mozilla Firefox和Internet Explorer。 |
| 对象存储库/恢复方案 | 无 | 内置对象存储库和恢复方案。 |
| 浏览器控件 | 无 | 可在浏览器中访问收藏夹栏,后退和前进按钮等控件。 |
| 测试报告生成 | 它依赖于外部工具来生成测试报告。 | 在工具中生成内置测试报告。 |
| 参数设置 | 依赖任何一种受支持的编程语言进行参数化。 | 内置工具可用于参数化。 |
3.1. Selenium集成开发环境(IDE)
Selenium IDE实现为Firefox扩展,在测试脚本上提供记录和回放功能。
它允许测试人员以HTML,Java,Ruby,RSpec,Python, C# ,JUnit和TestNG等多种语言导出录制的脚本。 可以在Selenium RC或Webdriver中使用这些导出的脚本。
用于解决测试人员复现bug产生过程,自动产生自动化脚本。
3.2. Selenium WebDriver
Selenium WebDriver(Selenium 2)是Selenium Suite最重要的组件。
SeleniumWebDriver提供了一个编程接口来创建和执行测试用例。 编写测试脚本是为了识别网页上的Web元素,然后对这些元素执行所需的操作。
WebDriver直接调用不同浏览器的方法,因此每个浏览器都有单独的驱动程序。
一些最广泛使用的Web驱动程序包括:
- Mozilla Firefox驱动程序(Gecko驱动程序)
- 谷歌Chrome驱动程序
- Internet Explorer驱动程序
- Opera驱动程序
- Safari驱动程序
- HTML单元驱动程序(一个特殊的无头驱动程序)
3.3. Selenium Grid
Selenium Grid也是Selenium Suite的一个重要组件,它允许在不同的机器上并行运行不同浏览器的测试。 简单来说,可以在运行不同浏览器和操作系统的不同机器上同时运行测试。
Selenium Grid遵循Hub-Node架构来实现测试脚本的并行执行。Hub被视为网络的主设备,另一个将是节点。 Hub控制在网络的各个节点上执行测试脚本。
3.4. Selenium元素定位
Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。
测试与浏览器的兼容性——测试你的应用程序看是否能够很好得工作在不同浏览器和操作系统之上。
测试系统功能——创建回归测试检验软件功能和用户需求。
在UI层面的自动化测试开发中,元素的定位与操作是基础,有8种元素定位:
- id定位:find_element_by_id("id值");id属性是唯一的
- name定位:元素的名称,find_element_by_name("name值");name属性值在当前页面可以不唯一
- class定位:元素的类名,find_element_by_class_name("class值")
- tag定位:页面html文档下的各种标签,find_element_by_tag_name("input");
- link定位:专门用来定位文本链接,find_element_by_link_text();
- partial link定位:find_element_by_partial_link_text() 是对link定位的一种补充,当链接上的文本内容比较长的时候,可以取文本的一部分进行定位,当然这部分可以唯一地标识这个链接
如上方式局限性比较大,因为id,name等标签属性可能没有,class重复性可能较高等问题,因此使用Xpath和Css灵活性更大
- XPath定位:find_element_by_xpath("")
- CSS定位(薄弱,用的很少,但很强大,比xpath简洁灵活):使用选择器来为页面元素绑定属性,可以灵活地选择控件的任意属性;find_element_by_css_selector("");
3.5. 实战案例
3.5.1. 控制窗口大小
# 控制浏览器大小
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
# 参数数字为像素点
print("设置浏览器宽480、高800显示")
driver.set_window_size(2080,800)
time.sleep(2)
driver.close()
3.5.2. 全屏显示
# 控制浏览器大小
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get("http://www.baidu.com")
# 参数数字为像素点
driver.maximize_window()
time.sleep(2)
driver.close()
3.6. 网页前进后退
# 控制浏览器前进、后退
from selenium import webdriver
import time
driver = webdriver.Chrome()
# 访问百度首页
first_url='http://www.baidu.com'
print("now access %s "%(first_url))
driver.get(first_url)
# 访问新闻页面
time.sleep(2)
second_url='http://news.baidu.com'
print("now access % s" %(second_url))
driver.get(second_url)
# 后退到百度首页
print("back to %s "%(first_url))
driver.back()
# 前进到新闻页
print("forward to %s "%(second_url))
driver.forward()
time.sleep(2)
driver.close()
3.7. 浏览器刷新
# 控制浏览器前进、后退
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get('https://www.baidu.com')
for i in range(10):
driver.refresh()
time.sleep(2)
driver.close()
3.7.1. id元素定位
接下来,我们以 http://www.pythonav.com/ 和 https://www.luffycity.com/home 来介绍各定位方法的具体使用。
案例1:自动填写pythonav网址的注册用户名
手动注册流程:
1.打开浏览器,输入网址http://www.pythonav.com/register/
2.点击用户名的框,填写用户名
3.关闭浏览器
自动化代码:
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('http://www.pythonav.com/register/')
# 根据id获取对应的元素
username = browser.find_element_by_id('id_username')
# 为元素的value属性赋值
username.send_keys('社会我超哥')
# 睡3秒
time.sleep(3)
# 清空元素的value属性
username.clear()
# 再睡2秒
time.sleep(2)
# 关闭浏览器
browser.quit()
案例2:自动点击发送短信验证码
手动发短信流程:
1.打开浏览器,输入网址http://www.pythonav.com/register/
2.找到手机输入框,填写手机号
3.点击发送验证码
自动化代码:
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("http://www.pythonav.com/register/")
# 根据id获取对应的元素
phone = browser.find_element_by_id('id_telephone')
# 回填手机号
phone.send_keys('152xxxxxx04') # 这里填写一个真实可用的手机号
# 睡一会儿
time.sleep(5)
# 获取发送短信的按钮id
ele = browser.find_element_by_id('smsBtn')
# 模拟按钮的点击事件
ele.click()
time.sleep(2)
browser.quit()
自动化注册pythonav网站
手动注册流程:
1.打开浏览器,输入网址http://www.pythonav.com/register/
2.找到账号密码栏,分别填入账号密码信息
3.填写手机号,发送验证码
4.填写验证码
5.点击注册
6.关闭网站
自动化代码:
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get("http://www.pythonav.com/register/")
# 填写用户名
browser.find_element_by_id('id_username').send_keys('社会我超哥')
# 填写密码
browser.find_element_by_id('id_password').send_keys('chaoge666')
# 确认密码
browser.find_element_by_id('id_confirm_password').send_keys('chaoge666')
# 回填手机号
browser.find_element_by_id('id_telephone').send_keys('18xxxxxx01') # 需要一个真实的手机号
# 点击获取短信验证码
browser.find_element_by_id('smsBtn').click()
# 睡它40秒,这里是为了等发送短信验证码,然后我们手动填进去
time.sleep(40)
# 最后点击注册按钮
browser.find_element_by_id('submit').click()
# browser.find_element_by_id('submit').submit()
time.sleep(100)
browser.quit()
代码与网站按钮对应关系:

自动完成新用户注册

3.7.2. name定位
咱们通过pythonav来学习name元素定位

获取用户名输入框,自动填入信息
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://pythonav.com/login/')
# 通过标签的name属性
un = browser.find_element_by_name("username")
print(un.send_keys('社会我超哥'))
time.sleep(2)
browser.quit()

3.7.3. class name定位
找到标签中的class标签属性
案例:打开路飞学城登录页面,勾选记住密码
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/signin')
# 通过class获取span标签
span = browser.find_element_by_class_name(name='no')
# 点击事件,点击记住密码
span.click()
#点击记住密码之后,class的值变化了
print(span.get_attribute(name='class')) # no yes
# 获取当前元素的内容,也就是span标签的内容
print(span.text) # ✓
time.sleep(3)
# 再次点击span标签
span.click()
print(span.get_attribute(name='class'))
print(span.text)
time.sleep(5)
browser.quit()

案例2
获取路飞轮播图地址信息

获取一个class元素属性的信息
img = browser.find_element_by_class_name('banner')
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/home')
# 根据class获取img元素
img = browser.find_element_by_class_name('banner')
# 获取元素的指定(src)属性
print(img.get_attribute('src')) # https://hcdn1.luffycity.com/static/frontend/index/home-banner4_1535545832.4715614.png
time.sleep(5)
browser.quit()
找到第一章图片信息

那我们想要找到多张图片信息呢,如上只找到一张图片地址
找到多个class元素属性的信息
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/home')
# 根据class获取img元素
imgs = browser.find_elements_by_class_name('banner')
print(type(imgs)) #列表数据类型,可以for循环遍历取值
for i in imgs:
print(i.get_attribute(name='src'))
# 获取元素的指定(src)属性
time.sleep(5)
browser.quit()
运行结果
<class 'list'>
https://hcdn1.luffycity.com/static/frontend/index/home-banner4_1535545832.4715614.png
https://hcdn1.luffycity.com/static/frontend/activity/pcbanner_1559620281.8534358.jpeg
https://hcdn1.luffycity.com/static/frontend/index/banner11_1538122470.2779157.png
https://hcdn1.luffycity.com/static/frontend/index/home-banner4_1535545832.4715614.png
https://hcdn1.luffycity.com/static/frontend/activity/pcbanner_1559620281.8534358.jpeg
3.7.4. tag name定位
我们还是搞一搞路飞学城

tag往往用来定义一类功能,所以通过tag识别某个元素的概率很低。任意打开一个页面,都会发现大量的
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/home')
nav = browser.find_element_by_tag_name(name='nav')
print(nav.text)
time.sleep(3)
browser.quit()
'''打印结果
免费课
轻课
学位课
题库
老男孩教育
'''
此时咱们找到了一个大范围nav,只需要取出内部的span标签,给每一个span标签绑定click点击事件,就可以自动切换页面了
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/home')
# 获取span的外部nav标签
nav = browser.find_element_by_tag_name(name='nav')
# 然后再获取nav内部的所有span标签
span_list = nav.find_elements_by_tag_name(name='span')
#循环点击每一个标签,每次等待3秒
for i in span_list:
i.click()
time.sleep(3)
time.sleep(3)
browser.quit()
3.7.5. 练习题,自动切换pythonav.com的导航栏
分析网页标签内容

使用partial link text定位时,使用标签连接内容部分内容即可
而通过link text定位时,连接内容必去是完全匹配才能成功。
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://pythonav.com/index/')
# 找到link超链接标签,进行事件绑定
browser.find_element_by_link_text('首页').click()
time.sleep(2)
browser.find_element_by_link_text('知识库').click()
time.sleep(2)
browser.find_element_by_link_text('内部资料').click()
time.sleep(2)
browser.find_element_by_link_text('免费视频').click()
time.sleep(2)
browser.find_element_by_partial_link_text('每天').click()
time.sleep(2)
browser.quit()
小结:
link text/partial link text都仅能用于超链接标签的定位,其他的标签都不可以。link text是精确定位,也就是说超链接内的内容必须完全匹配才能定位成功。partial link text是模糊定位,只要超链接的内容包含该指定内容既可以匹配到。根据不同的场景,需谨慎使用。
3.7.6. css定位
之前我们是选择html标签,现在通过css样式定位
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/home')
time.sleep(1)
# 通过css selector
res = browser.find_element_by_css_selector('.luffy-home .title p[_v-2f0761bc]')
print(res.tag_name)#获取标签名
browser.quit()
案例2
通过css选择器,点击登录
import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/home')
time.sleep(1)
# 通过css selector
res = browser.find_element_by_css_selector('.header .header_cont .header_right_box .register span[_v-0ec42e90]')
print(res.tag_name)#获取标签名
res.click()
time.sleep(2)
browser.quit()
3.8. XPATH
背景:
世界上最远的距离就是明明看到一个页面元素在那里,但是我却定位不到!!
1.当难以寻找id、name、class等熟悉
2.id、name、class属性是动态加载,可能是点击、刷新后加载
如上问题就难以用元素定位。
3.8.1. 什么是XPATH
- xpath就是xml path的简称
- 原本是用来在xml文档中查找信息的语言
- xpath用于在xml文档中通过元素和属性进行导航
- selenium用户可以使用此语言在web应用中定位元素
3.8.2. Xpath使用方法
xpath定位selenium语法:find_element_by_xpath
3.8.3. XPATH定位策略
节点表达式
XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。 下表列举了常用的路径表达式:
| 表达式 | 描述 |
|---|---|
| node name | 选取此节点的所有子节点 |
| / | 从根节点选取 |
| // | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
| . | 选取当前节点 |
| .. | 选取当前节点的父节点 |
| @ | 选取属性 |
下表列举了一些表达式的应用及描述:
| 路径表达式 | 描述 |
|---|---|
| bookstore | 选取bookstore元素的所有子节点 |
| /bookstore | 选取根元素bookstore。如果路径起始于/,则此路径始终代表到某元素的绝对路径 |
| bookstore/book | 选取属于bookstore元素下的所有book元素 |
| //book | 选取book子元素,而不管它们在文档中的位置 |
| bookstore//book | 选择属于bookstore元素的所有book元素,而不管它们位于bookstore之下的什么位置 |
| //@book | 选取名为book的所有属性 |
谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。 下表列举了带有谓语的一些路径表达式,以及表达式结果:
| 路径表达式 | 结果 |
|---|---|
| /bookstore/book[1] | 选取属于bookstore子元素的第一个book元素 |
| /bookstore/book[last()] | 选取属于bookstore子元素的最后一个book元素 |
| /bookstore/book[last()-1] | 选取属于bookstore子元素的倒数第二个book元素 |
| /bookstore/book[position()<3] | 选取最前面的两个属于bookstore元素的子元素的book元素 |
| //title[@book] | 选取所有拥有名为book的属性的title元素 |
| //title[@book='lang'] | 选取所有book属性为lang的title元素 |
| /bookstore/book[price>35.00] | 选取bookstore元素的所有book元素,并且其中price属性的值必须大于35.00 |
| /bookstore/book[price>35.00]/title | 选取bookstore元素中的title元素,过滤条件是price元素值必须大于35.00 |
选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
| 通配符 | 描述 |
|---|---|
| * | 匹配任何元素节点 |
| @* | 匹配任何属性节点 |
| node() | 匹配任何类型的节点 |
实例 下表中列举了一些路径表达式及对应的结果:
| 路径表达式 | 结果 |
|---|---|
| /bookstore/* | 选取bookstore元素的所有子元素 |
| //* | 选取文档中的所有元素 |
| //title[@*] | 选取所有带有属性的title元素 |
选取若干路径
通过在路径表达式中使用|运算符,我们可以选取若干个路径。
实例
下表中列举了一些路径表达式及对应的结果:

绝对路径定位:
假如一个人,你不知道他的任何特征,直白来说,就是你不知道他的身份证号码、名字、手机号等信息,但是你知道他的位置,如xx省/ xx市/ xx区 /xx路/ xx号。你通过他的位置就可以准确找到他。从上往下查找元素的这种方法,在selenium中我们叫绝对路径定位。
简单举例:
find_element_by_xpath(‘html/body/div’)
标签名结合元素属性定位
标签名结合元素属性定位
find_element_by_xpath("//标签名[@id=‘属性值’]")
find_element_by_xpath("//标签名[@name=‘属性值’]")
find_element_by_xpath("//标签名[@class_name=‘属性值’]")
以上例举三种属性值,当然xpath不只局限于这三种,任意元素的属性值都是可以的,但要确保元素属性的唯一性。这就是xpath强大的地方,相对于单调的id、name、class_name定位,xpath结合元素属性定位元素的方法选择性更多。
有些人喜欢把标签名用星号“”代替,当然也是可以的。
find_element_by_xpath("//[@id=‘属性值’]")
层级和属性结合`**
假如你不知道某人的身份证号码、名字、手机号码等信息时无法取得联系,但是你知道某人爸爸的手机号码,此时你可以通过他爸爸来找到某人。也就是通过("/他爸爸[phone=‘手机号’]/本人") 找到某人。
换成术语就是当我们定位元素时,发现没有可以标识的唯一的元素的属性值时,那我们可以考虑用父亲标签结合属性来定位元素。例如:
find_element_by_xpath("//input[@id=‘属性值’]/div")
假如他爸爸也没有手机号码,此时你可以往上找他爷爷。也就是也就是通过("/他爷爷[phone=‘手机号’]/他爸爸/本人") 找到某人。 换成术语就是当我们定位元素时,发现父亲标签中没有可以标识的唯一的元素的属性值时,那我们可以考虑用爷爷标签结合属性来定位元素。例如:
find_element_by_xpath("//input[@id=‘属性值’]/div/span")
结合逻辑运算符
假如一个标签中有多个属性值时,且属性值不是唯一值时,此时我们可以用逻辑运算符连接多个属性来定位元素。我们用and来连接两个属性值,例如:
find_element_by_xpath("//input[@id=‘属性值’ and @name=‘属性值’]/div/span")
当然你可以用and连接更多的属性来加强定位,目标元素是能定到位。
3.8.4. xpath技巧
浏览器提供了xpath查找方法

3.8.5. xpath案例
获取路飞学城页面元素

import time
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('https://www.luffycity.com/home')
time.sleep(1)
# 首先关闭弹出框
img = browser.find_element_by_xpath('//ul/li/img[@_v-2f0761bc]')
print(img.get_attribute('src'))
time.sleep(2)
browser.quit()
3.9. Selenium之鼠标操作
在WebDriver中,关于鼠标相关操作的方法都封装在ActionChains类中。
我们来看看ActionChains类都提供了哪些鼠标操作的方法:
| Method | Description |
|---|---|
| click(on_element=None) | 鼠标左键单击 |
| click_and_hold(on_element=None) | 鼠标左键单击,但不松开 |
| context_click(on_element=None) | 鼠标右键单击 |
| double_click(on_element=None) | 鼠标左键双击 |
| drag_and_drop(source, target) | 鼠标左键单击不松开,移动到指定元素后松开(即拖拽 ) |
| drag_and_drop_by_offset(source, xoffset, yoffset) | 鼠标左键单击不松开,移动到指定坐标后松开 |
| move_by_offset(xoffset, yoffset) | 鼠标移动到某个坐标 |
| move_to_element(to_element) | 鼠标移动到某个元素 |
| move_to_element_with_offset(to_element, xoffset, yoffset) | 鼠标移动到距离某个元素的某个距离 |
| pause(seconds) | 暂停输入 |
| release(on_element=None) | 在某个元素松开鼠标左键 |
| send_keys(*keys_to_send) | 在当前元素中输入值 |
| send_keys_to_element(element, *keys_to_send) | 给某个元素输入值 |
| perform() | 相应存储的动作 |
| reset_actions() | 清除所有已存储的动作 |
3.9.1. 左键单击click
之前我们已经在用鼠标左键单击了,那就是click。这里再来学习使用ActionChains类中调用click。
我们通过访问路飞学城的轻课页面,并点击播放。
import time
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
# 获取webdriver实例
browser = webdriver.Chrome()
# 访问URL
browser.get('https://www.luffycity.com/home')
# 获取轻课标签并点击它
span3 = browser.find_element_by_class_name('span3') # 通过分析类名发现,span3只有一个
ActionChains(browser).move_to_element(span3).click().perform()
# 点击视频播放按钮
time.sleep(1)
button = browser.find_element_by_xpath('//*[@id="router-view"]/div/div[2]/button')
ActionChains(browser).move_to_element(button).click().perform()
# # 关闭浏览器
time.sleep(30) # 可以适当调整该值
browser.quit()
3.9.2. 右键点击:content_click
再来个鼠标右键的示例,我们这次打开的是多玩LOL天赋模拟器。
有以下几点需要注意:
- 如果反复打开这个网页,并且上一次有操作天赋模拟器,这一次会自动记录之前添加的点数。
- 第一次点击某个技能(巫术),第一次点击会加5点,然后右键一次减一点,这时你要左键想加回来就是加1点了。要注意第一次加5点的操作。
示例代码如下:
要求完成如图,顺序是
- 狂怒点一次+5
- 新鲜血液点一次+满,然后右击取消新鲜血液
- 点击盛宴

如图,注意第一次是左键点+5,右键-1
第二次是左键点+1 右键-1
import time
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
# 获取webdriver实例
browser = webdriver.Chrome()
# 访问URL
browser.get('http://lol.duowan.com/s/talent.html#duowan')
# 反复打开页面,有时候天赋点数会被记录,所以要先重置
time.sleep(2)
# 找到第一个狂怒,单击加5
browser.find_element_by_xpath('//*[@id="calculator"]/div[1]/div[1]').click()
# 找到第二个新鲜血液,单击加满
time.sleep(2)
browser.find_element_by_xpath('//*[@id="calculator"]/div[3]/div[1]').click()
#右击,点灭新鲜血液
#获取元素位置
xueye=browser.find_element_by_xpath('//*[@id="calculator"]/div[3]/div[1]')
#右击
time.sleep(2)
ActionChains(browser).move_to_element(xueye).context_click().perform()
#左击盛宴
time.sleep(2)
browser.find_element_by_xpath('//*[@id="calculator"]/div[4]/div[1]').click()
time.sleep(5)
#点击重置天赋
browser.find_element_by_xpath('//*[@id="reset-tallent"]').click()
# 关闭浏览器
time.sleep(50)
browser.quit()
3.10. 拖动 drag_and_drag
所谓的拖动,也就是鼠标左键点击标签不松开,直到拖动到指定标签后再松开。
来个玩个游戏。
import time
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
# 获取webdriver实例
browser = webdriver.Chrome()
# 访问URL
browser.get('http://www.jq22.com/demo/pintu20151229/')
# 点击开始按钮,开始游戏
time.sleep(1)
start = browser.find_element_by_id('start')
ActionChains(browser).move_to_element(start).click().perform()
# 准备拖动,首先要找到开始和结束的两个标签
time.sleep(2)
img1 = browser.find_element_by_xpath('//*[@id="container"]/div[18]') # 选中开始标签
img2 = browser.find_element_by_xpath('//*[@id="container"]/div[18]') # 结束标签
ActionChains(browser).move_to_element(img1).drag_and_drop(img1, img2).perform()
# 关闭浏览器
time.sleep(3)
browser.quit()
3.11. 下载菜单
下拉菜单这里可以有三种方式选择:
- select_by_index(id),通过id选择。
- select_by_value(value值),通过value值选择。
- select_by_text(“中国”),通过显示的文本内容选择。
现在让我们通过路飞学城的注册页面来演示下拉菜单的操作:
import time
from selenium import webdriver
from selenium.webdriver.support.ui import Select
# 获取webdriver实例
browser = webdriver.Chrome()
# 访问URL
browser.get('https://www.luffycity.com/signup')
# browser.maximize_window() # 窗口最大化
time.sleep(1)
# 定位到select标签
select = browser.find_element_by_class_name('phone_select')
Select(select).select_by_value('235') # 根据value值选择
# 关闭浏览器
time.sleep(5)
browser.quit()
3.12. 键盘事件
在 WebDriver 中, 将这些关于鼠标操作的方法封装在 Keys类提供。
键盘输入
来个热身的测试,输入手机号码,然后复制当前的密码粘贴到邀请码里面
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get("https://www.luffycity.com/signup")
time.sleep(1)
input_tel = driver.find_element_by_class_name('phone')
input_tel.send_keys("15210858004")
time.sleep(5)
driver.close()
3.13. 百度输入
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
import time
driver = webdriver.Chrome()
# driver.maximize_window()
driver.get("https://www.baidu.com/")
time.sleep(2)
driver.find_element_by_id('kw').send_keys('selenium')
time.sleep(2)
driver.find_element_by_id("su").send_keys(Keys.ENTER) #通过回车键来代替鼠标的左键
driver.quit()
3.14. 窗口切换
查看如下代码,由于网速慢,代码执行会报错
from selenium import webdriver
import time
driver = webdriver.Chrome()
driver.get("https://www.baidu.com/")
time.sleep(1)
kw = driver.find_element_by_id("kw")
kw.send_keys("路飞学城")
time.sleep(2)
su = driver.find_element_by_id("su")
su.click()
lufei = driver.find_element_by_link_text("路飞学城")
lufei.click()
time.sleep(5)
print(driver.window_handles)
driver.switch_to.window(driver.window_handles[0])
time.sleep(2)
driver.switch_to.window(driver.window_handles[1])
time.sleep(2)
driver.switch_to.window(driver.window_handles[0])
time.sleep(5)
driver.close()
3.15. 强制等待事件
之前我们的代码里见到很多time.sleep()是因为代码执行的太快了,即使我们人为的网页功能测试,也得等待网页元素加载完毕才能点击。代码亦是如此,网页元素还没加载好,代码就想要点击,必然出错,因此我们选择添加time.sleep()强制线程睡眠,等待元素出现后再进行代码执行。
元素定位不到,一般是
- 有frame
- 没有添加等待
代码运行速度和网页元素加载速度是不一样的,好比闪电侠和奥特曼约好去打怪兽,闪电侠刷一下把怪兽打死了,奥特曼还在穿衣服。。。奥特曼这不就很尴尬么。。
WebDriver提供了两种类型的等待:显性等待和隐性等待、time.sleep属于强制等待
3.15.1. 隐性等待
隐性等待代码implicitly_wait(xx),隐性等待意义是:无论闪电侠到了哪,都需要等待奥特曼xx秒,如果奥特曼规定时间到了,两人在一起去打怪兽,如果奥特曼规定时间内没到,闪电侠那就自己去了,奥特曼也就报错了!!
隐形等待是设置了一个最长等待时间,如果在规定时间内网页加载完成,则执行下一步,否则一直等到时间截止,然后执行下一步。注意这里有一个弊端,那就是程序会一直等待整个页面加载完成,也就是一般情况下你看到浏览器标签栏那个小圈不再转,才会执行下一步,但有时候页面想要的元素早就在加载完成了,但是因为个别js之类的东西特别慢,我仍得等到页面全部完成才能执行下一步,我想等我要的元素出来之后就下一步怎么办?有办法,这就要看selenium提供的另一种等待方式——显性等待wait了。
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
kw = driver.find_element_by_id("kw")
kw.send_keys("路飞学城")
su = driver.find_element_by_id("su")
su.click()
#点击路飞学城页面
driver.implicitly_wait(20) #隐性等待,不等待就报错
lufei = driver.find_element_by_link_text("路飞学城")
lufei.click()
# driver.switch_to_window(driver.window_handles[1])
driver.current_window_handle
time.sleep(5)
driver.quit()
3.15.2. 显示等待
显性等待就是WebDriverWait,配合该类的until()和until_not()方法,就能够根据判断条件而进行灵活地等待了。它主要的意思就是:程序每隔xx秒看一眼,如果条件成立了,则执行下一步,否则继续等待,直到超过设置的最长时间,然后抛出TimeoutException。
WebDriverWait
wait模块的WebDriverWait类是显性等待类,先看下它有哪些参数与方法:
selenium.webdriver.support.wait.WebDriverWait(类)
__init__
driver: 传入WebDriver实例,即我们上例中的driver
timeout: 超时时间,等待的最长时间(同时要考虑隐性等待时间)
poll_frequency: 调用until或until_not中的方法的间隔时间,默认是0.5秒
ignored_exceptions: 忽略的异常,如果在调用until或until_not的过程中抛出这个元组中的异常,
则不中断代码,继续等待,如果抛出的是这个元组外的异常,则中断代码,抛出异常。默认只有NoSuchElementException。
until
method: 在等待期间,每隔一段时间调用这个传入的方法,直到返回值不是False
message: 如果超时,抛出TimeoutException,将message传入异常
until_not 与until相反,until是当某元素出现或什么条件成立则继续执行,
until_not是当某元素消失或什么条件不成立则继续执行,参数也相同,不再赘述。
method
message
案例
WebDriverWait(driver, 超时时长, 调用频率, 忽略异常).until(可执行方法, 超时时返回的信息)
WebDriverWait(driver,5,0.5).until(EC.presence_of_element_located((By.LINK_TEXT,"路飞学城")))
- driver :浏览器驱动。
- timeout :最长超时时间,默认以秒为单位。
- poll_frequency :检测的间隔(步长)时间,默认为0.5S。
- ignored_exceptions :超时后的异常信息,默认情况下抛NoSuchElementException异常。
WebDriverWait()一般由until()或until_not()方法配合使用,下面是until()和until_not()方法的说明。
- until(method, message=‘’)
调用该方法提供的驱动程序作为一个参数,直到返回值为True。
- until_not(method, message=‘’)
调用该方法提供的驱动程序作为一个参数,直到返回值为False。
在本例中,通过as关键字将expected_conditions 重命名为EC,并调用presence_of_element_located()方法判断元素是否存在。
expected_conditions
expected_conditions是selenium的一个模块,其中包含一系列可用于判断的条件:
selenium.webdriver.support.expected_conditions(模块)
这两个条件类验证title,验证传入的参数title是否等于或包含于driver.title
title_is
title_contains
这两个人条件验证元素是否出现,传入的参数都是元组类型的locator,如(By.ID, 'kw')
顾名思义,一个只要一个符合条件的元素加载出来就通过;另一个必须所有符合条件的元素都加载出来才行
presence_of_element_located
presence_of_all_elements_located
这三个条件验证元素是否可见,前两个传入参数是元组类型的locator,第三个传入WebElement
第一个和第三个其实质是一样的
visibility_of_element_located
invisibility_of_element_located
visibility_of
这两个人条件判断某段文本是否出现在某元素中,一个判断元素的text,一个判断元素的value
text_to_be_present_in_element
text_to_be_present_in_element_value
这个条件判断frame是否可切入,可传入locator元组或者直接传入定位方式:id、name、index或WebElement
frame_to_be_available_and_switch_to_it
这个条件判断是否有alert出现
alert_is_present
这个条件判断元素是否可点击,传入locator
element_to_be_clickable
这四个条件判断元素是否被选中,第一个条件传入WebElement对象,第二个传入locator元组
第三个传入WebElement对象以及状态,相等返回True,否则返回False
第四个传入locator以及状态,相等返回True,否则返回False
element_to_be_selected
element_located_to_be_selected
element_selection_state_to_be
element_located_selection_state_to_be
最后一个条件判断一个元素是否仍在DOM中,传入WebElement对象,可以判断页面是否刷新了
staleness_of
显示等待元素代码
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
kw = driver.find_element_by_id("kw")
kw.send_keys("路飞学城")
su = driver.find_element_by_id("su")
su.click()
# 就是这里加上一句话
# 等待页面出现路飞学城这个元素
WebDriverWait(driver,5,0.5).until(EC.presence_of_element_located((By.LINK_TEXT,"路飞学城")))
lufei = driver.find_element_by_link_text("路飞学城")
lufei.click()
time.sleep(5)
driver.quit()