WD.py是一个Python WebDriver客户端,实现了WebDriver协议中的大部分API。 它最初是为Macaca(一个Node.js驱动的WebDriver服务器)而设计的,但也可以应用于WebDriver服务器的其他实现,比如Selenium,Appium等。
查找元素
WebDriver的查找元素命令允许分别查找单个元素和元素集合,定位策略如下:
- 文本
- id
- XPath
- 链接文本
- 部分链接文本
- 标签名
- 类名
- CSS选择器
找到元素的基本方法是element()
,例如查找id为“login”的元素:
driver.element('id', 'login')
但是在大多数情况下,不需要使用这个基本的方法,为了方便起见,有很多扩展方法。
文本
例如,查找页面上name属性为“Login failed!”的元素:
driver.element_by_name('Login failed!')
id
例如,查找id为“login”的元素:
driver.element_by_id('login')
XPath
XPath是XML Path的简称,由于HTML文档本身就是一个标准的XML页面,所以可以使用XPath的语法来定位页面元素。这个方法是非常强大的元素查找方式,使用这种方法几乎可以定位到页面上的任意元素。
例如,查找页面上id为“finding-elements-to-interact”的元素下的第4个table元素:
driver.element_by_xpath('//*[@id="finding-elements-to-interact"]/table[4]')
链接文本
这个方法比较直接,即通过超文本链接上的文字信息来定位元素,这种方式一般专门用于定位页面上的超文本链接。
例如,查找页面上文字为“macaca”的超文本链接:
driver.element_by_link_text('macaca')
部分链接文本
这个方法是上一个方法的扩展,当不能准确知道超链接上的文本信息或者只想通过一些关键字进行匹配时,可以使用这个方法来通过部分链接文字进行匹配。
例如,查找页面上部分文字为“maca”的超文本链接:
driver.element_by_partial_link_text('maca')
标签名
该方法可以通过元素的标签名称来查找元素,需要注意的是,这个方法搜索到的元素通常不止一个。
例如,查找页面上的“ input”标签:
driver.element_by_tag_name('input')
此外,WebDriver上的所有元素方法都可以在WebElement上使用,也就是从当前Web元素中查找元素:
web_element.element_by_id('ss')
类名
一般程序员或页面设计师会给元素直接赋予一个样式属性或者利用css文件里的伪类来定义元素样式,这个方法可以利用元素的css样式表所引用的伪类名称来进行元素查找。
例如,查找页面上className属性为“btn”的元素:
driver.element_by_class_name('btn')
CSS选择器
这种元素定位方式跟XPath比较类似,但执行速度较快,所以功能也是蛮强大的。
例如,查找页面上样式表为“.btn”的元素:
driver.element_by_css_selector('.btn')
异常处理
当没有找到元素时,会引发WebDriverException
异常。为了避免这种情况,可是使用element_if_exists
方法,如果元素存在,则返回True,否则返回False,例如:
driver.element_by_id_if_exists('login')
也可以使用element_or_none
方法,如果元素存在,则返回元素,否则返回None,例如:
driver.element_by_id_or_none('login')
此外,还有wait_for
方法等待元素满足给定条件,默认等待10秒,每个间隔1秒,断言器函数默认为asserters.is_displayed
,例如:
driver.wait_for_element_by_id('login')
按键输入
当需要完成一个输入字段的操作时,可以将一系列的按键行为发送给一个元素:
driver.web_element.send_keys('123456')
send_keys
方法也接受一个数组,这在发送特殊键(不是文本的按键)时非常有用:
driver.web_element.send_keys([1, 2, 3, 4, 5, 6])
PC按键映射:
映射 | 按键 | 键码 |
---|---|---|
\uE002 | HELP | 259 (0x00000103) |
\uE003 | BACK_SPACE | 67 (0x00000043) |
\uE004 | TAB | 61 (0x0000003d) |
\uE005 | CLEAR | 28 (0x0000001c) |
\uE007 | ENTER | 66 (0x00000042) |
\uE008 | SHIFT | 59 (0x0000003b) |
\uE009 | CONTROL | 113 (0x00000071) |
\uE00A | ALT | 57 (0x00000039) |
\uE00B | PAUSE | 121 (0x00000079) |
\uE00C | ESCAPE | 111 (0x0000006f) |
\uE00E | PAGE_UP | 92 (0x0000005c) |
\uE00F | PAGE_DOWN | 93 (0x0000005d) |
\uE010 | END | 123 (0x0000007b) |
\uE011 | HOME | 122 (0x0000007a) |
\uE012 | ARROW_LEFT | 21 (0x00000015) |
\uE013 | ARROW_UP | 19 (0x00000013) |
\uE014 | ARROW_RIGHT | 22 (0x00000016) |
\uE015 | ARROW_DOWN | 20 (0x00000014) |
\uE016 | INSERT | 124 (0x0000007c) |
\uE017 | DELETE | 112 (0x00000070) |
\uE031 | F1 | 131 (0x00000083) |
\uE032 | F2 | 132 (0x00000084) |
\uE033 | F3 | 133 (0x00000085) |
\uE034 | F4 | 134 (0x00000086) |
\uE035 | F5 | 135 (0x00000087) |
\uE036 | F6 | 136 (0x00000088) |
\uE037 | F7 | 137 (0x00000089) |
\uE038 | F8 | 138 (0x0000008a) |
\uE039 | F9 | 139 (0x0000008b) |
\uE03A | F10 | 140 (0x0000008c) |
\uE03B | F11 | 141 (0x0000008d) |
\uE03C | F12 | 142 (0x0000008e) |
\uE03D | META | 117 (0x00000075) |
Android按键映射:
映射 | 按键 | 键码 |
---|---|---|
\uE101 | POWER 电源键 | 26 (0x0000001a) |
\uE102 | VOLUME_UP 音量加 | 24 (0x00000018) |
\uE103 | VOLUME_DOWN 音量减 | 25 (0x00000019) |
\uE104 | VOLUME_MUTE 禁音 | 164 (0x000000a4) |
\uE105 | HOME_SCREEN HOME键 | 3 (0x00000003) |
\uE106 | BACK BACK键 | 4 (0x00000004) |
\uE107 | MENU MENU键 | 82 (0x00000052) |
\uE108 | CAMERA 拍照键 | 27 (0x0000001b) |
\uE109 | CALL 电话键 | 5 (0x00000005) |
\uE10A | END_CALL 结束电话键 | 6 (0x00000006) |
\uE10B | SEARCH 搜索键 | 84 (0x00000054) |
\uE10C | DPAD_LEFT 导航左键 | 21 (0x00000015) |
\uE10D | DPAD_UP 导航上键 | 19 (0x00000013) |
\uE10E | DPAD_RIGHT 导航右键 | 22 (0x00000016) |
\uE10F | DPAD_DOWN 导航下键 | 20 (0x00000014) |
\uE110 | DPAD_CENTER 导航确定键 | 23 (0x00000017) |
iOS按键映射:
映射 | 按键 |
---|---|
\uE105 | HOME_SCREEN HOME键 |
使用数组发送特殊键非常方便:
driver.web_element.send_keys([1, DELETE, 1, 2, 3, 4, 5, 6])
屏幕快照
截图时可以返回截图的base64
编码字符串:
base64_str = driver.take_screenshot()
或者保存截图到给定的路径:
driver.save_screenshot('./screen.png')
save_screenshot
方法具有可选的第二个参数来决定是否由于某种原因无法保存到文件系统时忽略IOError
。例如,没有读写权限时,忽略异常信息:
driver.save_screenshot('/etc/screen.png', True)
切换环境
对于移动端测试,可能需要在Native(原生)和Webview(H5)之间切换环境,首先获取现有的环境:
ctxs = driver.contexts
print(ctxs) # ['NATIVE', 'WEBVIEW_1', 'WEBVIEW_2']
然后切换到指定的环境:
driver.context = 'WEBVIEW_1'
print(driver.context) # WEBVIEW_1
执行JS片段
在一些复杂的情况下,可能需要在页面中插入一段JavaScript代码,并得到想要的任何东西。可以在脚本中使用arguments
来表示脚本之后的索引参数。
script = 'return document.querySelector(".btn").tagName === arguments[0]'
args = ['div']
result = driver.execute_script(script, *args)
上面的脚本等于JavaScript中的IIFE:
function () {
return document.querySelector(".btn").tagName === "div"
}()
WebElement方法
WebElement的实例方法主要与行为元素有关,比如点击元素、获取标签名或元素的内部文本。WebElement实例是通过查找元素命令返回的,例如通过id检索元素:
web_element = driver.element_by_id('login')
print(type(web_element) == WebElement) # True
例如点击元素:
web_element.click()
例如获取元素的标签名称:
tag_name = web_element.tag_name
例如获取元素的内部文本:
text = web_element.text
编码风格
建议使用官方推荐的两种编码风格,第一种是使用额外的括号:
(
driver
.get('https://www.google.com')
.element_by_id('login')
.click()
)
第二种是使用反斜杠:
driver \
.get('https://www.google.com') \
.element_by_id('login') \
.click()