用于web应用程序的测试工具
模拟手工操作浏览器,进行自动化测试
特点
- 开源免费
- 多浏览器支持 —Chrome、IE、FireFox等
- 多平台支持 — Windows、Linux都支持
- 支持分布式测试(Grid)
- 支持录制回放和脚本生成(IDE)
Selenium三剑客
- WebDriver
- IDE 支持录制回放和脚本生成
- Grid 支持分布式测试
官方文档
- https://selenium-python.readthedocs.io/index.html
- https://seleniumhq.github.io/selenium/docs/api/py/api.html
webdriver工作原理
通过浏览器的driver与浏览器进行通信.(传令兵,把我们的指令通过webdriver传递给浏览器,同时把浏览器的返回结果进行定位、操作、获取属性信息等)
配置环境
pip install selenium
下载webdriver(与浏览器的种类和版本匹配)
Chrome:http://chromedriver.storage.googleapis.com/index.html
Firefox:https://github.com/mozilla/geckodriver/releases/
下载好后解压
1.放置到python的安装目录
2.放置在项目中的专门目录
进入网址,进入到网站后显示5秒钟,5秒之后关闭浏览器
# 想操作浏览器导入webdriver的包就可以,不用导入selenium中所有的包
from selenium import webdriver
from time import sleep
# 初始化一个driver(要加括号)
driver = webdriver.Chrome()
# 访问乐博商城的网址
driver.get("http://shop.pro.17lebo.com")
#这时我就可以控制浏览器了,能控制浏览器就可以操纵要测试的软件了
#……
# 沉睡5秒钟
sleep(5)
# 退出当前标签页
# driver.close()
# 退出整个浏览器 不关闭浏览器,浏览器会越来越多
driver.quit()
webdriver的功能
- 能访问浏览器
- 能设置浏览器的窗口大小 无界面时也有效
# 最大化 driver.maximize_window() # 最小化 driver.minimize_window() # 设置窗口大小 driver.set_window_size(800, 600)
- 控制前进、后退
from selenium import webdriver
from time import sleep
# 初始化一个driver(要加括号)
driver = webdriver.Chrome()
# 访问乐博商城的网址
driver.get("http://shop.pro.17lebo.com")
# 设置浏览器的大小
# 最大化
driver.maximize_window()
# 控制前进。后退
# 打开乐博官网
driver.get("http://www.17lebo.com")
sleep(3)
# 后退 去上一个页面
driver.back()
sleep(3)
# 前进 去下一个页面
driver.forward()
sleep(3)
- 截图
# 浏览器截图
driver.get_screenshot_as_file("浏览器截图3.png")
- 刷新页面
# 刷新页面 driver.refresh()
- 关闭浏览器
driver.quit()
- 关闭当前页面
driver,close()
- 获取页面属性
浏览器的无界面操作
每次运行的时候都会出现浏览器,有的时候不想让浏览器出现,就用到无界面操作
无界面模式下默认不是全屏,默认大小是800*600
# 浏览器的无界面操作 # 用来保存各种webdriver的配置项 opt = webdriver.ChromeOptions() opt.headless = True # 初始化一个driver(要加括号) driver = webdriver.Chrome(options=opt)Selenium定位页面元素
UI自动化测试,从定位页面元素开始
8大定位方法
- id
- name
- class name:class的名
- tag name:标签名
- link text:链接的文字内容
- partial link text:这个link text包含的一部分内容
- xpath
- css selector
find_element()和find_elements()
name定位
item = driver.find_element_by_name("wd")
item.send_keys("手机")
可以看到是定位成功并且已经输入我想要搜索的内容了
但是提示了最好不要使用find_element_by_*,selenium4.0以后就无法使用了
所以用find_element()代替
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
# 访问乐博商城的网址
driver.get("http://shop.pro.17lebo.com")
item = driver.find_element(By.NAME, "wd")
item.send_keys("手机")
By.name实际就是传的name,同理,By.id就是传的id
所以可以直接传name
item = driver.find_element("name", "wd")
item.send_keys("手机")
id定位
item = driver.find_element("id", "search-input")
item.send_keys("手机")
class定位
我想定位百宝箱,然后点击
item = driver.find_element("class name", "navigation-main-quick")
item.click()
点击百宝箱后底部弹框,说明点击成功
tag name定位
多少有点不靠谱,因为重名的太多了
标签名定位,需要确认这个页面只有一个这个标签,才用标签定位,否则定位出来的就不止一个了
item = driver.find_element("tag name", "input")
item.send_keys("手机")
如果当前页面有多个同样的标签,就要用find_elements(),这时,返回的就是一个列表了,如果要引用其中的一个元素,就要加索引
比如:
item = driver.find_elements("tag name", "input")
item[1].send_keys("手机")
link text定位
link是通过链接的文字定位,点一下会跳转到另外的页面
item = driver.find_element("link text", "登录")
item.click()
partial link text定位
和link text差不多,只是这个是通过链接的文字内容的一部分进行定位,而不是全部内容
还是点击登录跳转,我只要链接中的“录”字就可以定位到了
item = driver.find_element("partial link text", "录")
item.click()
id、 name、 class name、tag name、 link text、partial link text这些定位方法都是理想的情况下,能通过这些定位,都是有要求的,有局限性。如果标签中没有这些属性,就没法通过这些来定位了。
xpath和css selector定位是万能定位,功能强大,css selector比xpath的速度快
xpath定位
xpath就是XML path language
专门在xml文档中对元素和属性进行遍历
xpath是可以拷贝的
相对定位://*[@id=“search-input”]
绝对定位(严重不推荐):/html/body/div[3]/div/div[3]/form/div/input
xpath的语法结构:xpath = //tagname[@Attribute = ‘value’]
- 斜线/双斜线 查找范围或查找方式
/表示绝对定位
//表示相对定位 - tagname 标签名称
*代表所有标签
具体的标签名称:h、p、input、div、button、a…
当标签名不足以唯一的选择出来时,后面可以加条件[ ] - [ ]选择条件
@Attribute 用属性进行选择 id、name、class…
用函数选择
属性+函数
只用标签名后面不跟选择条件
# xpath的选择条件只用标签名定位
items = driver.find_elements("xpath", "//p")
for i in items:
print(i.text)
xpath的选择条件只用标签名定位的执行结果,只用标签名一般都会定位到很多东西
选择条件用id
# 选择条件用id
item = driver.find_element("xpath", "//input[@id='search-input']")
item.send_keys("找到一个//input[@id=search-input]")
选择条件用name
# 选择条件用name
item = driver.find_element("xpath", "//input[@name='wd']")
item.send_keys("找到xpath为//input[@name='wd']的元素")
选择条件用class+层级关系
# 选择条件用class
# 这个元素的class不是唯一的,所以可以用层级关系来辅助定位
# 因为要定位的是一个input 而input的class不是唯一的,所以找到input上一级的class,input上一级是一个div,把这个div写出来,然后后面再加一个input
# 这个class在整个页面中不是唯一的,但是在这个div中是唯一的
item = driver.find_element("xpath", "//div[@class='search-group']/input")
item.send_keys("找到xpath为//div[@class='search-group']/input的元素")
text() 函数
用属性前面有@符,用函数前面没有@符
# text属性
# 先找到输入框元素
item = driver.find_element("xpath", "//div[@class='search-group']/input")
# 在输入框中输入手机
item.send_keys("手机")
# 找到搜索按钮(已经精确到文字内容了,所以前面标签名可以用通配符*)
search = driver.find_element("xpath", "//*[text()='搜索']")
# 点击搜索
search.click()
这时已经进到手机页了
使用索引
没有办法唯一定位的时候可以使用索引
item = driver.find_element("xpath", "//div[@class='search-group']/input")
item.send_keys("手机")
item = driver.find_elements("xpath", "//button")
item[0].click()
多条件组合
当中括号中一个条件已经不足以确定元素的时候,就可以输入多个条件
# 多条件组合
item = driver.find_element("xpath", "//input[@type = 'text' and @placeholder = '其实搜索很简单^_^ !']")
item.send_keys("电脑")
常用函数
contains() 包含XXX
# 常用函数之包含XXX——contains()
item = driver.find_element("xpath", "//input[contains(@placeholder,'^_^')]")
item.send_keys("电脑")
starts-with() 以XXX开头
# 以XXX开头——starts-with()
item = driver.find_element("xpath", "//input[starts-with(@placeholder,'其实')]")
item.send_keys("电脑")
……
轴 (相对查找. 找 父节点,祖父节点)
语法:
轴名称::节点测试[谓语]
| 轴名称 | 结果 |
|---|---|
| ancestor | 选取当前节点的所有先辈(父、祖父等)。 |
| ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
| attribute | 选取当前节点的所有属性。 |
| child | 选取当前节点的所有子元素。 |
| descendant | 选取当前节点的所有后代元素(子、孙等)。 |
| descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
| following | 选取文档中当前节点的结束标签之后的所有节点。 |
| namespace | 选取当前节点的所有命名空间节点。 |
| parent | 选取当前节点的父节点。 |
| preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
| preceding-sibling | 选取当前节点之前的所有同级节点。 |
| self | 选取当前节点。 |
| … |
css selector定位
css定位是selenium首推的定位方式,因为css定位的速度快。项目小的时候无所谓,项目大的时候速度快是很重要的。
几乎很难发现找到某一个元素没有class没有样式的,所有网页里显示的都系几乎都会有样式,没有样式会特别丑。所以css选择器定位很方便,总会定位出来想要的元素。
css和xpath的比较:
- 速度比xpath快
- 语法简洁
css选择器用id定位
# css selector定位
# 用id定位 #代表id
item = driver.find_element("css selector", "#search-input")
item.send_keys("手机")
用name定位
# 用name定位 input是我要定位元素的标签
item = driver.find_element("css selector", "input[name='wd']")
item.send_keys("手机")
用class name定位
class name定位的一般都会出现一堆,而不是一个,所以要通过索引定位
# class name定位 .代表class
items = driver.find_elements("css selector", ".outer")
items[2].click()
要定位的元素有多个class时
# 多个class
item = driver.find_element("css selector", "[class='am-text-truncate name']")
item.click()
用其他属性定位
# 用其他属性定位 三种都可以
# item = driver.find_element("css selector", "input[placeholder='其实搜索很简单^_^ !']")
# item = driver.find_element("css selector", "*[placeholder='其实搜索很简单^_^ !']")
item = driver.find_element("css selector", "[placeholder='其实搜索很简单^_^ !']")
item.send_keys("手机")
多个属性组合
item = driver.find_element("css selector", "input[placeholder='其实搜索很简单^_^ !'][autocomplete='off']")
item.send_keys("手机")
部分属性定位
包含 *=
# 包含 *=
item = driver.find_element("css selector", "input[placeholder *= '很简']")
item.send_keys("手机")
以XXX开始 ^=
# 以XXX开始 ^=
item = driver.find_element("css selector", "input[placeholder ^= '其实']")
item.send_keys("手机")
以XXX结束 $=
# 以XXX结束 $=
item = driver.find_element("css selector", "input[placeholder $= '!']")
item.send_keys("手机")
层级关系 >
上下一级关系,顶头上司
# 层级关系 > div是父级,input是子级
item = driver.find_element("css selector", "div[class='search-group']>input")
item.send_keys("电脑")
后代关系 用空格
上下多级关系,越级领导
# 后代关系 用空格
item = driver.find_element("css selector", "div[class='am-container'] input")
item.send_keys("电脑")
兄弟选择器
# 兄弟选择器 找到div中class为word的元素,在这个元素里面找到a标签,冒号后面代表要找第几个a标签的元素
# 找第一个
# item = driver.find_element("css selector", "div[class='word']>a:first-child")
# 找第三个
# item = driver.find_element("css selector", "div[class='word']>a:nth-child(3)")
# 找最后一个
item = driver.find_element("css selector", "div[class='word']>a:last-child")
item.click()
层级与class组合
# 层级与class组合
item = driver.find_element("css selector", "div.search-bar>form>div>input")
item.send_keys("电脑")
selenium官方文档 CSS定位
css选择器常用的语法
| 选择器 | 例子 | 例子描述 |
|---|---|---|
| .class | .intro | 选择 class=“intro” 的所有元素。 |
| #id | #firstname | 选择 id=“firstname” 的所有元素。 |
| * | * | 选择所有元素。 |
| element | p | 选择所有 < p > 元素。 |
| element,element | div,p | 选择所有 < div> 元素和所有 < p> 元素。 |
| element element | div p | 选择 < div> 元素内部的所有 < p> 元素。 |
| element>element | div>p | 选择父元素为 < div> 元素的所有 < p> 元素。 |
| element+element | div+p | 选择紧接在 < div> 元素之后的所有 < p> 元素。 |
| [attribute] | [target] | 选择带有 target 属性所有元素。 |
| [attribute=value] | [target=_blank] | 选择 target=“_blank” 的所有元素。 |
| [attribute~=value] | [title~=flower] | 选择 title 属性包含单词 “flower” 的所有元素。 |
| [attribute I= value] | [lang I= en] | 选择 lang 属性值以 “en” 开头的所有元素。 |
| … |
在有些特殊情况就需要定位多个元素,然后挨个去进行操作
还有可能就是实在无法定位到唯一的元素了,找不到条件了,那就只能定位多个元素然后通过索引定位到要用的元素
items = driver.find_elements("class name", "outer")
for item in items:
# 打印出所有的元素
print(item.text)
# 然后就可以根据对应的索引进行定位,然后操作了
items[1].click()
获取页面中元素的属性值
items = driver.find_elements("class name", "outer")
# 获取页面元素的属性值
print(items[2].get_attribute("name"))
print(items[2].get_attribute("type"))
print(items[2].get_attribute("class"))
有的有有的没有,有值的会打印出来,没有的会显示为空
点击:click()
输入:send_keys()
清除:clear()
等等……



