web自动化-Selenium(一)
Selenium简介
Webdriver概述
Webdriver(Selenium2)是一种用于Web 应用程序的自动化测试工具,它提供了一套友好的API,与Selenium1(Selenium-RC)相比,Webdriver 的API更容易理解和使用,其可读性和可维护性也大大提高。Webdriver 完全就是一套类库,不依赖于任何测试框架,除了必要的浏览器驱动,不需要启动其他进程或安装其他程序,也不必像Selenium1 那样需要先启动服务。
支持浏览器
Firefox、IE、Microsoft Edge、Chrome、safari
支持语言
Java、C#、PHP、Python、Perl、Ruby
前世
Selenium RC
早期的Selenium使用的是JavaScript注入技术与浏览器打交道,需要Selenium RC启动一个Server,将操作Web元素的API调用转化为一段段Javascript,在Selenium内核启动浏览器之后注入这段Javascript。开发过Web应用的人都知道,Javascript可以获取并调用页面的任何元素,自如的进行操作。由此才实现了Selenium的目的:自动化Web操作。这种Javascript注入技术的缺点是速度不理想,而且稳定性大大依赖于Selenium内核对API翻译成的Javascript质量高低。
今生
WebDriver
当Selenium2.x 提出了WebDriver的概念之后,它提供了完全另外的一种方式与浏览器交互是。利用浏览器原生的API,封装成一套更加面向对象的Selenium WebDriver API,直接操作浏览器页面里的元素,甚至操作浏览器本身(截屏,窗口大小,启动,关闭,安装插件,配置证书之类)。由于使用的是浏览器原生的API,速度大大提高,而且调用的稳定性交给了浏览器厂商本身,显然是更加科学。然而带来的一些副作用就是,不同的浏览器厂商,对Web元素的操作和呈现多少会有一些差异,这就直接导致了Selenium WebDriver要分浏览器厂商不同,而提供不同的实现。例如Firefox就有专门的FirefoxDriver,Chrome就有专门的ChromeDriver等等。(甚至包括了AndroidDriver和iOS WebDriver)
Selenium3.0发布后,最大更新点就是干掉了对selenium rc的支持,这标志着webdriver协议最终一统江湖,rc毕竟是继子,webdriver才是亲儿子,假儿子给真儿子让路,豪门继承权尘埃落定。
selenium3.0的意味着什么
webdriver 协议现在已经成为业内公认的浏览器UI测试的标准实现。简而言之,做浏览器ui测试,请认准selenium webdriver商标。各种官方支持意味着以后的浏览器UI测试的速度和稳定性会有较大的提升。selenium 2.0时代只有chrome driver是官方出品,其它实现均是第三方。从稳定性上说,2.0时代最稳定的测试浏览器是chrome和firefox,其它浏览器支持均或多或少有些问题。浏览器UI自动化测试已经成为了行业标配。这也是为什么几乎所有浏览器厂商都推出自己官方driver的原因。
RemoteWebDriver(selenium的WebDriver的基类)
启动目标浏览器,并绑定到指定端口。该启动的浏览器实例,做为web driver的remote server,Remote server 需要依赖原生的浏览器组件(如:IEDriver.dll,chromedriver.exe),来转化浏览器的api调用,一些定位元素的api都在该类中。
WebDriver
webdriver是按照server – client的经典设计模式设计的。
webdriver的作用就是创建一个新的浏览器实例,也就是启动一个Server端。
(Starts the service and then creates new instance of chrome driver)
server端就是我们的Remote server,也就是我们通过各个不同浏览器所启动的浏览器实例,在我们脚本启动浏览器后,这个浏览器就可以称之为我们的Remote server,它的职责就是等待client发送请求并做出相应处理。
client 就是我们的测试代码,我们测试代码中的所有操作,比如打开浏览器,寻找元素,点击都是以http请求的方式发送给被测试浏览器,也就是我们的Remote server,remote server接受请求,并执行相应操作,并在response中返回执行状态、返回值等信息(这里调用的接口是浏览器的源生API,而每一个浏览器都有自己的一套接口信息,这也就是为什么我们要安装不同的驱动的原因)
WebDriver工作流程
-
通过WebDriver创建一个浏览器服务,remote server。
-
脚本启动时会在新的线程中启动一个浏览器,并绑定特定的端口,没个浏览器有不同的端口段。
-
client 创建1个session,在该session中通过http请求向remote server发送restful的请求,remote server解析请求,完成相应操作并返回response。
-
分析response,继续执行脚本还是结束执行
command.py
Command类中定义了WebDriver的一些常用的常量。
remote\webdrvier.py
所有浏览器webdrvier的基类,其中包含了所有webdriver的api接口
remote\remote_connection.py
包含启动Remote WebDrvier server,执行client请求,self._commands是selenium的核心请求参数,根据对应的Command常量,发送不同的http请求。
Page Object Model(POM)的优势
- POM提供了一种在UI层操作、业务流程与验证分离的模式,这使得测试代码变得更加清晰和高可读性
- 对象库与用例分离,使得我们更好的复用对象,甚至能与不同的工具进行深度结合应用
- 可复用的页面方法代码会变得更加优化
- 更加有效的命名方式使得我们更加清晰的知道方法所操作的UI元素。例如我们要回到首页,方法名命名为: gotoHomePage(),通过方法名即可清晰的知道具体的功能实现。
元素定位方法
xpath使用方法
什么是Xpath
xpath是XML路径语言,是一种查询语言,使用路径表达式浏览XML文档中的元素和属性。XPath标准语法如下:
xpath=//tagname[@attribute='value']
- // : 选择当前节点
- Tagname: 节点标签名
- @: 选择属性
- Attribute: 节点属性名
- Value: 属性值
xpath有绝对定位和相对定位两种,绝对定位使用绝对路径,缺点是路径太长,只要一个节点变动就无法定位。
xpath支持id、class、name定位元素
# 通过ID定位
//*[@id='kw']
# 通过Class定位
//*[@class='class_name']
#通过Name定位
//*[@name='name']
xpath支持属性定位功能
# @ 代表以属性定位,后面可以接标签中任意属性
//*[@other='attribute']
当标签的属性重复时,xpath提供了通过标签来进行过滤
# 将 * 换位任意标签名,则可根据标签进行筛选
//input[@placeholder='用户名']
当标签重复时,xpath提供了层级过滤
例如:找不到儿子,那么就先找爸爸,实在不行可以先找爷爷
# 支持通过 / 进行层级递进,找到符合层级关系的标签
//form/div/input[@placeholder="用户名"]
# 当层级都重复时,可以通过单个层级的属性进行定位
//form/div[@class='login-user']/input
xpath提供了索引过滤
一个元素它的兄弟元素跟它的标签一样,这时候无法通过层级定位到。因为都是一个父亲生的,多胞胎兄弟。xpath提供了索引过滤
# 通过索引,在List中定位属性,与python的索引有些差别,Xpath从1开始
//select[@name='city'][1]/option[1]
# 通过多个层级的属性来定位
//div[@class='driver'][1]/div[@class='inner'][1]
逻辑运算定位
上面如果都用上还重复的话,我们就可以使用xpath提供的终极神器,逻辑运算定位。and或or
# 通过and来缩小过滤的范围,只有条件都符合时才能定位到
//select[@name='city' and @size='4' and @multiple="multiple"]
# or就相反了,只要这些筛选中,其中一个出现那么久匹配到了
//select[@name='city' or @size='4']
Contains()定位
# Contains()方法也许通过部分文本来定位查找元素,CSS Selector不支持这种用法。
Xpath = //*[contains(@type,'partial_text')]
Xpath = //*[contains(@name,'partial_text')]
Xpath = //*[contains(@class,'partial_text')]
Xpath = //*[contains(@id,'partial_text')]
Xpath = //*[contains(text(),'partial_text')]
Xpath = //*[contains(@href,'partial_text')]
Starts-with()方法
# 通过开始位置包含文本的定位方式
Xpath = //*[starts-with(@type,'start_text')]
Xpath = //*[starts-with(@name,'start_text')]
Xpath = //*[starts-with(@class,'start_text')]
Xpath = //*[starts-with(@id,'start_text')]
Xpath = //*[starts-with(text(),'start_text')]
Xpath = //*[starts-with(@href,'start_text')]
用text() 定位
# 模糊定位 包含【原始】str的元素
//li[contains(text(),'原始')]
# 定位text文本为【原始数据】的元素
//li[text()="原始数据"]
用parent通过儿子定位父亲
//td[text()='轴的含义说明']/parent::tr
用ancestor通过儿子定位祖先(包括爸爸)
//td[text()='轴的含义说明']/ancestor::table
CSS和xpath区别
CSS Selector和Xpath几乎可以定位到所有Web元素(HTML和XML文档元素,Android应用的层级结构使用xml编写),它们的主要差异包括:
- XPath通过遍历的方式从XML文档中选择节点,CSS Selector是一种匹配模式定位,因此CSS Selector比 XPath 执行效率更高。
- Xpath可以通过文本来定位,而CSS Selector不能;
- Xpath可以通过子节点来定位父节点,CSS Selector是前向的,不能利用子节点定位父节点。
- CSS Selector语法相比Xpath更加简洁
CSS Selector使用方法
什么是CSS selector
CSS selector定位,实际就是HTML的CSS选择器的标签定位
CSS selector支持id、class的定位
CSS selector支持id、class的定位与HTML中CSS定位相同
# 号表id 定位有id的标签方式更加简洁
#i1
# . 代表Class 定位有id的标签方式更加简洁
.c1
# Class定位还提供了多个Class定位 通过连续 . 来缩小范围
.c1.c2.c3
CSS selector支持标签定位没什么卵用
# 与Css相同 支持标签选择器,但并没有什么用,一个页面重复的标签太多
# 定位方式 :直接输入标签名称
CSS selector支持任意属性定位
# 属性定位方式与css相同,直接中括号,加上属性就可以了
[name='n1']
CSS selector子字符串匹配进行定位
[id^='id_prefix_'] # id前缀为‘id_prefix_’的元素
[id$='_id_sufix'] # id后缀为‘_id_sufix’的元素
[id*='id_pattern'] # id包含‘id_pattern’的元素
单单属性定位还不够,CSS selector还提供了标签属性组合定位
# 与css 定位相同 等同于我们标签属性选择器
input[name='n1']
# 当与ID、Class 组合使用时书写方式更为简单
Class
input.c1
ID
input#i1
CSS selector提供了多属性组合过滤
# Css Selector 的多属性组合选择过滤 没有and 只需要多个[] 连接 就可以
select[name='city'][size='4'][multiple="multiple"]
CSS selector也支持层级关系定位
# 与Xpath的不同 Css Selector通过 > 来区分层级的界定
select>option[value='3']
CSS selector 可以用索引来定位
# css也可以通过索引nth-child(1)来定位子元素,直接翻译过来就是第几个小孩
# 总结:选择标签后,找第几个小孩即可
# Select控件第三个Opel
select>select>option:nth-child(3)
# CheckBox第一个Volvo
checkbox>input:nth-child(1)
# CheckBox第二个Saab
checkbox>input:nth-child(4)
# RadioBox第二个Saab
radio>input:nth-child(4)
CSS selector 模糊匹配
# ^= 匹配元素属性以什么开头
input[value^="登"]
# $= 匹配属性以什么结尾
input[value$="录"]
# *= 匹配属性包含什么值 input
[value*="录"]
常用API
浏览器滚动条操作
上下滚动
使用JavaScript操作浏览器的滚动条。
# 拖动滚动条至底部
js1="document.documentElement.scrollTop=10000"
driver.execute_script(js1)
# 拖动滚动条至顶部
js2="document.documentElement.scrollTop=0"
driver.execute_script(js2)
左右拖动
# 左右方向的滚动条可以使用window.scrollTo(左边距,上边距)方法
# example
js="window.scrollTo(200,1000)"
driver.execute_script(js)
窗口最大化
driver.maximize_window() # 窗口最大化
后退、前进、刷新
driver.back() # 向后退
driver.forward() # 向前进
driver.refresh() # 刷新页面
截屏
driver.get_screenshot_as_file(filename)
# 封装方法
def insert_img(driver, filename):
func_path = os.path.dirname(__file__)
# print(func_path)
base_dir = os.path.dirname(func_path)
# print(base_dir)
base_dir = str(base_dir)
base_dir = base_dir.replace('\\', '/') # 转换成反斜杠
# print(base_dir) # 字符串已经转换了
base = base_dir.split('/Website')[0] # 列表读取第一个元素
# print(base)
filepath = base + '/Website/test_report/screenshot/' + filename
driver.get_screenshot_as_file(filepath)
获取元素里属性值
search = self.find_element(*self.search_loc).get_attribute('placeholder')
获取标签内部文案,要用innerText
针对复选框,判断是否勾选上
driver.find_element_by_id('TANGRAM__PSP_10__memberPass').is_selected() # 通常返回布尔值,即True或Failse,来判断
检查元素是否显示(是否可见)
driver.find_element_by_id('TANGRAM__PSP_10__memberPass').is_display() # 用来判断元素是否出现,通常返回布尔值,即True或Failse,来判断
检查元素是否能编辑
driver.find_element_by_id('TANGRAM__PSP_10__memberPass').is_enable() # 用来判断元素(input\select标签等)是否可编辑,通常返回布尔值,即True或Failse,来判断
清空输入框内文本
driver.find_element_by_id('TANGRAM__PSP_10__memberPass').clear() # 用于清除input标签内文本
切换tab窗口
# 1、如果我要当前显示最后一个窗口,封装方法如下:
def switch_window(self):
all_handles = self.driver.window_handles
self.driver.switch_to.window(all_handles[-1])
# 2、如果我要当前显示倒数第二个窗口,封装方法如下:
def switch_window(self):
all_handles = self.driver.window_handles
self.driver.switch_to.window(all_handles[-2])
# 2、如果我要当前显示第一个窗口,封装方法如下:
def switch_window(self):
all_handles = self.driver.window_handles
self.driver.switch_to.window(all_handles[0])
关闭和退出
# 关闭当前窗口
def close_window(self):
self.driver.close()
# 关闭浏览器,退出
self.driver.quit()
切换到框架frame操作
# 1、先切换到‘top-frame’框架
driver.switch_to_frame('top-frame')
# 2、在这个框架下定位input元素进行操作
driver.find_element_by_css_selector('#newtag').send_keys(123)
# 3、紧接着从‘top-frame’框架切换到‘baidu-frame’框架
driver.switch_to_frame('baidu-frame')
# 4、在这个框架下定位input元素进行操作
driver.find_element_by_css_selector('#kw').send_keys(123123)
frame操作,如果里面有嵌套多层frame,那需要一层一层进去,进去后一层一层出来
# 1、从当前框架回到上一层框架
driver.switch_to.parent_frame()
# 2、直接回到默认层框架
driver.switch_to.default_content()
获取当前URL
current_url = self.driver.current_url
print(current_url) # 打印当前url
鼠标悬浮
# 1、先导入模块
from selenium.webdriver import ActionChains
# 2、定位元素
hover_element = driver.find_element_by_css_selector('div.list-top-mld p')
# 对该元素执行悬停操作
ActionChains(driver).move_to_element(hover_element).perform()
# 等待几秒看看效果
time.sleep(3)
或
from selenium.webdriver.common.action_chains import ActionChains
# 先定位元素
element = driver.find_element_by_css_selector('#a')
element2 = driver.find_element_by_css_selector('#dis1')
action = ActionChains(driver)
# 鼠标悬浮在element元素上,点击element2元素
action.move_to_element(element).click(element2).perform()
time.sleep(2)
独立键盘操作
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os
import sys
import win32api
import win32con
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
PathProject = os.path.split(rootPath)[0]
sys.path.append(rootPath)
sys.path.append(PathProject)
import win32api
import win32con
class KeyboardKeys(object):
#模拟键盘按键类
VK_CODE = {'backspace': 0x08,
'tab': 0x09,
'clear': 0x0C,
'enter': 0x0D,
'shift': 0x10,
'ctrl': 0x11,
'alt': 0x12,
'pause': 0x13,
'caps_lock': 0x14,
'esc': 0x1B,
'spacebar': 0x20,
'page_up': 0x21,
'page_down': 0x22,
'end': 0x23,
'home': 0x24,
'left_arrow': 0x25,
'up_arrow': 0x26,
'right_arrow': 0x27,
'down_arrow': 0x28,
'select': 0x29,
'print': 0x2A,
'execute': 0x2B,
'print_screen': 0x2C,
'ins': 0x2D,
'del': 0x2E,
'help': 0x2F,
'0': 0x30,
'1': 0x31,
'2': 0x32,
'3': 0x33,
'4': 0x34,
'5': 0x35,
'6': 0x36,
'7': 0x37,
'8': 0x38,
'9': 0x39,
'a': 0x41,
'b': 0x42,
'c': 0x43,
'd': 0x44,
'e': 0x45,
'f': 0x46,
'g': 0x47,
'h': 0x48,
'i': 0x49,
'j': 0x4A,
'k': 0x4B,
'l': 0x4C,
'm': 0x4D,
'n': 0x4E,
'o': 0x4F,
'p': 0x50,
'q': 0x51,
'r': 0x52,
's': 0x53,
't': 0x54,
'u': 0x55,
'v': 0x56,
'w': 0x57,
'x': 0x58,
'y': 0x59,
'z': 0x5A,
'numpad_0': 0x60,
'numpad_1': 0x61,
'numpad_2': 0x62,
'numpad_3': 0x63,
'numpad_4': 0x64,
'numpad_5': 0x65,
'numpad_6': 0x66,
'numpad_7': 0x67,
'numpad_8': 0x68,
'numpad_9': 0x69,
'multiply_key': 0x6A,
'add_key': 0x6B,
'separator_key': 0x6C,
'subtract_key': 0x6D,
'decimal_key': 0x6E,
'divide_key': 0x6F,
'F1': 0x70,
'F2': 0x71,
'F3': 0x72,
'F4': 0x73,
'F5': 0x74,
'F6': 0x75,
'F7': 0x76,
'F8': 0x77,
'F9': 0x78,
'F10': 0x79,
'F11': 0x7A,
'F12': 0x7B,
'F13': 0x7C,
'F14': 0x7D,
'F15': 0x7E,
'F16': 0x7F,
'F17': 0x80,
'F18': 0x81,
'F19': 0x82,
'F20': 0x83,
'F21': 0x84,
'F22': 0x85,
'F23': 0x86,
'F24': 0x87,
'num_lock': 0x90,
'scroll_lock': 0x91,
'left_shift': 0xA0,
'right_shift ': 0xA1,
'left_control': 0xA2,
'right_control': 0xA3,
'left_menu': 0xA4,
'right_menu': 0xA5,
'browser_back': 0xA6,
'browser_forward': 0xA7,
'browser_refresh': 0xA8,
'browser_stop': 0xA9,
'browser_search': 0xAA,
'browser_favorites': 0xAB,
'browser_start_and_home': 0xAC,
'volume_mute': 0xAD,
'volume_Down': 0xAE,
'volume_up': 0xAF,
'next_track': 0xB0,
'previous_track': 0xB1,
'stop_media': 0xB2,
'play/pause_media': 0xB3,
'start_mail': 0xB4,
'select_media': 0xB5,
'start_application_1': 0xB6,
'start_application_2': 0xB7,
'attn_key': 0xF6,
'crsel_key': 0xF7,
'exsel_key': 0xF8,
'play_key': 0xFA,
'zoom_key': 0xFB,
'clear_key': 0xFE,
'+': 0xBB,
',': 0xBC,
'-': 0xBD,
'.': 0xBE,
'/': 0xBF,
'`': 0xC0,
';': 0xBA,
'[': 0xDB,
'\\': 0xDC,
']': 0xDD,
"'": 0xDE,
'`': 0xC0}
@staticmethod
def keyDown(keyName):
#按下按键
win32api.keybd_event(KeyboardKeys.VK_CODE[keyName],0,0,0)
@staticmethod
def keyUp(keyName):
#释放按键
win32api.keybd_event(KeyboardKeys.VK_CODE[keyName],0,win32con.KEYEVENTF_KEYUP,0)
@staticmethod
def oneKey(key):
#模拟单个按键
KeyboardKeys.keyDown(key)
KeyboardKeys.keyUp(key)
@staticmethod
def twoKeys(key1,key2):
#模拟两个组合键
KeyboardKeys.keyDown(key1)
KeyboardKeys.keyDown(key2)
KeyboardKeys.keyUp(key2)
KeyboardKeys.keyUp(key1)
def type_keyboard(self):
kb = win32key_board.KeyboardKeys()
kb.oneKey("m")
kb.oneKey("h")
kb.oneKey("p")
kb.oneKey("enter")
【鼠标键盘操作】
https://blog.csdn.net/huilan_same/article/details/52305176
等待
UI自动化什么最关键
稳定性
隐式等待
【固定等待】、【隐式等待】
time.sleep() # 只适用于代码调试的时候用
# 1、需要导入模块
from selenium.common.exceptions import NoSuchElementException
# 2、调用implicity_wait()方法
driver.implicitly_wait(2) # 隐式等待
# 隐式等待,设置对多等2s
显示等待
显示等待是针对某一个元素进行相关等待判断
在页面元素定位时,等待元素出现立马执行,提高了代码执行效率
首先导入模块
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
实例化
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Firefox()
e = EC.presence_of_element_located((By.CSS_SELECTOR,'i1'))
element = WebDriverWait(driver,10,0.5).until(e)
element.send_keys(12312)
详解
#coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
base_url = "http://www.baidu.com"
driver = webdriver.Firefox()
driver.implicitly_wait(5)
'''隐式等待和显示等待都存在时,超时时间取二者中较大的'''
locator = (By.ID,'kw')
driver.get(base_url)
WebDriverWait(driver,10).until(EC.title_is(u"百度一下,你就知道"))
'''判断title,返回布尔值'''
WebDriverWait(driver,10).until(EC.title_contains(u"百度一下"))
'''判断title,返回布尔值'''
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'kw')))
'''判断某个元素是否被加到了dom树里,并不代表该元素一定可见,如果定位到就返回WebElement'''
WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.ID,'su')))
'''判断某个元素是否被添加到了dom里并且可见,可见代表元素可显示且宽和高都大于0'''
WebDriverWait(driver,10).until(EC.visibility_of(driver.find_element(by=By.ID,value='kw')))
'''判断元素是否可见,如果可见就返回这个元素'''
WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.CSS_SELECTOR,'.mnav')))
'''判断是否至少有1个元素存在于dom树中,如果定位到就返回列表'''
WebDriverWait(driver,10).until(EC.visibility_of_any_elements_located((By.CSS_SELECTOR,'.mnav')))
'''判断是否至少有一个元素在页面中可见,如果定位到就返回列表'''
WebDriverWait(driver,10).until(EC.text_to_be_present_in_element((By.XPATH,"//*[@id='u1']/a[8]"),u'设置'))
'''判断指定的元素中是否包含了预期的字符串,返回布尔值'''
WebDriverWait(driver,10).until(EC.text_to_be_present_in_element_value((By.CSS_SELECTOR,'#su'),u'百度一下'))
'''判断指定元素的属性值中是否包含了预期的字符串,返回布尔值'''
#WebDriverWait(driver,10).until(EC.frame_to_be_available_and_switch_to_it(locator))
'''判断该frame是否可以switch进去,如果可以的话,返回True并且switch进去,否则返回False'''
#注意这里并没有一个frame可以切换进去
WebDriverWait(driver,10).until(EC.invisibility_of_element_located((By.CSS_SELECTOR,'#swfEveryCookieWrap')))
'''判断某个元素在是否存在于dom或不可见,如果可见返回False,不可见返回这个元素'''
#注意#swfEveryCookieWrap在此页面中是一个隐藏的元素
WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//*[@id='u1']/a[8]"))).click()
'''判断某个元素中是否可见并且是enable的,代表可点击'''
driver.find_element_by_xpath("//*[@id='wrapper']/div[6]/a[1]").click()
#WebDriverWait(driver,10).until(EC.element_to_be_clickable((By.XPATH,"//*[@id='wrapper']/div[6]/a[1]"))).click()
#WebDriverWait(driver,10).until(EC.staleness_of(driver.find_element(By.ID,'su')))
'''等待某个元素从dom树中移除'''
#这里没有找到合适的例子
WebDriverWait(driver,10).until(EC.element_to_be_selected(driver.find_element(By.XPATH,"//*[@id='nr']/option[1]")))
'''判断某个元素是否被选中了,一般用在下拉列表'''
WebDriverWait(driver,10).until(EC.element_selection_state_to_be(driver.find_element(By.XPATH,"//*[@id='nr']/option[1]"),True))
'''判断某个元素的选中状态是否符合预期'''
WebDriverWait(driver,10).until(EC.element_located_selection_state_to_be((By.XPATH,"//*[@id='nr']/option[1]"),True))
'''判断某个元素的选中状态是否符合预期'''
driver.find_element_by_xpath(".//*[@id='gxszButton']/a[1]").click()
instance = WebDriverWait(driver,10).until(EC.alert_is_present())
'''判断页面上是否存在alert,如果有就切换到alert并返回alert的内容'''
print instance.text
instance.accept()
driver.close()