概念
WEB自动化框架
三大组件:
- selenium IDE 浏览器插件,实现脚本录制
- WebDriver 实现对浏览器的各种操作(API包)
- Grid 实现同时对多个用例进行执行,用例在多个浏览器同步执行
环境搭建
1、安装selenium:
pip install selenium
2、安装浏览器
3、安装浏览器驱动(对应的驱动,版本必须一致)
将其复制在python路径下(selenium默认会寻找@path路径)
注意: 浏览器版本必须和浏览器驱动版本必须一致。
google driver下载地址:goole driver
底层
selenium框架 操作 浏览器驱动 操作 浏览器
1、启动浏览器驱动服务
2、webdriver脚本与浏览器建立连接,在发送请求(JsonWoreProtocol指令包)
其实底层就是将原本复杂的浏览器操作进行了封装,让浏览器操作更加简单
即客户端为脚本,服务器为浏览器驱动
浏览器常见操作
操作 | 代码 |
---|---|
最大化 | driver.maximize_window() |
最小化 | driver.minimize_window() |
指定窗口大小 | driver.set_window_size(2000, 800) |
前进 | driver.forward() |
后退 | driver.back() |
获取网页标题 | driver.tit |
获取网页url | driver.current_ur |
获取网页信息 | driver.page_source |
截图 | driver.get_screenshot_as_file(‘路径’) |
关闭当前窗口 | dirver.close() |
关闭当前浏览器 | dirver.quit() |
三种等待方式
-
自接等待:
time.sleep(5) -
隐视等待:
drive.implicitly_wait(5) # 在轮询时间内等待到了就执行,全局变量 -
显示等待:
WebDriverWait(driver, 10, 0.6).until()
参数:1.driver:浏览器对象
2.最长等待时间
3.每隔多久查找一次,默认0.5
方法:1.until(‘判断一个元素是否在页面出现的方法’):每隔一段时间调用这个传入的方法,直到返回值不是False
2.方法为:expected_conditions.element_to_be_clickable(“元素定位”) -
显示等待,封装成简单的方法
1、分装
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
class MyGonJu:
# 判断元素是否能被点击
def waif_for_click(self, time, locator):
WebDriverWait(self, time).until(expected_conditions.element_to_be_clickable(locator))
2、使用
MyGonJu.waif_for_click(self.drive, 10, (By.XPATH, '//*[@class="c-container"]//h3/a'))
元素定位
XPATH
用于解析html和xml
缺点:速度慢
优点:可以在selenium和appium上使用
google上的使用:
1、移到操作点,右击检查
2、寻找其父类,确定XPATH的编写
3、在Console(控制台),验证是否正确。语法:$x()
例如: 【 $x(‘//*[@class=“c-container”]//h3/a’) 】
// :代表相对定位 /:代表下一级
Css Selector
和js的语法一样,具体语法可以看css选择器
选择器 | 示例 | 示例说明 |
---|---|---|
.class | .intro | 选择所有class="intro"的元素 |
#id | #firstname | 选择所有id="firstname"的元素 |
* | * | 选择所有元素 |
element | p | 选择所有< p>元素 |
element,element | div,p | 选择所有< div>元素和 < p> 元素 |
element.class | p.hometown | 选择所有 class=“hometown” 的 < 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"的元素 |
:first-of-type | p:first-of-type | 选择每个p元素是其父级的第一个p元素 |
:last-of-type | p:last-of-type | 选择每个p元素是其父级的最后一个p元素 |
:only-of-type | p:only-of-type | 选择每个p元素是其父级的唯一p元素 |
:only-child | p:only-child | 选择每个p元素是其父级的唯一子元素 |
:nth-child(n) | p:nth-child(2) | 选择每个p元素是其父级的第二个子元素 |
:nth-last-child(n) | p:nth-last-child(2) | 选择每个p元素的是其父级的第二个子元素,从最后一个子项计数 |
:nth-of-type(n) | p:nth-of-type(2) | 选择每个p元素是其父级的第二个p元素 |
:nth-last-of-type(n) | p:nth-last-of-type(2) | 选择每个p元素的是其父级的第二个p元素,从最后一个子项计数 |
:last-child | p:last-child | 选择每个p元素是其父级的最后一个子级 |
更多请看 | 菜鸟教程 | css选择器链接直达 |
google上的使用:
语法:$()
例如:【 $(#test)】
八大元素定位方法:
- ID:元素的唯一标识符。
可以通过driver.findElement()方法来查找元素。优点是速度快、稳定性好,缺点是ID不一定在所有元素中都存在,且可能有重复的ID。 - Name:元素的名称属性。
可以通过driver.findElement()方法来查找元素。优点是速度快、易于理解和维护,缺点是Name属性不一定唯一,可能与其他元素重名。 - Class Name:元素的class属性。
可以通过driver.findElement(By.className())方法来查找元素。优点是速度快、易于理解和维护,缺点是Class Name属性不一定唯一,可能与其他元素重名。 - Tag Name:元素的标签名称。
可以通过driver.findElement(By.tagName())方法来查找元素。优点是速度快,缺点是Tag Name属性对具体元素而言不一定唯一。 - Link Text/Partial Link Text:用于链接元素的文本内容。
可以通过driver.findElement(By.linkText()/By.partialLinkText())方法来查找元素。优点是适用于链接元素,易于理解和维护,缺点是Link Text/Partial Link Text属性并不总是唯一,可能会影响测试结果。 - XPath:元素的路径表达式。
可以通过driver.findElement(By.xpath())方法来查找元素。优点是灵活性高,可以通过多个属性组合定位元素,缺点是XPath表达式较长,容易出错,且速度相对较慢。 - CSS Selector:元素的样式表达式。
可以通过driver.findElement(By.cssSelector())方法来查找元素。优点是灵活性高,可读性好,缺点是CSS Selector表达式较长,容易出错,且速度相对较慢。
例如:driver.find_element(By.CSS_SELECTOR, “#kw”)
页面元素未加载完全,导致报错
- findElement():通过定位器查找单个元素,例如driver.findElement(By.id(“username”))。
- findElements():通过定位器查找多个元素,例如driver.findElements(By.tagName(“a”))。
- click():模拟用户点击指定元素,例如element.click()。
- sendKeys():向指定元素输入文本,例如element.sendKeys(“hello world”)。
- getText():获取指定元素的文本内容,例如element.getText()。
- getAttribute():获取指定元素的属性值,例如element.getAttribute(“href”)。
- isEnabled():判断指定元素是否可用,例如element.isEnabled()。
- isSelected():判断指定元素是否选中,例如element.isSelected()。
- isDisplayed():判断指定元素是否可见,例如element.isDisplayed()。
- 定位器的优先级:当多个定位器可以定位到同一个元素时,应该优先使用ID、Name、Class Name等具有唯一性的定位器。
- 相对路径定位:可以通过元素的相对位置来定位其他元素,例如XPath中的//following-sibling、//preceding-sibling等。
- 多重定位器:可以使用多个定位器组合来定位元素,例如XPath中的contains()、starts-with()等函数。
- 等待机制:在执行操作前,应该等待页面加载完成,可以使用time.sleep()、WebDriverWait等方法来控制等待时间。
- 错误处理:在定位元素时,应该加上错误处理机制,例如try-except语句,以避免出现异常情况导致测试失败或程序崩溃。
键盘操作
操作 | 代码 |
---|---|
Keys.BACK_SPACE | 回退键(BackSpace) |
Keys.TAB | 制表键(Tab) |
Keys.ENTER | 回车键(Enter) |
Keys.SHIFT | 大小写转换键(Shift) |
Keys.CONTROL | Control键(Ctrl) |
Keys.ALT | ALT键(Alt) |
Keys.ESCAPE | 返回键(Esc) |
Keys.SPACE | 空格键(Space) |
Keys.PAGE_UP | 翻页键上(Page Up) |
Keys.PAGE_DOWN | 翻页键下(Page Down) |
Keys.END | 行尾键(End) |
Keys.HOME | 行首键(Home) |
Keys.LEFT | 方向键左(Left) |
Keys.UP | 方向键上(Up) |
Keys.RIGHT | 方向键右(Right) |
Keys.DOWN | 方向键下(Down) |
Keys.INSERT | 插入键(Insert) |
DELETE | 删除键(Delete) |
NUMPAD0 ~ NUMPAD9 | 数字键1-9 |
F1 ~ F12: | F1 - F12键 |
(Keys.CONTROL, ‘a’) | 组合键Control+a,全选 |
(Keys.CONTROL, ‘c’) | 组合键Control+c,复制 |
(Keys.CONTROL, ‘x’) | 组合键Control+x,剪切 |
(Keys.CONTROL, ‘v’) | 组合键Control+v,粘贴 |
其他操作
- 单击:click()
- 输入:send_keys()
动作链接ActionChains
执行原理:
调用ActionChains的方法时,不会立即执行,而是将所有的操作,按顺序存放在一个队列里,当你调用perform()方法时,队列中的事件会依次执行。
基本用法:
生成一个动作action=ActionChains(driver)
动作添加方法1 action.方法1
动作添加方法2 action.方法2
调用perform()方法执行
(action.perform())
具体写法:
1、链式写法:
ActionChains(driver).move_to_element(element).click(element).perform()
2、分布写法
actions = ActionChains(driver)
actions.move to element(element)
actions.click(element)
actions.perform()
常见操作:
操作 | 作用 |
---|---|
click(on_element=None) | 单击鼠标左键 |
click_and_hold(on_element=None) | 点击鼠标左键,不松开 |
context_click(on_element=None) | 点击鼠标右键 |
double_click(on_element=None) | 双击鼠标左键 |
drag_and_drop(source, target) | 拖拽到某个元素然后松开 |
drag_and_drop_by_offset(source, xoffset, yoffset) | 拖拽到某个坐标然后松开 |
key_down(value, element=None) | 按下某个键盘上的键 |
key_up(value, element=None) | 松开某个键 |
move_by_offset(xoffset, yoffset) | 鼠标从当前位置移动到某个坐标 |
move_to_element(to_element) | 鼠标移动到某个元素 |
move_to_element_with_offset(to_element, xoffset, yoffset) | 移动到距某个元素(左上角坐标)多少距离的位置 |
perform() | 执行链中的所有动作 |
release(on_element=None) | 在某个元素位置松开鼠标左键 |
send_keys(*keys_to_send) | 发送某个键到当前焦点的元素 |
send_keys_to_element(element, *keys_to_send) | 发送某个键到指定元素 |
滚动条操作:
1.滚动条回到顶部:
js=“var q=document.getElementById(‘id’).scrollTop=0”
browers.execute_script(js)
2.滚动条拉到底部
self.browser.execute_script(‘window.scrollTo(0, document.body.scrollHeight)’)
动作链接TouchAction(适用于手机)
情况处理
滚动条
鼠标悬浮
多窗口处理
就算单击了按钮,页面弹到了新页面,drive控制的还是未跳转时的页面,必须用句柄进行页面的跳转。
窗口切换(句柄)
- 1、获取到当前的窗口句柄:
driver.current_window_handle - 2、再获取到所有的窗口句柄
driver.window_handles - 3、切换窗口
driver.switch_to_window
frame页面
driver.switch_to.frame(“xxx”) 切换到xxxframe下
javascrip脚本操作
selenium能操作js
- drive.execute_script(“JS代码”)
- drive.execute_script(“return JS代码”) 有返回值
文件上传
使用drive.xxx.send_keys(“文件完整路径”)
弹框处理
- drive.switch_to.alert() 切换到的警告框。
- text 返回alert/confirm/prompt 中的文字信息。
- accept() 接受现有警告框。
- dismiss() 解散现有警告框。
- send keys(keysToSend) 发送文本至警告框。keysToSend:将文本发送至警告框
例如:drive.switch_to.alert().accept() 确定弹框
浏览器复用
1、设置chrome 端口号,然后去操作浏览器。(chrome必须配置到环境变量中)
chrome --remote-debugging-port=9222
2、 编写代码如下:
options = Options()
options.debugger_address = ‘127.0.0.1:9222’
self.drive = webdriver.Chrome(options=options)
cooking的使用
1、使用浏览器复用登录,获取cooking并保存在db中
db = shelve.open("cookies")
db['cookie'] = self.drive.get_cookies()
2、然后调用db中的cooking
db = shelve.open("cookies")
cookies = db['cookie']
for cookie in cookies:
if 'expity' in cookie.keys():
cookie.pop('expity')