Selenium

  1. 官方文档:https://www.selenium.dev/zh-cn/documentation/
  2. Selenium 是支持 web 浏览器自动化的一系列工具和库的综合项目。

  3. selenium中包含的工具:
    • webDriver:使用浏览器供应商提供的浏览器自动化API来控制浏览器
    • seleniumIDE:用来开发测试用例的工具,这是一个易于使用的 Chrome 和 Firefox 浏览器扩展。他会使用现有的selenium命令记录用户的操作,参数由上下文确定。
    • Grid:可以本地控制测试用例的操作, 当测试用例被触发时, 它们由远端自动执行。当开发完WebDriver测试之后, 您可能需要在多个浏览器和操作系统的组合上运行测试. 这就是 Grid 的用途所在.
  4. WebDriver 通过驱动程序向浏览器传递命令, 然后通过相同的路径接收信息。

    • 驱动程序: 负责控制实际的浏览器。大多数驱动程序是由浏览器厂商自己创建的。 驱动程序通常是与浏览器一起在系统上运行的可执行模块,而不是在执行测试套件的系统上。 (尽管它们可能是同一个系统。) 注意: 有些人把驱动称为代理。
    • 每个浏览器都有一个特定的 WebDriver 实现,称为驱动程序。 驱动程序是负责委派给浏览器的组件,并处理与 Selenium 和浏览器之间的通信。

    基本通信

    远程通信也可以使用 Selenium Server 或 Selenium Grid 进行,这两者依次与主机系统上的驱动程序进行通信

    WebDriver 对测试一窍不通:它不知道如何比较事物、 断言通过或失败,当然它也不知道报告或 Given/When/Then 语法。

    所以需要一个与绑定语言相匹配的测试框架,比如. NET 的 NUnit, Java 的 JUnit, Ruby 的 RSpec 等等。

    测试框架负责运行和执行 WebDriver 以及测试中相关步骤。因此,您可以认为它看起来类似于下图。

    测试框架

  5. WebDriver
    • WebDriver 被设计成一个简单和简洁的编程接口。
    • WebDriver 是一个简洁的面向对象 API。
    • 它能有效地驱动浏览器。
  6. 八个基本组成部分

    Selenium所做的一切, 就是发送给浏览器命令, 用以执行某些操作或为信息发送请求. 您将使用Selenium执行的大部分操作, 都是以下基本命令的组合

    • 使用驱动实例开启会话

      driver = webdriver.Chrome()
      
    • 导航到网页

      driver.get("https://www.selenium.dev/selenium/web/web-form.html")
      
    • 请求浏览器信息

      title = driver.title
      
    • 建立等待策略

      driver.implicitly_wait(0.5)
      

      它的作用是让 WebDriver 在尝试查找元素时,如果没有立即找到,会在接下来的 0.5 秒内持续轮询查找,直到找到元素或者超时。

      通常情况下,轮询时间的具体值是由 WebDriver 的内部实现决定的,并且对于使用者来说是不可配置的。在这个例子中,WebDriver 会在 0.5 秒的超时时间内,按照其内部设定的轮询频率不断检查元素是否出现。

    • 查找元素

      text_box = driver.find_element(by=By.NAME, value="my-text")
      submit_button = driver.find_element(by=By.CSS_SELECTOR, value="button")
      
    • 操作元素

      text_box.send_keys("Selenium")
      submit_button.click()	
      
    • 获取元素信息

      text = message.text
      
    • 结束会话

      driver.quit()
      
  7. 一个小示例
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    
    def test_eight_components():
        driver = webdriver.Chrome()
    
        driver.get("https://www.selenium.dev/selenium/web/web-form.html")
    
        title = driver.title
        assert title == "Web form"
    
        driver.implicitly_wait(0.5)
    
        text_box = driver.find_element(by=By.NAME, value="my-text")
        submit_button = driver.find_element(by=By.CSS_SELECTOR, value="button")
    
        text_box.send_keys("Selenium")
        submit_button.click()
    
        message = driver.find_element(by=By.ID, value="message")
        value = message.text
        assert value == "Received!"
    
        driver.quit()
    
    
  8. 驱动选项类Options-pageLoadStrategy-页面加载策略
    • normal (默认值)

      WebDriver一直等到 load 事件触发并返回.

          options.page_load_strategy = 'normal'
          driver = webdriver.Chrome(options=options)
      
      • Window: load event

        当整个页面(包括所有相关资源,如样式表、脚本、iframe 和图像,但不包括那些延迟加载的资源)加载完成时,会触发“load”事件。

    • eager

      WebDriver一直等到 DOMContentLoaded 事件触发并返回.

          options.page_load_strategy = 'eager'
          driver = webdriver.Chrome(options=options)
      
      • DOMContentLoaded 事件

        当 HTML 文档已被完全解析,并且所有延迟脚本已下载并执行时,会触发 DOMContentLoaded 事件。它不会等待诸如图片、子框架和异步脚本之类的其他内容完成加载。

    • none

      WebDriver 仅等待初始页面已下载.

          options.page_load_strategy = 'none'
          driver = webdriver.Chrome(options=options)
      
  9. 驱动服务类Service
    • 驱动程序端口

      如果希望驱动程序在特定端口上运行, 您可以在启动时指定端口号, 如下所示:

      service = webdriver.ChromeService(port=1234)
      
    • 日志

      日志记录功能因浏览器而异. 大多数浏览器都允许您指定日志的位置和级别.:

          service = webdriver.ChromeService(service_args=['--log-level=DEBUG'], log_output=subprocess.STDOUT)
      
          service = webdriver.ChromeService(log_output=log_path)
      
    • 浏览器日志是浏览器在运行过程中记录的各种信息和事件的记录。

      它可以包含多种类型的信息,例如: 1. 页面加载的相关信息:包括加载的起始时间、结束时间、是否有错误等。 2. 脚本执行的情况:如 JavaScript 脚本的执行错误、警告等。 3. 网络请求和响应:包括请求的 URL、请求方法、响应状态码、响应时间等。 4. 浏览器的配置和设置更改。 5. 插件和扩展的相关活动。 通过查看浏览器日志,开发人员可以诊断网页加载和运行中的问题,优化性能,以及了解用户与浏览器的交互情况。

      不同的浏览器通常提供不同的方式来查看和获取这些日志信息。

  10. 隐式等待

Selenium 有一种内置的自动等待元素的方法,称为隐式等待。

这是一个全局设置,适用于整个会话中的每个元素定位调用。默认值是 0,这意味着如果找不到元素,它将立即返回错误。如果设置了隐式等待,在返回错误之前,驱动程序将等待所提供的值的持续时间。请注意,一旦定位到元素,驱动程序将返回元素引用,并且代码将继续执行,所以较大的隐式等待值不一定会增加会话的持续时间。

driver.implicitly_wait(2)
  1. 显式等待

    显式等待是添加到代码中的循环,它在应用程序中轮询特定条件,在该条件评估为真时才退出循环并继续执行代码中的下一个命令。如果在指定的超时值之前条件未满足,代码将给出超时错误。由于应用程序有很多方式无法处于期望的状态,所以显式等待是在每个需要的地方指定确切等待条件的绝佳选择。另一个不错的特性是,默认情况下,Selenium 的 Wait 类会自动等待指定的元素存在。

  2. 显式等待和隐式等待的区别

显式等待

  • 非常有针对性,可以针对特定的元素或条件进行等待。
  • 可以根据不同的元素和情况设置不同的等待条件和超时时间。
  • 例如,可以等待某个特定元素出现后再进行下一步操作,或者等待页面加载完成特定的部分。

隐式等待

  • 是一种通用的等待方式,适用于所有元素的查找。
  • 一旦设置,在整个 WebDriver 会话期间都会生效,对所有元素的查找操作都遵循这个等待时间。
  1. 文件上传

    因为 Selenium 无法与文件上传对话框进行交互,所以它提供了一种无需打开对话框即可上传文件的方法。如果元素是一个类型为“file”的输入元素,你可以使用 send_keys 方法来发送要上传的文件的完整路径。

        file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']")
        file_input.send_keys(upload_file)
        driver.find_element(By.ID, "file-submit").click()
    
  2. 查询器
    • Evaluating the Shadow DOM

      隐藏在一个元素内部的封装 DOM 树

      shadow_host = driver.find_element(By.CSS_SELECTOR, '#shadow_host')
      shadow_root = shadow_host.shadow_root
      shadow_content = shadow_root.find_element(By.CSS_SELECTOR, '#shadow_content')
      
    • Find Elements From Element
      element = driver.find_element(By.TAG_NAME, 'div')
      
          # Get all the elements available with tag name 'p'
      elements = element.find_elements(By.TAG_NAME, 'p')
      for e in elements:
          print(e.text)
      
    • Get Active Element

      它用于跟踪(或)找到在当前浏览上下文中具有焦点的 DOM 元素。

        from selenium import webdriver
        from selenium.webdriver.common.by import By
      
        driver = webdriver.Chrome()
        driver.get("https://www.google.com")
        driver.find_element(By.CSS_SELECTOR, '[name="q"]').send_keys("webElement")
      
          # Get attribute of current active element
        attr = driver.switch_to.active_element.get_attribute("title")
        print(attr)
        
      
  3. 交互
    • 点击

          # Navigate to url
      	driver.get("https://www.selenium.dev/selenium/web/inputs.html")
      
          # Click on the element 
      	driver.find_element(By.NAME, "color_input").click()
        
      
    • 发送键位与清除

          # Navigate to url
      	driver.get("https://www.selenium.dev/selenium/web/inputs.html")
      
          # Clear field to empty it from any previous data
      	driver.find_element(By.NAME, "email_input").clear()
      
      	# Enter Text
      	driver.find_element(By.NAME, "email_input").send_keys("admin@localhost.dev" )
      
        
      
  4. 定位器

  1. CSS选择器

    CSS 选择器(CSS Selector)是一种用于选择 HTML 或 XML 文档中特定元素的模式。它是 CSS(层叠样式表)的重要组成部分,允许开发人员指定要应用样式的元素。

    一、基本类型的 CSS 选择器

    1. 元素选择器: - 通过元素名称来选择元素。例如,p 选择所有 <p> 段落元素,div 选择所有 <div> 元素。
    2. 类选择器: - 以 . 开头,后面跟着类名。选择具有特定类名的元素。例如,.my-class 选择所有具有 class="my-class" 的元素。
    3. ID 选择器: - 以 # 开头,后面跟着 ID 名称。选择具有特定 ID 的单个元素。例如,#my-id 选择具有 id="my-id" 的元素。

    二、组合和高级选择器

    1. 后代选择器: - 用于选择作为特定元素后代的元素。例如,div p 选择所有在 <div> 元素内部的 <p> 元素。
    2. 子选择器: - 选择直接子元素。以 > 符号表示。例如,div > p 选择所有直接在 <div> 元素下的 <p> 元素。
    3. 相邻兄弟选择器: - 选择紧跟在指定元素后面的兄弟元素。以 + 符号表示。例如,h1 + p 选择紧跟在 <h1> 元素后面的第一个 <p> 元素。
    4. 通用兄弟选择器: - 选择指定元素后面的所有兄弟元素。以 ~ 符号表示。例如,h1 ~ p 选择 <h1> 元素后面的所有 <p> 元素。

    三、属性选择器

    1. 根据属性值选择元素:

      [attribute=value]:选择具有特定属性和值的元素。例如,[type="text"] 选择所有 type="text" 的元素。

      [attribute^=value]:选择属性值以特定值开头的元素。例如,[href^="https"] 选择所有以“https”开头的 href 属性的元素。 [attribute$=value]:选择属性值以特定值结尾的元素。例如,[href$=".pdf"] 选择所有以“.pdf”结尾的 href 属性的元素。 [attribute*=value]:选择属性值包含特定值的元素。例如,[alt*="image"] 选择所有 alt 属性包含“image”的元素。

  2. xpath(XML Path Language)

    1. 选择根节点

    /   # 选择根节点
    

    2. 选择元素

    //div  # 选择所有的 `<div>` 元素
    /bookstore/book  # 选择所有位于 `<bookstore>` 下的 `<book>` 元素
    

    3. 通过属性选择

    //a[@href='https://example.com']  # 选择所有具有 `href` 属性值为 `https://example.com` 的 `<a>` 元素
    //img[@alt='Image description']  # 选择所有具有 `alt` 属性值为 `Image description` 的 `<img>` 元素
    

    4. 选择特定位置的元素

    //ul/li[2]  # 选择 `<ul>` 下的第二个 `<li>` 元素
    (//p)[5]   # 选择文档中的第五个 `<p>` 元素
    

    5. 选择具有特定文本的元素

    //p[contains(text(),'Some text')]  # 选择包含特定文本的 `<p>` 元素
    

    6. 选择父节点

    //a[@href='https://example.com']/parent::div  # 选择具有特定链接的 `<a>` 元素的父 `<div>` 元素
    

    7. 选择子节点

    //div[@id='container']/child::p  # 选择具有特定 `id` 的 `<div>` 元素的子 `<p>` 元素
    

    8. 选择后代节点

    //div[@id='container']//p  # 选择具有特定 `id` 的 `<div>` 元素的后代 `<p>` 元素
    

    9. 选择兄弟节点

    //div[@id='first']/following-sibling::div[@id='second']  # 选择具有 `id` 为 `first` 的 `<div>` 元素的下一个兄弟 `<div>` 元素(具有 `id` 为 `second`)
    

    这些只是 XPath 表达式的一些基本示例,XPath 还可以进行更复杂的选择和导航操作,具体取决于文档的结构

    	driver = webdriver.Chrome()
    	driver.find_element(By.XPATH, "//input[@value='f']")
    
  3. Available relative locators
    Above

    If the email text field element is not easily identifiable for some reason, but the password text field element is, we can locate the text field element using the fact that it is an “input” element “above” the password element.

    email_locator = locate_with(By.TAG_NAME, "input").above({By.ID: "password"})
    
    Below
    password_locator = locate_with(By.TAG_NAME, "input").below({By.ID: "email"})
    
    Left of
    cancel_locator = locate_with(By.TAG_NAME, "button").to_left_of({By.ID: "submit"})
    
    Right of
    submit_locator = locate_with(By.TAG_NAME, "button").to_right_of({By.ID: "cancel"})
    
    Near
    email_locator = locate_with(By.TAG_NAME, "input").near({By.ID: "lbl-email"})
    
    Chaining relative locators
    submit_locator = locate_with(By.TAG_NAME, "button").below({By.ID: "email"}).to_right_of({By.ID: "cancel"})
    
  4. 元素
    是否显示
    # Navigate to the url
    driver.get("https://www.selenium.dev/selenium/web/inputs.html")
    
    # Get boolean value for is element display
    is_email_visible = driver.find_element(By.NAME, "email_input").is_displayed()
    
    是否启用
        # Navigate to url
    driver.get("https://www.selenium.dev/selenium/web/inputs.html")
    
        # Returns true if element is enabled else returns false
    value = driver.find_element(By.NAME, 'button_input').is_enabled()
      
    
    是否被选定
        # Navigate to url
    driver.get("https://www.selenium.dev/selenium/web/inputs.html")
    
        # Returns true if element is checked else returns false
    value = driver.find_element(By.NAME, "checkbox_input").is_selected()
      
    
    获取元素标签名
        # Navigate to url
    driver.get("https://www.selenium.dev/selenium/web/inputs.html")
    
        # Returns TagName of the element
    attr = driver.find_element(By.NAME, "email_input").tag_name
      
    
    位置和大小
        # Navigate to url
    driver.get("https://www.selenium.dev/selenium/web/inputs.html")
    
        # Returns height, width, x and y coordinates referenced element
    res = driver.find_element(By.NAME, "range_input").rect
      
    
    获取元素CSS值
        # Navigate to Url
    driver.get('https://www.selenium.dev/selenium/web/colorPage.html')
    
        # Retrieves the computed style property 'color' of linktext
    cssValue = driver.find_element(By.ID, "namedColor").value_of_css_property('background-color')
    
      
    
    文本内容
        # Navigate to url
    driver.get("https://www.selenium.dev/selenium/web/linked_image.html")
    
        # Retrieves the text of the element
    text = driver.find_element(By.ID, "justanotherlink").text
      
    
    获取特性或属性
    # Navigate to the url
    driver.get("https://www.selenium.dev/selenium/web/inputs.html")
    
    # Identify the email text box
    email_txt = driver.find_element(By.NAME, "email_input")
    
    # Fetch the value property associated with the textbox
    value_info = email_txt.get_attribute("value")
      
    
  5. 浏览器导航
    driver.get("https://www.selenium.dev")
    driver.get("https://www.selenium.dev/selenium/web/index.html")
    
    title = driver.title
    assert title == "Index of Available Pages"
    # 按下浏览器的后退按钮:
    driver.back()
    title = driver.title
    assert title == "Selenium"
    # 按下浏览器的前进键:
    driver.forward()
    title = driver.title
    assert title == "Index of Available Pages"
    # 刷新
    driver.refresh()
    title = driver.title
    assert title == "Index of Available Pages"
    
  6. 切换窗口或标签页
    from selenium import webdriver
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    
        # 启动驱动程序
    with webdriver.Firefox() as driver:
        # 打开网址
    driver.get("https://seleniumhq.github.io")
    
        # 设置等待
        wait = WebDriverWait(driver, 10)
    
        # 存储原始窗口的 ID
        original_window = driver.current_window_handle
    
        # 检查一下,我们还没有打开其他的窗口
        assert len(driver.window_handles) == 1
    
        # 单击在新窗口中打开的链接
        driver.find_element(By.LINK_TEXT, "new window").click()
    
        # 等待新窗口或标签页
        wait.until(EC.number_of_windows_to_be(2))
    
        # 循环执行,直到找到一个新的窗口句柄
        for window_handle in driver.window_handles:
            if window_handle != original_window:
                driver.switch_to.window(window_handle)
                break
    
        # 等待新标签页完成加载内容
        wait.until(EC.title_is("SeleniumHQ Browser Automation"))
    
  7. 屏幕截图
    from selenium import webdriver
    
    driver = webdriver.Chrome()
    
        # Navigate to url
    driver.get("http://www.example.com")
    
        # Returns and base64 encoded string into image
    driver.save_screenshot('./image.png')
    
    driver.quit()
    
  8. 元素屏幕截图
    from selenium import webdriver
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    
        # Navigate to url
    driver.get("http://www.example.com")
    
    ele = driver.find_element(By.CSS_SELECTOR, 'h1')
    
        # Returns and base64 encoded string into image
    ele.screenshot('./image.png')
    
    driver.quit()
    
posted @ 2024-08-30 15:28  疯啦吧你  阅读(45)  评论(0编辑  收藏  举报