selenium介绍与使用
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4a0774cb764387e91acb55d6f2dcb487.png)
selenium等待
直接等待
解释:强制等待,一段时间后执行
格式:time.sleep(3)
隐式等待
解释:设置等待时间,等待时间内会轮询查找(默认0.5s),没找到就抛出异常
格式:self.driver.implicitly_wait(3)
缺点:针对全局的设置,无法顾及部分时间较长或较短的元素
显示等待
解释:代码中定义等待条件,满足条件才触发执行代码。程序每隔一段时间(默认0.5s)进行条件判断,成立执行,否正继续等待,知道超过设置的最长时间
格式:WebDriverWait配合until()和until_not()方法,根据判断条件进行等待
实例:
class TestTouchAction():
def setup(self):
self.driver = webdriver.Chrome()
self.driver.get('https://www.baidu.com')
self.driver.implicitly_wait(5)#隐式等待
def test_touchaction(self):
time.sleep(1)#强制等待
self.driver.find_element(By.ID,"kw").click()
#自定义函数,用显示等待判断执行
def wait(x):
return len(self.driver.find_element(By.ID,"r")) >= 1
WebDriverWait(self.driver,10).until(wait)
#使用内置函数expected_conditions来判断是否可被点击
WebDriverWait(self.driver, 10).until(expected_conditions.element_to_be_clickable(self.driver.find_element(By.ID, "r")))
self.driver.find_element(By.ID,"su").click
元素定位
xpath定位
表达式 | 结果 |
---|---|
/bookstore/book[1] | 选取bookstore子元素的第一个book元素 |
/bookstore/book[last()] | 选取bookstore子元素的最后一个book元素 |
/bookstore/book[last()-1] | 选取bookstore子元素的倒数第二个book元素 |
/bookstore/book[position()< 3] | 选取最前面的两个属于bookstore元素的子元素的book元素 |
//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 |
表达式 | 结果 |
---|---|
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑他们的位置 |
. | 选取当前节点 |
… | 选取当前节点的父节点 |
@ | 选取属性 |
self.driver.find_element(By.XPATH,"//*[@id='su']")
css样式定位
选择器 | 例子 | 例子描述 |
---|---|---|
.class | .inrot | 选择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"的所有元素 |
:nth-child(n) | p:nth-child(2) | 选择属于其父元素的第二个子元素的每个< p>元素 |
element1~element2 | p~ul | 选择前面有< p>元素的每个< ul>元素 |
元素交互
官方文档:https://selenium-python.readthedocs.io/api.html
ActionChains
执行原理:调用ActionChains方法时,不会立即执行,而是将所有的操作,按顺序放到列表里,当调用perform()方法时,队列中的时间会依次执行,ActionChains针对PC端,无法对H5页面进行操作
基本用法
生成一个动作action = ActionChains(driver)
动作添加方法1 action.方法1
动作添加方法2 action.方法2
调用perform()方法执行 action.perform()
写法:
链式写法
ActionChains(driver).move_to_element(element).click(element).perform()
分布写法
用法:鼠标移动到element元素上
action = ActionChains(driver)
action.move_to_element(element)
action.perform()
用法:将drag_element拖拽到drop_element元素后释放
action = ActionChains(driver)
action.drag_and_drop(drag_elememt,drop_element).perform()
action.click_and_hold(drag_element).release(drop_element).perform()
用法:模拟按键操作,
action = ActionChains(driver)
action.send_key(Keys.BACK_SPACE)
action.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
TouchAction
手势控制
手势 | 解释 |
---|---|
tap | 在指定元素上点击 |
double_tap | 在指定元素上双击 |
tap_and_hold | 在指定元素上点击但不释放 |
move | 手势移动指定偏移(未释放) |
release | 释放手势 |
scroll | 手势点击并滚动 |
scroll_from_element | 从某元素位置开始手势点击并滚动(向下负数,向上正) |
long_press | 长按元素 |
flick | 收拾滑动 |
flick_element | 从某元素位置开始收拾滑动(向上负数,向下正) |
Perform | 执行 |
action = TouchActions(self.driver)
action.tap(el_search)
action.scroll_from_element(el,0,10000).perform()
表单操作
表单提交前需要先定位元素,才能对元素进行操作
class TestForm():
def setup(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(5)
self.driver.maximize_window()
def teardown(self):
self.driver.quit()
def test_form(self):
self.driver.get("https://testerhome.com/account/sign_in")
self.driver.find_element(By.ID,"user_login").send_keys("username")
self.driver.find_element(By.ID, "user_password").send_keys("password")
self.driver.find_element(By.ID, "user_remember_me").click()
self.driver.find_element(By.CSS_SELECTOR,".btn-block").click()
time.sleep(3)
多窗口和frame处理
多窗口处理
识别窗口:获取唯一标识句柄,通过切换句柄就能多窗口灵活切换
多窗口处理流程:
获取句柄:
先获取到当前窗口句柄
driver.current_window_handle
在获取到所有的窗口句柄
driver.window_handles
判断是否相应草自拍的窗口,如果是就操作,不是就切换窗口
driver.switch_to_window
print(self.driver.current_window_handle)#打印当前窗口
windows = self.driver.window_handles#手机所有窗口
self.driver.switch_to.windws(windows[0])#切换窗口
frame处理
介绍:
frame是html中的框架,可以在同一个浏览器中显示不止一个页面
给予html,又分为垂直框架和水平框架(cols,rows)
分类:
- frame标签包含frameset、frame、iframe
- frameset和普通标签一样,不影响正常定位
- frame和iframe对selenium定位而言是一样的
多frame切换
frame存在两种:嵌套的和未嵌套的
切换frame
- driver.switch_to.frame()#根据元素id或者index切换frame
- driver.switch_to.default_content()#切换到默认frame
- driver.switch_to.parent_frame()#切换到父级frame
处理未嵌套的iframe
- driver.switch_to_frame(“frame的id”)
- driver.switch_to_frame(“frame-index”) frame无id的时候一句索引来处理,索引从0开始driver.switch_to_frame(0)
处理嵌套的iframe
- 对于嵌套的先进入到iframe的父节点,在进入到子节点,最后再对子节点里的对象进行处理和操作
- driver.switch_to.frame(“父节点”)
- driver.switch_to.frame(“子节点”)
多浏览器处理
class Base():
def setup(self):
browser = os.getenv("browser")
if browser == 'firefox':
self.driver = webdriver.Firefox
elif browser == 'headless':
self.driver = webdriver.PhantomJS
elif browser == 'safari':
self.driver = webdriver.Safari
else:
self.driver = webdriver.Chrome()
执行js脚本
js操作
页面滑动操作
document.documentElement.scrollTop=1000
在网页里,可以模拟窗口操作
window.alert("hello")
获取性能数据(响应时间等数据)
JSON.stringify(performance.timing)
selenium调用js
execute_script:执行js
return:可以返回js的返回结果
execute_script:arguments传参
#定位
self.driver.execute_srcipt("return document.getElementById("su")")
#滑动页面
self.driver.execute_srcipt("return document.documentElement.scrollTop=1000")
#打印性能数据
for code in [
'return document.title','return document.documentElement.scrollTop=1000")'
]:
print(self.driver.execute_script(code))
js时间控件操作
网页上的时间空间大部分时readonly,可以删掉readonly重新赋值来更改时间
#定位到了元素"train_date"并赋值到对象a,同时找到当前的时间readonly清除
time_element = self.driver.execute_script("a=document.getElementById('train_date');a.removeAttribute('readonly')")
#元素"train_date"已被清除,重新赋予时间为"2020-12-30"
self.driver.execute_script("document.getElementById('train_date').value='2020-12-30'")
文件上传、弹窗处理
文件上传
input标签可以直接使用send_key(文件地址)上传文件
self.driver.find_element(By.ID,"kw").send_key("C:/Desktop/a.jpg")
弹窗处理
需要先分辨是alert、window、div模态框
alert处理
#切换到alert弹窗,点击确认
self.driver.switch_to.alert.accept()
#确认后需要切换回默认的控件页面上
self.driver.switch_to.default_content()
PageObject设计原则
- 只为页面中重要的元素创建page类
- 不要暴露细节
- 不要把断言和操作细节混用
- 方法可以return到新打开的页面
- 不要把整页的内容都放到PO中
- 相同的行为会产生不同的结果,可以封装不同结果
复用已有浏览器(调试)
启动命令:
windows:chrome --remote-debugging-port=9222
mac:Google\Chrome --remote-debugging-port=9222
访问http://localhost:9222
def test_option(self):
#实例化option
option = Options()
option.debugger_address = "localhost:9222"
driver = webdriver.Chrome(options=option)
driver.get("https://www.baidu.com")
调试功能可以直接在本地执行,不需要反复调用浏览器
cookie处理
def test_get_cookie(self):
self.driver = webdriver.Chrome()
self.driver.get("https://www.baidu.com")
time.sleep(15)
cookie = self.driver.get_cookie()
#将cookie存储到json文件里,以免反复调用新的cookie
with open("cookie.json","w") as f:
json.dump(cookie,f)
def tset_cookie():
cookies = json.load(open("cookie.json"))
for cookie in cookies:
#添加一个dict的cookie信息,把cookie键值对塞入浏览器中
self.driver.add_cookie()
time.sleep(5)
self.driver.refresh()#刷新页面