1. Selenium 元素定位方法

1.1 元素定位工具:chropath

chropath 官网:https://autonomiq.io/deviq-chropath.html

其它下载地址:https://www.crx4chrome.com/crx/50476

chropath 是一款浏览器插件,用于元素属性识别和自动获取,支持主流浏览器。

我们常规定位元素的方式是通过查看「检查」中的内容,这种方式对于新手来说比较不直观:

而下载了 chropath 之后,则可以快速直观的获取到 “XPath”、”cssSelector”、”tagName” 等相关信息:

1.2 八类基本元素定位方式

在做 WEB UI 自动化时,最根本的就是操作页面上的元素,首先我们要能定位到这些元素,然后才能操作这些元素。

定位方法:driver.find_element(By.XXX, "YYY")

注意: 并不是每个页面的元素都需要用到下面的八种方法,比如一些页面的元素就是没有 id,则就不能用 id 进行定位。

元素名称 By.XXX
id By.ID
name By.NAME
class name By.CLASS_NAME
tag name By.TAG_NAME
link text By.LINK_TEXT
partial link text By.PARTIAL_LINK_TEXT
xpath By.XPATH
css selector By.CSS_SELECTOR

1.2.1 通过 ID 定位

例如,百度页面输入框的 ID 属性为 “kw”。

我们通过 ID 定位的结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 申请一个浏览器驱动实例
driver = webdriver.Chrome()
# 打开访问页面
driver.get('http://www.baidu.com')
# 通过 ID 定位搜索框,并输入 selenium
element = driver.find_element(By.ID, 'kw')
element.send_keys('selenium')
# 等待 3 秒
time.sleep(3)
# 退出
driver.quit()

1.2.2 通过 Name 定位

还是拿上面百度的例子举例,效果是一样的,都能成功定位到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 申请一个浏览器驱动实例
driver = webdriver.Chrome()
# 打开访问页面
driver.get('http://www.baidu.com')
# 通过 ID 定位搜索框,并输入 selenium
element = driver.find_element(By.NAME, 'wd')
element.send_keys('selenium')
# 等待 3 秒
time.sleep(3)
# 退出
driver.quit()

1.2.3 通过 Class Name 定位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 申请一个浏览器驱动实例
driver = webdriver.Chrome()
# 打开访问页面
driver.get('http://www.baidu.com')
# 通过 ID 定位搜索框,并输入 selenium
element = driver.find_element(By.CLASS_NAME, 's_ipt')
element.send_keys('selenium')
# 等待 3 秒
time.sleep(3)
# 退出
driver.quit()

1.2.4 通过 Tag Name 定位

注意: 不推荐用 Tag 进行定位,因为一个页面 tag 很可能不是唯一的。

Link Text 和 Partail Link Text 都是用于定位超链接元素,例如百度左上角这些元素,点击后会跳转到另一个页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 申请一个浏览器驱动实例
driver = webdriver.Chrome()
# 打开访问页面
driver.get('http://www.baidu.com')
# 通过 ID 定位搜索框,并输入 selenium
element = driver.find_element(By.LINK_TEXT, '新闻')
element.click()
# 等待 3 秒
time.sleep(3)
# 退出
driver.quit()

Partial Link Text 和 Link Text 的区别是可以模糊匹配超链接文本,例如有些超链接文本太长,我可以只输入一部分文字进行匹配,就能定位到对应的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 申请一个浏览器驱动实例
driver = webdriver.Chrome()
# 打开访问页面
driver.get('http://www.baidu.com')
# 通过 ID 定位搜索框,并输入 selenium
element = driver.find_element(By.PARTIAL_LINK_TEXT, 'hao1')
element.click()
# 等待 3 秒
time.sleep(3)
# 退出
driver.quit()

1.2.7 通过 Xpath 定位

对于实际场景中,很多元素没办法通过前面的六种简单的方式定位,就需要通过后面两种方式来进行定位,先来看 Xpath 是怎么定位的:

  • 绝对路径:以 / 开头定位,例如 `/html/body/input/xx
  • 相对路径:以 // 开头定位,例如 //input[@id='kw' and @name='wd]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"""
定位百度搜索框,并输入 selenium
"""
# 方法一
element = driver.find_element(By.XPATH, "//*[@id='kw']")
# 方法二
element = driver.find_element(By.XPATH, "//*[@name='wd']")
# 方法三
element = driver.find_element(By.XPATH, "//*[@id='kw' and @name='wd']")
element.send_keys('selenium')

"""
定位文本为「新闻」的超链接,并点击
"""
element = driver.find_element(By.XPATH, "//a[text()='新闻']")
element.click()

"""
定位文本为「hao123」的超链接,并点击
"""
element = driver.find_element(By.XPATH, "//a[contains(text(), 'hao')]")
element.click()

"""
如果某个元素本身没有唯一的属性可以定位,则可以结合其父节点的属性来唯一定位到这个元素
"""
element = driver.find_element(By.XPATH, "//form[@id='form']/span/input")

1.2.8 通过 CSS Selector 定位

通过 CSS Selector 整体功能和 Xpath 类似,只是 CSS 定位的语法不同,常用语法如下:

  • 以 ID 定位:#id
  • 以 Class Name 定位:.class
  • 以 Tag Name 定位:tag
  • 以 Tag Name 下的某个 ID 定位:tag#id
  • 以 Tag Name 下的某个 Class Name 定位:tag.class
  • 通过其它属性定位:[属性名=属性值]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"""
定位百度搜索框,并输入 selenium
"""
# 方法一
element = driver.find_element(By.CSS_SELECTOR, ".s_ipt")
# 方法二
element = driver.find_element(By.CSS_SELECTOR, "#kw")
# 方法三
element = driver.find_element(By.CSS_SELECTOR, "input")
# 方法四
element = driver.find_element(By.CSS_SELECTOR, "input#kw")
# 方法五
element = driver.find_element(By.CSS_SELECTOR, "input.s_ipt")
# 方法六
element = driver.find_element(By.CSS_SELECTOR, "input[name='wd']")
# 方法七
element = driver.find_element(By.CSS_SELECTOR, "input[name='wd'][id='kw']")
element.send_keys('selenium')

1.3 复数定位元素方式

定位方法:driver.find_elements(By.XXX, "YYY")

find_elements 属于 selenium 中复数的定位元素内容,find_elements 主要定位页面上多个相同的元素。

例如,我现在想定位百度页面左上角一列的超链接按钮。

而定位的方法其实和上面的 find_element 定位方式一模一样,只是这里的方法名后面多了一个 s,所以我们现在只用找到这些相同元素下相同的属性值用来定位。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

# 申请一个浏览器驱动实例
driver = webdriver.Chrome()
# 打开访问页面
driver.get('http://www.baidu.com')
# 通过 target 属性定位搜索框,并点击其中的几个按钮
elements = driver.find_elements(By.XPATH, "//a[@class='mnav c-font-normal c-color-t' and @target='_blank']")
print(len(elements))
elements[0].click()
elements[1].click()
elements.pop().click()
# 等待 3 秒
time.sleep(3)
# 退出
driver.quit()

1.4 元素定位策略

推荐的定位方式的优先级:ID > name > CSS selector > Xpath

定位元素的注意事项:

  • 找到待定位元素的唯一属性
  • 如果该元素没有唯一属性,则先找到能被唯一定位到的父元素/子元素/相邻元素进行辅助定位
  • 不要使用随机唯一属性定位
  • 最重要的是多跟研发沟通,尽量把关键元素加上 ID 或者 name,并减少不合理的页面元素,例如重复 ID 这样的事情最好不要发生

2. Selenium 操作

2.1 元素的操作

在自动化测试中,成功定位到元素后,即可对元素进行相应的操作。

webdriver 中比较常用的操作对象的方法如下:

方法名称 功能
click() 点击对象
send_keys() 在对象上模拟键盘输入
clear() 清楚对象内容
submit() 表单提交,可以触发 action 行为
text 用于获取对象的文本信息
size 用于获取元素尺寸
get_attribute() 获取元素属性
is_displayed() 元素是否可见
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from selenium import webdriver
from selenium.webdriver.common.by import By
import time

browser = webdriver.Chrome()
browser.get("https://www.baidu.com")
browser.implicitly_wait(30)

# 输入内容
browser.find_element(By.ID, "kw").send_keys("python")
time.sleep(2)
# 清空内容
browser.find_element(By.ID, "kw").clear()
time.sleep(1)
# 再次输入内容
browser.find_element(By.ID, "kw").send_keys("http")
time.sleep(2)
# 点击
browser.find_element(By.ID, "su").click()
# browser.find_element(By.ID, "su").submit() # 提交

# 定位元素
els = browser.find_element(By.CLASS_NAME, "hint_PIwZX")

# 获取元素的文本内容
text = els.text
print(text) # 打印元素文本

# 获取元素尺寸
print(browser.find_element(By.ID, "kw").size)
print(browser.find_element(By.ID, "su").size)

# 判断元素是否可见
if browser.find_element(By.ID, "kw").is_displayed():
print("输入框可见")
print(browser.find_element(By.ID, "su").is_displayed())

# 获取元素属性
print(browser.find_element(By.ID, "kw").get_attribute("type"))
print(browser.find_element(By.ID, "kw").get_attribute("value"))

time.sleep(2)
browser.quit()

效果演示

执行结果

2.2 浏览器的操作

在自动化测试中,除了可以对元素进行操作外,同样也支持对浏览器进行控制。

webdriver 中比较常用的操作浏览器的方法:

方法名称 功能
maximize_window 浏览器最大化
set_window_size 设置浏览器的宽和高
back 后退
forward 前进
refresh 刷新
title 打印 title
current_url 打印 url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import time
from selenium import webdriver

browser = webdriver.Chrome()

# 将浏览器最大化显示
browser.maximize_window()
# # 让浏览器以宽 400,高 800 显示
# browser.set_window_size(400, 800)

# 第一次访问百度页面
first_url = "https://ww.baidu.com"
browser.get(first_url)
time.sleep(2)

# 访问新闻页面
second_url = "https://news.baidu.com"
browser.get(second_url)
time.sleep(2)

# 第一次打印结果
print(browser.title)
print(browser.current_url)

# 后退到百度页面
browser.back()
time.sleep(2)

# 第二次打印结果
print(browser.title)
print(browser.current_url)

# 前进道新闻页面
browser.forward()
time.sleep(2)

# 第三次打印结果
print(browser.title)
print(browser.current_url)

# 模拟浏览器刷新
browser.refresh()

time.sleep(2)
browser.quit()

效果演示

执行结果

2.3 键盘按键用法

在 Selenium 自动化测试中,要调用键盘按键操作需要引入 keys 包,并通过 send_keys() 调用按键。

Keys() 类提供了键盘上几乎所有按键的方法,这个类可以用来模拟键盘上的按键,包括各种组合键,如 Ctrl+A、Ctrl+X、Ctrl+C、Crtl+V 等等。

属性 含义
Keys.DOWN, Keys.UP, Keys.LEFT, Keys.RIGHT 键盘箭头键
Keys..ENTER, Keys.RETURN 回车和换行键
Keys.HOME, Keys.END, Keys.PAGE_DOWN, Keys.PAGE_UP Home 键、End 键、Page Up 键、Page Down 键
Keys.ESCAPE, Keys.BACK_SPACE, Keys.DELETE Esc、Backspace 和删除键
Keys.F1, Keys.F2, …, Keys.F12 键盘顶部的 F1 到 F12
Keys.TAB Tab 键

模拟键盘的操作首先需要引入 Keys 类:

1
from selenium.webdriver.common.keys import Keys

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

browser = webdriver.Chrome()
browser.maximize_window()
browser.get("https://www.baidu.com")

# 输入内容
browser.find_element(By.ID, "kw").send_keys("selenium1")
time.sleep(2)

# 删除多输入的一个 1
browser.find_element(By.ID, "kw").send_keys(Keys.BACK_SPACE)

# 模拟空格输入
browser.find_element(By.ID, "kw").send_keys(Keys.SPACE)
browser.find_element(By.ID, "kw").send_keys("教程")
time.sleep(2)

# 通过回车键代表点击操作
browser.find_element(By.ID, "su").send_keys(Keys.ENTER)
time.sleep(2)

html = browser.find_element(By.TAG_NAME, "html")

# 滚动到该页的底部
html.send_keys(Keys.END)
time.sleep(1)

# 滚动到该页的首部
html.send_keys(Keys.HOME)
time.sleep(1)

# ctrl+a 全选输入框内容
browser.find_element(By.ID, "kw").send_keys(Keys.CONTROL, "a")
time.sleep(1)
# ctrl+x 剪切输入框内容
browser.find_element(By.ID, "kw").send_keys(Keys.CONTROL, "x")
time.sleep(1)
# ctrl+v 粘贴内容到输入框
browser.find_element(By.ID, "kw").send_keys(Keys.CONTROL, "v")
time.sleep(1)

# 通过回车键来代替单机操作
browser.find_element(By.ID, "su").send_keys(Keys.ENTER)
time.sleep(2)

browser.quit()

2.4 鼠标事件用法

WebDriver 中,就爱那个鼠标的操作封装在 ActionChains 类中,常见方法如下:

方法名称 功能
context_click() 右击
double_click() 双击
move_to_element() 悬停
drag_and_drop() 拖动
perform() 执行所有 ActionChains 中存储的行为,可理解为对整个操作的提交动作

在模拟鼠标操作前,需要引入 ActionChains 的类:

1
from selenium.webdriver.common.action_chains import ActionChains

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

browser = webdriver.Chrome()
browser.maximize_window()
browser.get("https://www.baidu.com")

right_click_element = browser.find_element(By.LINK_TEXT, "新闻")
# 模拟鼠标右键
ActionChains(browser).context_click(right_click_element).perform()
time.sleep(2)

# 模拟鼠标双击
ActionChains(browser).double_click(right_click_element).perform()
time.sleep(2)

# 模拟鼠标悬停
above = browser.find_element(By.LINK_TEXT, "更多")
ActionChains(browser).move_to_element(above).perform()
browser.find_element(By.LINK_TEXT, "百科").click()
time.sleep(2)

# 模拟鼠标拖放 - 将 source 元素拖动到 target 元素位置
# source = browser.find_element(By.LINK_TEXT, "新闻")
# target = browser.find_element(By.XPATH, "//*[@id='form']/span[1]/span")
# ActionChains(browser).drag_and_drop(source, target).perform()
# time.sleep(2)

browser.quit()

2.5 多框架切换定位用法

在 Web 应用里经常会出现框架或窗口的应用,有时候定位一个元素,定位器没有问题,但是却一直定位不了,这个时候就要检查这个元素是否在一个 frame 中,switch_to.frame() 是将当前定位的主题切换到了 frame 里。因为 frame 中其实相当于嵌入了另一个页面,webdriver 每次只能在一个页面识别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get(os.path.join(os.path.dirname(os.path.abspath(__file__)), "frame.html"))

# 先跳转到内层页面(默认使用表单 id 或 name 属性)
driver.switch_to.frame("f1")
# 再进行元素定位
driver.find_element(By.ID, "kw").send_keys("selenium")
driver.find_element(By.ID, "su").click()

# 跳到最外层页面
driver.switch_to.default_content()
driver.find_element(By.ID, "youku").click()
time.sleep(2)

driver.quit()

2.6 多窗口切换定位用法

在页面操作过程中有时候点击某个链接会弹出新的窗口,这时就需要主机切换到新打开的窗口上进行操作。WebDriver 提供了 switch_to.window() 方法,可以实现在不同的窗口之间切换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.maximize_window()
driver.get("http://www.baidu.com")

# 获取当前百度首页的句柄
baidu_handle = driver.current_window_handle
print("百度首页的句柄为:", baidu_handle)
time.sleep(2)
driver.find_element(By.LINK_TEXT, "登录").click()
time.sleep(2)
driver.find_element(By.LINK_TEXT, "立即注册").click()
time.sleep(2)

# 获取当前所有打开窗口的句柄
all_handles = driver.window_handles
print("所有打开窗口的句柄为:", all_handles)

for handle in all_handles:
if handle != baidu_handle:
driver.switch_to.window(handle) # 跳转到注册窗口
driver.find_element(By.ID, "TANGRAM__PSP_4__userName").send_keys("jack")
driver.find_element(By.ID, "TANGRAM__PSP_4__phone").send_keys("12345678901")
driver.find_element(By.ID, "TANGRAM__PSP_4__password").send_keys("123456jack")
time.sleep(2)

for handle in all_handles:
if handle == baidu_handle:
driver.switch_to.window(handle) # 跳转到百度首页
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()

2.7 其它一些高级用法

Selenium 还有一些其它常见的用法,比如调用 JS、截图保存图片等等。

2.7.1 截图

下面来看一个在百度搜索内容后,保存截图的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
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.save_screenshot("screenshot1.png")
driver.get_screenshot_as_file("screenshot2.png")

driver.quit()

2.7.2 调用 JS

但是有时候我们拿到一个截图后,想通过对截图中的一些内容进行标亮从而传达一些信息,那么就可以通过调用 JS 脚本来达到这个目的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
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)

# 将夜面滚动条拖到底部
js = "var q=document.documentElement.scrollTop=10000"
driver.execute_script(js)
time.sleep(2)

# 将滚动条移动到页面的顶部
js = "var q=document.documentElement.scrollTop=0"
driver.execute_script(js)
time.sleep(2)

# 给搜索输入框标红 javascript 脚本
js = "var ele=document.getElementById(\"kw\");ele.style.border=\"2px solid red\""
# 调用给搜索输入框标红 js 脚本
driver.execute_script(js)
time.sleep(2)

# 截图保存常用的两种方法
driver.save_screenshot("screenshot1.png")
driver.get_screenshot_as_file("screenshot2.png")

driver.quit()