• WebDriver的工作原理及常用方法大全


    WebDriver的工作原理

    在我们new一个WebDriver的过程中,Selenium首先会确认浏览器的native component是否存在可用而且版本匹配。接着就在目标浏览器里启动一整套Web Service(实际上就是浏览器厂商提供的driver, 比如IEDriver, ChromeDriver,它们都实现了WebDriver’s wire protocol.),这套Web Service使用了Selenium自己设计定义的协议,名字叫做The WebDriver Wire Protocol。

    WebDriver Wire协议是通用的,也就是说不管是FirefoxDriver还是ChromeDriver,启动之后都会在某一个端口启动基于这套协议的Web Service。例如FirefoxDriver初始化成功之后,默认会从http://localhost:7055开始,而ChromeDriver 则大概是http://localhost:46350之类的。

    接下来,我们调用WebDriver的任何API,都需要借助一个 ComandExecutor发送一个命令,实际上是一个HTTP request给监听端口上的Web Service。在我们的HTTP request的body中,会以WebDriver Wire协议规定的JSON格式的字符串来告诉Selenium我们希望浏览器接下来做什么事情。

    WebDriver 启动目标浏览器,并绑定到指定端口。该启动的浏览器实例,做为web driver的remote server

    Client 端通过CommandExcuter 发送HTTPRequest 给remote server 的侦听端口(通信协议:the webriver wire protocol)

    Remote server 需要依赖原生的浏览器组件(如:IEDriver.dll,chromedriver.exe),来转化转化浏览器的native调用。

    那么remoteserver端的这些功能是如何实现的呢?答案是浏览器实现了webdriver的统一接口,这样client就可以通过统一的restful的接口去进行浏览器的自动化操作。目前webdriver支持ie, chrome, firefox, opera等主流浏览器,其主要原因是这些浏览器实现了webdriver约定的各种接口。

    可以更通俗的理解:由于客户端脚本(java,python,ruby)不能直接与浏览器通信,这时候可以把WebService当做一个翻译器,它可以把客户端代码翻译成浏览器可以识别的代码(比如js).客户端 (也就是测试脚本)创建1个session,在该session中通过http请求向WebService发送restful的请求,WebService翻译成浏览器懂得脚本传给浏览器,浏览器把执行的结果返回给WebService,WebService把返回的结果做了一些封 装(一般都是json格式),然后返回给client,根据返回值就能判断对浏览器的操作是不是执行成功

    摘自官网对于chrome driver的描述:

    The ChromeDriver consists of three separate pieces. There is the browser itself (“chrome”), the language bindings provided by the Selenium project (“the driver”) and an executable downloaded from the Chromium project which acts as a bridge between “chrome” and the “driver”. This executable is called “chromedriver”, but we’ll try and refer to it as the “server” in this page to reduce confusion.

    大概意思就是我们下载的chrome可执行文件(.exe)是为作为浏览器与client(language binding)桥梁的作用,也更印证了对于Web Service(driver)的理解。

    举个实际的例子:

    WebDriver diver = new FirefoxDriver();
    driver.get("http://google.com");
    
    • 1
    • 2

    在执行 driver.get(“http://google.com”); 这句代码时,client也就是我们的测试代码向Web Service(remote server)发送了如下的请求:

    POST session/285b12e4-2b8a-4fe6-90e1-c35cba245956/url
    post_data {"url":"http://google.com"} 
    
    • 1
    • 2

    通过post的方式请求localhost:port/hub/session/session_id/url地址,请求浏览器完成跳转url的操作。

    如果上述请求是可接受的,或者说Web Service是实现了这个接口,那么Web Service会跳转到该post data包含的url,并返回如下的

    response
    {"name":"get","sessionId":"285b12e4-2b8a-4fe6-90e1-c35cba245956","status":0,"value":""}
    
    • 1
    • 2

    该response中包含如下信息 name:Web Service端的实现的方法的名称,这里是get,表示跳转到指定url;sessionId:当前session的id;status:请求执行的状态码,非0表示未正确执行,这里是0,表示一切ok不必担心;value:请求的返回值,这里返回值为空,如果client调用title接口,则该值应该是当前页面的title;

    如果client发送的请求是定位某个特定的页面元素,则response的返回值可能是这样的:

    {"name":"findElement","sessionId":"285b12e4-2b8a-4fe6-90e1-c35cba245956","status":0,"value":{"ELEMENT":"{2192893e-f260-44c4-bdf6-7aad3c919739}"}}
    
    • 1

    name,sessionId,status跟上面的例子是差不多的,区别是该请求的返回值是ELEMENT:{2192893e- f260-44c4-bdf6-7aad3c919739},表示定位到元素的id,通过该id,client可以发送如click之类的请求与 server端进行交互。

    WebDriver的常用方法

    日常操作

    from selenium import webdriver
    from time import sleep
    
    
    # 创建谷歌浏览器对象
    chrome_driver = webdriver.Chrome()
    
    # 访问百度
    chrome_driver.get("http://www.baidu.com")
    
    # 最大化窗口
    chrome_driver.maximize_window()
    # 访问柠檬班
    chrome_driver.get("https://lemon.ke.qq.com/")
    # 后退
    chrome_driver.back()
    # 前进,要有历史记录
    chrome_driver.forward()
    
    # 刷新
    chrome_driver.refresh()
    
    # 等待10s,更明显看出效果
    sleep(10)
    # 关闭窗口,关闭当前窗口
    chrome_driver.close()
    
    # 等待10s,更明显看出效果
    sleep(10)
    
    # 关闭会话,关闭浏览器,关闭driver
    chrome_driver.quit()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    鼠标事件

    from selenium import webdriver
    # 引入 ActionChains 类
    from selenium.webdriver.common.action_chains import ActionChains
    driver = webdriver.Chrome() driver.get("https://www.baidu.cn")
    #  定位到要悬停的元素
    above = driver.find_element_by_link_text("设置") #  对定位到的元素执行鼠标悬停操作
    ActionChains(driver).move_to_element(above).perform()
    '''
    perform(): 执行操作
    context_click(): 右击;
    double_click(): 双击;
    drag_and_drop(): 拖动;
    move_to_element(): 鼠标悬停
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    键盘事件

    from selenium import webdriver
    #  引入 Keys  模块
    from selenium.webdriver.common.keys import Keys
    driver = webdriver.Chrome ()
    driver.get("http://www.baidu.com")
    #输入框输入内容
    driver.find_element_by_id ("kw").send_keys("seleniumm")
    #删除多输入的一个m
    driver.find_element_by_id ("kw").send_keys(Keys.BACK_SPACE)
    '''
    删除键(BackSpace)send_keys(Keys.BACK_SPACE)
    空格键 (Space)send_keys(Keys.SPACE)
    制表键(Tab) send_keys(Keys.TAB)
    回退键(Esc)send_keys(Keys.ESCAPE)
    回车键(Enter)send_keys(Keys.ENTER)
    全选(Ctrl+A)send_keys(Keys.CONTROL,‘a’)
    复制(Ctrl+C)send_keys(Keys.CONTROL,‘c’)
    剪切(Ctrl+X)send_keys(Keys.CONTROL,‘x’)
    粘贴(Ctrl+V)send_keys(Keys.CONTROL,‘v’)
    键盘 F1 send_keys(Keys.F1)
    键盘 F12send_keys(Keys.F12)
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    上传文件

    driver.find_element_by_id("albumUpload").send_keys("文件路径")
    #通过模拟键盘敲击上传
    from selenium.webdriver.common.action_chains import ActionChains
    from selenium import webdriver
    import win32com.client  # python -m pip install pypiwin32
    
    ActionChains(driver).click(driver.find_element_by_id("albumUpload")).perform()
    sh = win32com.client.Dispatch("WScript.shell")
    time.sleep(3)
    # 1、代码不联想  2、输入法要保持英文输入状态 3、无法处理中文
    sh.Sendkeys("文件路径\r\n")
    '''
    上传多个文件
    通过输入文件路径上传
    "文件1路径\n文件2路径"
    通过模拟键盘上传
    '"文件1路径" "文件2路径\r\n"'
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    内嵌网页iframe切换

    # 定位到内嵌网页
    ele = driver.find_element_by_css_selector("[class=\"ke-edit-iframe\"]")
    # 切入内嵌网页中
    driver.switch_to.frame(ele)
    driver.find_element_by_css_selector("[class=\"ke-content\"]").send_keys("123")
    # 切入内嵌网页后,若想再操作内嵌网页外的元素,需要再切出来
    driver.switch_to.default_content()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    浏览器标签页切换

    win_sli = driver.window_handles  # 获取当前所有标签页的句柄
    
    # 循环所有标签,直到找到标题、url、页面元素相符的标签,就停止切换,停留在当前标签页
    for win in win_sli:
        driver.switch_to.window(win)
        # 如果标签页的标题不固定,还可以用网址判断
        # 如果网址和标题都不固定,可以找一个目标标签页独有的元素,然后判断元素是否存在
        if driver.title == "OPMS-项目管理软件+OA管理软件+CRM管理软件":
            break
    '''
    current_window_handle:获得当前标签页句柄
    window_handles:返回所有便签页的句柄
    switch_to.window(标签页句柄):切换到对应的标签页
    关闭标签页使用 close 方法
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    页面滚动

    driver.execute_script(“window.scrollBy(0,500)”)
    driver.execute_script(“arguments[0].scrollIntoView();”, ele)
    '''
    window.scrollBy(0,500) 向下滚动500个像素
    window.scrollBy(0,-500) 向上滚动500个像素
    window.scrollBy(500,0) 向右滚动500个像素
    window.scrollBy(-500,0) 向左滚动500个像素
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    截图

    # 截图,截取全屏,参数为要保存图片的文件路径,官方建议用png格式
    # 如果想截取登陆以后的界面:1、sleep  2、寻找一个登录后才有的元素
    driver.get_screenshot_as_file("./a.png")
    
    # 对元素进行截图
    ele = driver.find_element_by_css_selector("[class=\"nav nav-pills nav-stacked custom-nav js-left-nav\"]")
    ele.screenshot("./b.png")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    警告框处理

    # 获取对话框对象
    al = driver.switch_to.alert
    # 确认对话框
    al.accept()
    '''
    text:返回 alert/confirm/prompt 中的文字信息
    accept():接受现有警告框
    dismiss():取消现有警告框
    send_keys(“haha”):发送文本至警告框
    '''
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    现在我邀请你进入我们的软件测试学习交流群:746506216】,备注“入群”, 大家可以一起探讨交流软件测试,共同学习软件测试技术、面试等软件测试方方面面,还会有免费直播课,收获更多测试技巧,我们一起进阶Python自动化测试/测试开发,走向高薪之路。

    喜欢软件测试的小伙伴们,如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一 键三连哦!

    软件测试工程师自学教程:

    这才是2022最精细的自动化测试自学教程,我把它刷了无数遍才上岸字节跳动,做到涨薪20K【值得自学软件测试的人刷】

    接口性能测试 — 软件测试人必会618实战场景分析

    软件测试工程师月薪2W以上薪资必学技能 — Python接口自动化框架封装.

    美团面试真题_高级测试25K岗位面试 — 软件测试人都应该看看

    测试开发之全面剖析自动化测试平台 — 软件测试人的必经之路

    软件测试必会_Jmeter大厂实战 — 仅6步可实现接口自动化测试

    Jmeter实战讲解案例 — 软件测试人必会

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    SpringBoot如何优雅的进行参数校验
    灯光照明设备经营小程序商城的作用是什么
    深入浅出Scala之函数式编程、静态类型语言(P4-P9)
    面试题之数组的去重方式
    无法访问mybatis.dto.StudengInVO-使用maven编译报错-2022新项目
    GLIP & DetCLIP
    XDP入门--通过用户态程序自动加载与卸载eBPF程序字节码到网卡
    【深度学习】今日bug(8月2)
    spring的redis注解@Cacheable @Cacheput @CacheEvict的condition、unless
    服务器基准测试实践:SysBench的搭建与基本使用
  • 原文地址:https://blog.csdn.net/m0_67695717/article/details/126285727