web自动化
元素定位
XPATH选择器
什么是xpath?
XPath即为XML路径语言,它是一种用来(标准通用标记语言的子集)在 HTML\XML 文档中查找信息的语言。
W3School官方文档:http://www.w3school.com.cn/xpath/index.asp
什么是XML?
XML 指可扩展标记语言(EXtensible Markup Language)
XML 是一种标记语言,很类似 HTML
XML 的设计宗旨是传输数据,而非显示数据
节点的概念
每个XML/HTML的标签我们都称之为节点
路径表达式
基本语法
表达式 | 示例 | 描述表达式 |
---|---|---|
nodename | html/body/div | 选取此节点的所有子节点(不推荐) |
/ | /html/head | 从根节点选取 |
// | //input | 相对路径 |
. | //input/. | 选取当前节点 |
.. | //input/.. | 选取当前节点的父节点 |
@ | //*[@type="text"] | 选取属性 |
查找某个特定的节点
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
---|---|
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position()❤️] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang=’eng’] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
/bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]/title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
选择未知节点
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
node() | 匹配任何类型的节点。 |
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
/bookstore/* | 选取 bookstore 元素的所有子元素。 |
//* | 选取文档中的所有元素。 |
//title[@*] | 选取所有带有属性的 title 元素。 |
选取若干路径
路径表达式 | 结果 |
---|---|
//book/title | //book/price | 选取 book 元素的所有 title 和 price 元素。 |
//title | //price | 选取文档中的所有 title 和 price 元素。 |
/bookstore/book/title | //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |
补充
更多操作路径表达式 | 结果 |
---|---|
//*[text()=“xxx”] | 文本内容是xxx的元素 |
//*[starts-with(@attribute,’xxx’)] | 属性以xxx开头的元素 |
//*[contains(@attribute,’xxxxx’)] | 属性中含有xxx的元素 |
//*[@attribute1=value1 and @attribute2=value2] | 同时有两个属性值的元素 |
//*[contains(@class,"myans_check")]/label | |
//*[contains(@class,"right_check")]/label |
XPath的运算符(了解)
CSS选择器
通过id,class等定位元素
通过元素之间的嵌套定位元素
通过元素的属性定位元素
通过父子关系定位元素
通过元素状态定位元素
其他
定位实例
xpath选择器
通过节点名定位(http://www.ifeng.com/)
html 定位到html节点
html/head 定位到head节点
html/head/meta 定位好head中的所有meta节点
相对路径定位节点(http://www.ifeng.com/)
//title 使用相对路径定位到title节点
//meta 使用相对路径定位到所有meta节点
使用.和..定位本身和父节点(http://www.ifeng.com/)
/html/head/title/./.. 使用.定位到title本身再使用..定位到title的父节点
/html/head/title/./../body 使用.定位到title本身再使用..定位到title的父节点,然后在定位到body子节点
通过@定位 格式 标签名[@属性名='属性值']
/meta[@name='author'] 定位到所有的meta,再从中找到name=author的那一个
//div[@id] 定位到所有div标签,再过滤出有id属性的节点
通配符定位节点
//* 匹配所有节点
/* 匹配绝对路径最外层
//*[@*] 匹配所有有属性的节点
/html/node()/meta 匹配所有含有meta的节点
糗事百科练习xpath
//div[@id="content-left"]/div 定位到所有糗事帖子节点
//div[@id="content-left"]/div[1] 通过索引定位到第一个节点
//div[@id="content-left"]/div[last()] 通过last()索引定位到结果中的最后一个
//div[@id="content-left"]/div[last()-n] 通过last()-n索引定位到结果集中的倒数第n+1个
//div[@id="content-left"]/div[position()=n] 定位到结果集中第n个节点
//div[@id="content-left"]/div[position()<n] 定位到结果集中索引小于n的节点
//div[@id="content-left"]/div[position()>n] 定位到结果集中索引大于n的节点
//span[i=n] 定位到好笑计数等于n的节点
//span[i>n] 定位到好笑计数大于n的节点
//meta | //script | //link 使用多个xpath,所有xpath的结果都放到一个结果集中
//*[starts-with(@name,'rend')] 匹配以标签属性值以给定值开头的节点
//*[contains(@name,'end')] 匹配给定值在标签属性中的节点
//*[@content="noarchive" and @name="robots"]匹配同时符合两个属性值的节点
css选择器
.weixinBottom 通过class的值进行定位
#wx 通过id的值进行定位
div 通过标签进行定位
meta,link 匹配两种标签结果集
div a 匹配div标签中的所有后代a标签
div>a 匹配div后是一个a标签的节点
div+div 匹配div后面的同胞div节点
[id] 匹配所有含有id属性的标签
[id='wx'] 匹配所有含有id并且值为wx的标签
[type="submit"]
[class~="Login"] 定位标签属性class值中有独立Login的节点
[name|=msapplication] 定位标签属性name的值以msapplicatio开头的节点(该节点需为一个完整的单词)
[src^="http://"] 匹配scr属性以http://开头的节点
[src$="js"] 匹配src属性以js结尾的节点
[src*="ifengimg"] 匹配src属性中含有ifengimg的节点
img:only-child 匹配所有独生子女的img节点
body>div:nth-child(1) 匹配body的第n个div子节点
body>*:nth-last-child(1) 匹配body的最后一个子节点
:not(link) 查找不是link标签的节点
xpath helper
Selenium
API基础
浏览器驱动对象
1)库的导入
from selenium import webdriver
2)创建浏览器对象
driver = webdriver.xxx()
使用dir(driver)查看方法
3)浏览器尺寸/位置相关操作
maximize_window() 最大化
get_window_size() 获取浏览器尺寸
set_window_size() 设置浏览器尺寸
get_window_position() 获取浏览器位置
set_window_position(x,y) 设置浏览器位置
注:显示器以左上角为(0,0),所有的位置操作都是相对于显示器左上角展开的位移操作,单位是像素。
4)浏览器的关闭操作
close() 关闭当前标签页
quit() 关闭浏览器
页面操作
url的格式:
形式 scheme://host[:port#]/path/…/[?query-string][#anchor]
scheme:协议(例如:http, https, ftp)
host:服务器的IP地址或者域名
port:服务器的端口(如果是走协议默认端口,80 or 443)
path:访问资源的路径
http://www.cnblogs.com/be-saber/p/4734951.html
query-string:参数,发送给http服务器的数据,参数使用&隔开
anchor:锚(跳转到网页的指定锚点位置)
https://detail.tmall.com/item.htm?id=545181862652
协议
HTTP
• 超文本传输协议
• 默认端口号:80
HTTPS
• HTTP + SSL(安全套接字层,)
• 默认端口号:443
DNS域名服务
页面请求操作
driver.get(url) 请求某个url对应的响应
refresh() 刷新页面操作
back() 回退到之前的页面
forward() 前进到之后的页面
断言
获取断言信息的操作
current_url 获取当前访问页面url
title 获取当前浏览器标题
get_screenshot_as_png() 保存图片
get_screenshot_as_file(file) 直接保存
page_source 网页源码
元素定位
定位方式分类
元素操作
1)点击和输入
点击操作
element.click()
清空/输入操作(只能操作可以输入文本的元素)
element.clear() 清空输入框
element.send_keys(data) 输入数据
2)提交操作
element.submit()
3)获取元素信息
获取文本内容(开闭标签之间的内容)
element.text
获取属性值(获取element元素的value属性的值)
element.get_attribute(value)
获取元素尺寸(了解)
element.size
获取元素是否可见(了解)
element.is_dispalyed()
API高级
多标签页切换
1.多标签之间的切换
场景:有的时候点击一个链接,新页面并非由当前页面跳转过去,而是新开一个页面打开,这种情况下,计算机需要识别多标签或窗口的情况。
1)获取所有窗口的句柄
handles = driver.window_handlers()
调用该方法会得到一个列表,在selenium运行过程中的每一个窗口都有一个对应的值存放在里面。
handle = driver.current_window_handle:
该方法可用得到当前所处窗口的句柄
2)通过窗口的句柄进入的窗口
driver.switch_to_window(handles[n])
driver.switch_to.window(handles[n])
示例:
def switch_windows(driver, url):
# 新开一个窗口,通过执行new一个窗口
driver.execute_script("window.open('{}')".format(url))
# 获取当前窗口句柄集合(列表类型)
handles = driver.window_handles
for handle in handles: # 切换窗口(切换到课程页面)
if handle != driver.current_window_handle:
handle_new = handle
driver.close()
driver.switch_to.window(handle_new)
break
多表单切换
2.多表单切换
在网页中,表单嵌套是很常见的情况,尤其是在登录的场景
1)什么是多表单?
实际上就是使用iframe/frame,引用了其他页面的链接,真正的页面数据并没有出现在当前源码中,但是在浏览器中我们看到,简单理解可以使页面中开了一个窗口显示另一个页面
2)处理方法
直接使用id值切换进表单
driver.switch_to.frame(value)/driver.switch_to_frame(value)
定位到表单元素,再切换进入
el = driver.find_element_by_xxx(value)
driver.switch_to.frame(el) /driver.switch_to_frame(el)
跳回最外层的页面
driver.switch_to.default_content()
跳回上层的页面
driver.switch_to.parent_frame()
鼠标和键盘操作
手动测试时键盘的操作在selenium页有实现,关于鼠标的操作由ActionChains()类来提供,关于键盘的操作由Key()类来提供
导入动作链类,动作链可以储存鼠标的动作,并一起执行
from selenium.webdriver import ActionChainsActionChains(driver)
执行ActionChains中储存的所有动作
perform()
鼠标右击
el = driver.find_element_by_xxx(value)
ActionChains(driver).context_click(el).perform()
双击操作
el = driver.find_element_by_xxx(value)
ActionChains(driver).double_click(el).perform()
鼠标悬停
el = driver.find_element_by_xxx(value)
ActionChains(driver).move_to_element(el).perform()
键盘操作
键盘操作使用的是Keys类,一般配合send_keys使用
导入
from selenium.webdriver.common.key import Key
常用键盘操作
send_keys(Keys.BACK_SPACE) 删除键(BackSpace)
send_keys(Keys.SPACE) 空格键(Space)
send_keys(Keys.TAB) 制表键(Tab)
send_keys(Keys.ESCAPE) 回退键(Esc)
send_keys(Keys.ENTER) 回车键(Enter)
send_keys(Keys.CONTROL,‘a’) 全选(Ctrl+A)
send_keys(Keys.CONTROL,‘c’) 复制(Ctrl+C)
send_keys(Keys.CONTROL,‘x’) 剪切(Ctrl+X)
send_keys(Keys.CONTROL,‘v’) 粘贴(Ctrl+V)
send_keys(Keys.F1) 键盘 F1
……
send_keys(Keys.F12) 键盘 F12
弹出框操作
进入到弹出框中
driver.switch_to.alert()
接收警告
accept()
解散警告
dismiss()
发送文本到警告框
send_keys(data)
下拉框操作
selenium关于下拉框的操作都交由Select类进行处理,一般获取到下拉框元素之后使用该类构建对象,调用对象的响应方法就能操作元素
导入Select类
from selenium.webdriver.support.select import Select
将定位到的下拉框元素传入Select类中
selobj = Select(element) 下拉框元素已经定位到
调用响应方法选择下拉框中的选项
select_by_index() 通过索引选择,index 索引从 0 开始
select_by_value() 通过值选择(option标签的一个属性值)
select_by_visible_text() 通过文本选择(下拉框的值)
调用响应方法选择下拉框中的选项
all_selected_options 查看所有已选
first_selected_option 查看第一个已选
is_multiple 查看是否是多选
options 查看选项元素列表
取消选择
deselect_by_index()
deselect_by_value()
deselect_by_visible_text()
调用JS
什么是JS?
JavaScript是世界上最流行的脚本语言,因为你在电脑、手机、平板上浏览的所有的网页,简单地说,JavaScript是一种运行在浏览器中的解释型的编程语言,用来给HTML网页增加动态功能。
JavaScript 是属于网络的脚本语言,被数百万计的网页用来改进设计、验证表单、检测浏览器、创建cookies,以及更多的应用。
为什么要执行js代码?
因为selenium鞭长莫及,没有操作滚动条的方法,而一般操作滚动条都是使用js实现的。
js = "window.scrllTo(x,y)" # x为水平拖动距离,y为垂直拖动举例
js = "var q=document.documentElement.scrollTop=n" # n为从顶部往下移动滚动举例
driver.execute_script(js) # 执行JS代码
举例:
js = "window.scrllTo(0,1000)"
浏览器等待
隐式等待
driver.implicitly_wait(n)
显式等待
WebDriverWait类是由WebDirver 提供的等待方法。在设置时间内,
默认每隔一段时间检测一次当前页面元素是否存在,如果超过设置
时间检测不到则抛出异常。
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None)
固定等待
import sleep from time
sleep(10)
cookies操作
get_cookies() 获取所有cookies
get_cookie(key) 获取key对应的值
add_cookie(cookie_dict) 设置cookies
delete_cookie(name) 删除指定名称的cookie
delete_all_cookies() 删除所有cookie
使用cookie可以实现多账户的免登录,实战可参考这里:selenium中get_cookies()和add_cookie()的用法 - 年轻人——001 - 博客园 (cnblogs.com)
API封装
封装开启关闭浏览器
封装定位操作
封装对元素的基本操作
unittest模块
基本概念
test fixture: 代表了用例执行前的准备工作和用例执行之后的清理工作。
test case: 测试用例,测试的最小单位,一般检查一组输入的响应(输出)是否符合预期。unittest模块提供了TestCase类来帮助我们创建测试用例;
test suite: 经常被翻译成”测试套件”,也有人称为”测试套”,是测试用例或测试套件的集合,一般用来把需要一起执行的用例组合到一起;
test runner: 用来执行测试用例并输出测试结果的组件。可以是图形界面或命令行界面;
基本用法
1.通过继承unittest.TestCase进行编写,继承unittest.TestCase的类会被框架识别为测试用例。
2.setUp和TearDown是用于事前和事后做相关处理动作的,就是前面说的Test Fixture,会在每个测试用例运行前后被框架自动调用
3.所有以test开头的方法会被框架自动识别为测试用例,并自动调用执行,不是以test开头的不会被调用
4.unittest.main()是最简单的测试执行方式
5.调用unittest.main()方法后,继承自unittest.TestCase类的类会被自动识别为测试用例并且被调用。
断言
断言是测试用例的核心,unittest使用assertEqual()来判断预期结果,用assertTrue()和assertFalse()来做是非判断