Selenium —— 基于Web的UI自动化测试工具
一、搭建
S
e
l
e
nium
的环境
1.
先安装
selenium
这个第
3
方包
理解:对
p
yt
hon
而言,
s
e
l
en
i
um
是一个第
3
方的包,需要额外下载和安装。
推荐使用
p
i
p
.
e
x
e
工具(
p
yt
hon
官方提供的,安装了
p
yt
hon
解释器后就有)在线下载安装
s
e
l
en
i
um
。
p
i
p
.
e
x
e
工具的使用
——
管理第
3
方包(查看、安装、卸载)
p
i
p
.
e
x
e
工具放置在
p
yt
hon
解释
器所在目录下的
S
c
r
i
p
t
s
目录(默认是配置到了环境变量
pa
t
h
下的)
使用
p
i
p
安装的第
3
方包存放在
p
yt
hon
解释器所在目录下的
L
i
b
\s
it
e
-
package
s
目录下
可以使用
PyCharm
中提供的包管理器工具(底层还是调用
pip
命令)
F
il
e
-
>
S
e
tti
ng
s
.
-
>
P
r
o
j
ec
t
:
XXX
-
>
P
r
o
j
ec
t
I
n
t
e
r
p
r
e
t
e
r
-
>
点击
+
图标
-
>
输入
s
e
l
en
i
um
-
>
I
n
s
t
a
ll
Package
2.
下载并配置对应浏览器的浏览器驱动程序文件
理解:
s
e
l
en
i
um
操作浏览器,必须通过浏览器驱动程序来向真正的浏览器发出指令。
不同的浏览器有不同的驱动程序文件 同一款浏览器的不同版本也要
尽量对应不同版本的驱动程序文件。
下载浏览器驱动程序
将下载后解压出来的驱动程序文件,放置到环境变量
PATH
能找得到的目录下
pip list #
查看所有已安装的第
3
方包
pip uninstall
包名
#
卸载指定的第
3
方包(可以用空格隔开,连续输入多个要卸载的包名)
pip install
包名
#
安装第
3
方包
pip install -i
镜像加速地址 包名
#
安装第
3
方包(使用镜像加速地址)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple selenium
(
1
)
Chrome
(强烈推荐使用
Chrome
)
http://npm.taobao.org/mirrors/chromedriver
(
2
)
Firefox
https://github.com/mozilla/geckodriver/releases/
(
3
)
IE
http://selenium-release.storage.googleapis.com/index.html
(
4
)
Edge
https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver
如果不配置环境变量
P
A
T
H
,也可以通过硬编码,指定驱动程序文件的路径,以
C
h
r
ome
浏览
器为例:
注意:如果修改了环境变量,记得要重启
P
y
C
ha
r
m
二、
W
e
bDriv
e
r
——
W
e
b
驱动类
对
W
ebDriver
类的理解
——
操作浏览器(启动浏览器、打开页面、关闭页面、退出浏览器、定位
元素)
s
e
l
en
i
um
针对不同的浏览器驱动,都定义了一个
WebDriver
的类,这个类定义在
webdriver.py
的模块中,这个模块放置在跟各自浏览器同名的包中。
s
e
l
en
i
um
为了访问方便,为各自浏览器的
WebDriver
类都定义了别名,别名为浏览器名(首
字母大写),例如:
C
h
r
ome
浏览器的
WebDriver
类的别名为
Chrome
创建
W
ebDriver
驱动类的对象,就能启动浏览器,创建驱动进程
方式
1
——
使用别名(企业里最常用,简洁)
方式
2
——
使用完整类名(比较冗长)
通过
W
ebDriver
对浏览器进行的各种操作
dr.get("URL")
——
打开指定
UR
L
的页面
dr.close()
——
关闭当前页面(如果浏览器中只有
1
个页面,浏览器也会退出),不会结
束驱动进程。
dr.quit()
——
退出浏览器(关闭浏览器中的所有页面),会结束驱动进程。
dr.title
——
获取页面在窗口标题栏上的标题文本
dr.current_url
——
获取当前页面的
UR
L
地址
三、定位元素
总结:八种策略、两套方法、长款和短款方法名
定位单个元素的方法
——
find
_
element
定位单个元素方法的共同特征
返回值的数据类型是
We
b
Eleme
n
t
,代表找到的页面上的标签元素对象。
如果页面上有多个匹配的元素,只返回
1
个元素(一般是第
1
个匹配的元素)
c =
webdriver.Chrome(executable_path=r"E:\browser_drivers\chromedriver.exe"
)
from selenium import webdriver
dr = webdriver.Chrome() #
启动浏览器
from selenium.webdriver.chrome.webdriver import WebDriver
dr = WebDriver() #
启动浏览器
如果页面上没有匹配的元素,程序会报错
——
NoSuchElementException
。
尽量根据标签上的唯一特征进行定位。
8
种不同策略的定位方法
dr.find_element_by_id("id
属性值
")
——
根据标签上的
i
d
属性值
dr.find_element_by_name("name
属性值
")
——
根据标签上的
name
属性值
dr.find_element_by_class_name("
类样式名
")
——
根据标签上
c
l
a
ss
属性值中的类
样式名
如果
c
l
a
ss
属性值中有空格,只能用空格分隔出来的其中一个
dr.find_element_by_tag_name("
标签名
")
——
根据标签名
dr.find_element_by_link_text("
链接文本
")
——
根据超链接标签的链接文本
此策略只能用于定位
<a>
标签
dr.find_element_by_partial_link_text("
部分
链接文本
")
——
根据部分超链接文
本
此策略只能用于定位
<a>
标签
dr.find_element_by_css_selector("CSS
选择器
")
——
根据
CSS
选择器
dr.find_element_by_xpath("XPATH
表达式
")
——
根据
X
P
A
T
H
表达式
定位多个元素的方法
——
find
_
elements
(使用得较少)
定位多个元素方法的共同特征
返回值的数据类型是
list
,代表找到的所有匹配元素的列表,列表中的元素的数据类
型是
We
b
Eleme
n
t
,代表每一个标签元素对象。 如果页面上没有匹配的元素,返回的列
表的长度为
0
(列表中是空的)
8
种不同策略的定位方法
dr.find_elements_by_id("id
属性值
")
——
根据标签上的
i
d
属性值
dr.find_elements_by_name("name
属性值
")
——
根据标签上的
name
属性值
dr.find_elements_by_class_name("
类样式名
")
——
根据标签上
c
l
a
ss
属性值中的类
样式名
如果
c
l
a
ss
属性值中有空格,只能用空格分隔出来的其中一个
dr.find_elements_by_tag_name("
标签名
")
——
根据标签名
dr.find_elements_by_link_text("
链接文本
")
——
根据超链接标签的链接文本
此策略只能用于定位
<a>
标签
dr.find_elements_by_partial_link_text("
部
分链接文本
")
——
根据部分超链接
文本
此策略只能用于定位
<a>
标签
dr.find_elements_by_css_selector("CSS
选择器
")
——
根据
CSS
选择器
dr.find_elements_by_xpath("XPATH
表达式
")
——
根据
X
P
A
T
H
表达式
长款和短款方法名
长款方法名
dr.find_element_by_xxx("
值
")
dr.find_elements_by_xxx("
值
")
短款方法名
dr.find_element(By.XXX, "
值
")
dr.find_elements(By.XXX, "
值
")
selenium
定义了一个代表元素定位策略的类
——
B
y
类
By
类中定义了
8
个类属性,分别代表
8
种策略
By.ID
、
By.NAME
、
By.CLASS_NAME
、
By.TAG_NAME
、
By.LINK_TEXT
、
By.PARTIAL_LINK_TEXT
、
By.CSS_SELECTOR
、
By.XPATH
四、
W
e
b
E
l
e
m
e
nt
——
标签元素类(操作页面上的标签元素)
对
W
eb
E
lement
的理解
W
ebE
l
emen
t
类代表的是页面上的标签元素。 往往是通过调用驱动对象定位元素的方法,返
回找到的页面上的标签元素,这个标签元素就 是
W
ebE
l
emen
t
类的对象。
获取到标签元素对象后,可以对其进行各种操作
——
输入、单击、获取文本等等。
标签元素具有的常见操作
标签元素对象
.send_keys("
文本
")
——
向输入框中输入文本内容
标签元素对象
.click()
——
单击标签元素
标签元素对象
.clear()
——
清空文本框
标签元素对象
.text
——
获取标签内部的文本
只有双标签才有有效的内部文本【开始标签和结束标签之间的文本】
单标签的内部文本永远为空串
标签元素对象
.get_attribute("
属性名
")
——
获取标签上指定属性的值
五、文件上传的实现思路
思路
定位到文件域标签元素后,只需要向其输入(
s
end
_
ke
y
s
)要上传文件的绝对路径即可。
文件的路径必须正确,否则会报错
文件的路径格式必须是绝对路径,否则会报错
企业中的实际做法
首先将作为上传的资源文件,都整体上放置到项目目录下。(提交代码的时候,可以一起提
交) 一般,项目目录下会统一专门建好存放这些资源的文件夹,甚至文件夹下还会再创建子
文件 夹来分类。 项目中,会有统一的项目绝对路径的配置代码,将项目的绝对路径用代码
动态的获取,存储 到变量中,后续凡是使用项目绝对路径的位置,禁止写死(写字符串的字
面量),必须用项 目路径的变量进行拼接。
六、使用
Select
类来操作下拉选择框元素
dr.find_element(By.NAME, "face").send_keys(r"E:\upload\
张学友
.png")
思路
先创建一个
Select
类的对象(必须要传入定位到的下拉框标签元素),代表页面上的下拉
框元素。
调用下拉框对象的方法,来选中其中的选项
三种选中选项的方法
s
e
l
ec
t
_
b
y
_
vi
s
i
b
l
e
_
t
e
x
t
("
选项文本
")
——
根据选项的文本,选中选项
s
e
l
ec
t
_
b
y
_
v
a
l
ue
("
v
a
l
ue
属性值
")
——
根据选项的标签上的
v
a
l
ue
属性值,选中选项
s
e
l
ec
t
_
b
y
_
i
nde
x(
索引
)
——
根据选项标签在整个
s
e
l
ec
t
标签下的排序(索引从
0
开始),选中
选项
获取下拉框中的所有选项标签元素的列表
op
ti
on
s
op
ti
on
s
的数据类型是列表,装的是该下拉框标签里的所有选项的标签元素,列表中
的元素是
W
ebE
l
emen
t
类型的。
七、使用
d
r.s
w
itc
h
_t
o
.alert
获取页面上的
JS
弹窗
场景
当页面上出现了
J
S
弹窗,因为它不是标签元素,无法使用元素定位
可以对
J
S
弹窗进行的操作
八、使用
d
r.s
w
itc
h
_t
o
.frame(
XX
)
切换框架
场景
当发现要定位的元素在
<iframe>
或
<frame>
标签里面,我们在外部页面也无法直接定位到
的,需要将驱动对象切换进入到框架内部,再定位元素。
将驱动切换进入到框架内部
框架的特征
传入框架标签的
i
d
或
name
属性 传入框架标签的索引(从
0
开始)
,它是这个页面中的第几个框架
将驱动对象从内部框架切换到外部页面
d = dr.switch_to.alert #
获取页面上的
JS
弹窗,返回一个代表这个弹窗的对象,用变量
d
代
表
print(d.text) #
获取
JS
弹窗上的提示文本
d.accept() #
点击
JS
弹窗上的
“
确定
”
按钮
d.dismiss() #
点击
JS
弹窗上的
“
取消
”
按钮
d.send_keys("
文本内容
") #
向
JS
弹窗上的输入框中输入指定的文本内容
dr.switch_to.frame(
框架的特征
)
dr.switch_to.parent_frame() #
切换到当前框架的上一级
dr.switch_to.default_content() #
切换到最外部页面
九、使用
d
r.s
w
itc
h
_t
o
.
w
i
ndo
w
(
XX
)
切换窗口
场景:当前窗口中,又打开了新的窗口,如果希望将
d
r
切换到新窗口中去定位元素,就需要进行
切换窗口。
切换到新窗口
窗口句柄
——
浏览器给每一个窗口起了一个唯一的编号(一个很长的含十六进制的字符串编号)
每次启动浏览器后,窗口的编号都是随机的,窗口的编号是唯一的。
获取浏览器中窗口的窗口句柄
十、使用
Acti
on
C
h
ai
n
s
类实现不常见的鼠标操作
代码套路
ActionChains
的操作
doub
l
e
_
c
li
ck
——
双击指定的元素
mo
v
e
_
t
o
_
e
l
emen
t
——
将鼠标移动到元素上
c
li
ck
_
and
_
ho
l
d
——
点住元素不放
r
e
l
ea
s
e
——
放开鼠标
……
十一、调用
d
r.exec
u
te_scri
p
t(JS代码)
将
JS
代码发送到页面 上
执行
场景
当你希望将
J
S
代码发送到页面上去执行时,就调用此方法 测试工
程师极少用这个方法:场景少、几乎对
J
S
的掌握普遍很弱
案例
页面上有只读的出生日期输入框,无法直接输入出生日期,点选日历插件又过于繁琐。 因此
,我们考虑编写一段
“
移除出生日期输入框上的只读属性
”
的
j
s
代码,发送到浏览器上去执 行。
十二、给页面或标签元素拍快照,保存至图片文件
dr.switch_to.window(
新窗口句柄
)
dr.window_handles #
获取浏览器中所有的窗口句柄列表(
list
)
dr.current_window_handle #
获取驱动对象指向的当前窗口句柄(
str
)
ActionChains(dr).
操作
1(
标签元素
).
操作
2(
标签元素
).
操作
3(
标签元素
).perform()
dr.execute_script("document.getElementById(’date1’).removeAttribute(’readonl
y’);")
给整个页面拍快照
给某个标签元素拍快照
十三、使用
K
eys
类来表现一些特殊按键
页面上的输入框标签元素,是可以发送特殊按键的,特殊按键是定义在
K
eys
类中的类属性
Keys.CONTROL
——
控制键(
c
t
r
l
)
Keys.ALT
——
a
lt
键
Keys.SHIFT
——
s
h
ift
键
Keys.F10
——
f
10
键
Keys.UP
——
方向键
↑
……
向输入框中,发送一些快捷键(特殊按
键
+
字母)
十四、 三种等待
强制等待
——
sleep
本质:调用
time
模块的
sleep
函数,让程序停下来,直到指定的时间过去,再继续执行后
续的脚本 在
s
e
l
en
i
um
编码中,强制等待是使用最多的一种等待方式:等待页面上的元素出现
、等待页 面上的元素更新、等待一个时间过去、让我们编码时更容易调试(让我们观察)、
……
隐式等待
——
智能等待
本质:调动
dr
的设置隐式等待的方法,设置一个最大的等待时长。设置后,后续凡是使用
dr
对象定位元素时,都会受到隐式等待的影响:如果要定的元素不存在,则会等到元素出现
为止,或者等到超过事先设置的最大时长而报错(
No
S
uchE
l
emen
t
E
x
cep
ti
on
)。
特点:
只能用于等待页面上的元素出现
智能地等到元素出现就不等了 只
需要设置一次
示例代码
dr.get_screenshot_as_file("xxx.png") #
给整个页面截图,并保存至
“xxx.png”
文件中
标签元素对象
.screenshot("xxx.png") #
给指定的标签元素截图,并保存至
“xxx.png”
文件中
from selenium.webdriver.common.keys import Keys
标签元素
.send_keys(Keys.CONTROL, "a") #
全选
标签元素
.send_keys(Keys.CONTROL, "c") #
复制
标签元素
.send_keys(Keys.CONTROL, "v") #
粘贴
dr.implicitly_wait(10) #
设置隐式等待的最大时长为
10
秒
显式等待
——
智能等待
本质:
需要先创建一个
WebDriverWait
类的对象实例,需要传入
d
r
和最大等待时长作参数。 再
调用等待对象的
until
方法(直到
……
才
……
),传入一个要等待的条件对象,真正让 程
序停下来的就是这个方法,它会等到
“
条件
”
满足为止,才结束等待,如果一直没有满 足
条件,则会报错(
T
i
meou
t
E
x
cep
ti
on
) 如果条件成立了,则立即返回。我们一般会创建
一个
presence_of_element_located
(被定位元素的出现)条件对象,传给
un
til
方法。创
建此条件对象时,需要传入要定位的元素的定位器
定位器(
l
oca
t
o
r
)
——
本质就是有一个定位策略和值组成的元组,例如:
(By.ID,
"cont")
特点:
主要用于等待页面上的元素出现
智能地等到元素出现就不等了
直接用显式等待的方式来定位元素,而不用传统的
find_element
方法来定位元素了。
示例代码
在企业中,如果需要使用显式等待,一般会定义公共的函数,将显式等待的实现代码封装起
来。
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.expected_conditions import
presence_of_element_located
#
要定位的元素的定位器
locator = (By.ID, "cont")
#
以显式等待的方式找元素,如果找到了,就会返回这个
WebElement
elem = WebDriverWait(dr,
10).until(presence_of_element_located(locator))
print(elem.text)