Loading

Selenium学习笔记

一、概述

1. 什么是自动化测试

  • 让程序代替人工去验证系统功能的过程

2. 自动化测试能解决什么问题

  • 回归测试:项目在发新版本之后,对项目之前的功能进行验证

  • 压力测试:可理解为多用户同时去操作软件,统计软件服务器处理多用户请求的能力

  • 兼容性测试:浏览器、分辨率、操作系统

  • 提高测试效率,保证产品质量

3. 优点

  • 较少的时间内运行更多的测试用例【提高效率】

  • 自动化脚本可重复运行

  • 减少人为的错误【提高产品质量】

  • 克服手工测试的局限性【如:获取图片大小】

  • 规格统一标准

4. 误区

  • 自动化测试可完全代替手工测试

  • 自动化测试一定比手工测试厉害

  • 自动化测试可以发掘更多的 BUG

  • 自动化测试适用于所有功能

5. 分类

  • Web - 自动化测试

  • 移动 - 自动化测试【app 自动化】

  • 接口 - 自动化测试(工具、代码)

  • 单元测试 - 自动化测试

6. 什么是 Web 自动化测试

  • 让程序代替人工自动验证 Web 项目功能的过程

  • Web 自动化测试属于黑盒测试

7. 什么 Web 项目适合做自动化测试

  • 需求变动不频繁

  • 项目周期长

  • 项目需要回归测试

8. Web 自动化测试在什么阶段开始

  • 功能测试完毕(手工测试之后)

    • 时间问题

    • 功能不完善

9. 主流的 Web 自动化测试工具

  • QTP:商业化的功能测试工具,收费,支持 web、桌面自动化测试

  • Selenium:开源的 Web 自动化测试工具,免费,主要做功能测试,只支持 web 项目

  • Robot framework:基于 Python 可扩展的关键字驱动的测试自动化框架(2014 年停止更新)

10. Selenium 特点

  • 开源软件:源代码开放,可根据需要来增加工具的某些功能

  • 跨平台:linux、windows、mac

  • 支持多种浏览器:Firefox、Chrome、IE、Edge、Opera、Safari 等

  • 支持多种语言:Python、Java、C#、JavaScript、Ruby、PHP 等

  • 成熟稳定:目前已被 Google、百度、腾讯等公司广泛使用

  • 功能强大:能够实现类似商业工具的大部分功能,因为开性,可实现定制化功能

11. 科普 Path

  • 说明:指定系统搜索的目录

  • dos 命令默认搜索顺序:

    • 检测是否为内部命令

    • 检测是否为当前目录下可执行文件

    • 检测 Path 环境变量指定的目录

  • 如果以上搜索目录都检测不到输入的命令或可执行文件,系统会抛出“不是内部或外部命令...”

二、Selenium

1. 安装、查看、卸载

pip install selenium
pip show selenium
pip uninstall selenium

2. 安装浏览器驱动

3. 新建项目

4. 示例

4.1 打开 B 站

import time
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://www.bilibili.com")
# 1、找到输入框,输入软件测试
driver.find_element(By.CLASS_NAME, "nav-search-input").send_keys("软件测试")
# 2、找到搜索框,点击搜索
driver.find_element(By.CLASS_NAME, "nav-search-btn").click()
time.sleep(3)
driver.close()

4.2 官方文档示例

from selenium import webdriver
from selenium.webdriver.common.by import By

# 八个基本组成部分
# 1. 使用驱动实例开启会话
driver = webdriver.Chrome()
# 2. 在浏览器上执行操作
driver.get("https://www.selenium.dev/selenium/web/web-form.html")
# 3. 请求浏览器信息
title = driver.title
print(title)
# 4. 建立等待策略
driver.implicitly_wait(0.5)
# 5. 发送命令查找元素
textInput = driver.find_element(By.CSS_SELECTOR, "#my-text-id")
submitBtn = driver.find_element(By.XPATH, "//button[@type='submit']")
# 6. 操作元素
textInput.send_keys("hello")
submitBtn.click()
# 7. 获取元素信息
message = driver.find_element(By.ID, "message")
text = message.text
print(text)
# 8. 结束会话
driver.quit()
  • 结合 pytest 后的代码
from selenium import webdriver
from selenium.webdriver.common.by import By


def setup():
    # 1. 使用驱动实例开启会话
    driver = webdriver.Chrome()
    # 2. 在浏览器上执行操作
    driver.get("https://www.selenium.dev/selenium/web/web-form.html")
    return driver


def teardown(driver):
    # 8. 结束会话
    driver.quit()


def test_eight_components():
    driver = setup()
    # 3. 请求浏览器信息
    title = driver.title
    assert title == "Web form"
    # 4. 建立等待策略
    driver.implicitly_wait(0.5)
    # 5. 发送命令查找元素
    textInput = driver.find_element(By.CSS_SELECTOR, "#my-text-id")
    submitBtn = driver.find_element(By.XPATH, "//button[@type='submit']")
    # 6. 操作元素
    textInput.send_keys("hello")
    submitBtn.click()
    # 7. 获取元素信息
    message = driver.find_element(By.ID, "message")
    text = message.text

5. 关闭浏览器

  • driver.close():关闭单个浏览器窗口

  • driver.quit():关闭所有浏览器窗口

  • selenium4 会自动关闭

6. 八大元素定位

定位器 描述
By.ID 通过 id 定位
By.CLASS_NAME 通过类名定位
By.TAG_NAME 通过标签名定位
By.NAME 通过 name 属性定位
By.LINK_TEXT 根据链接中的文字定位
By.PARTIAL_LINK_TEXT 根据链接部分名称查找定位,如果匹配多个元素,则只选择第一个元素
By.CSS_SELECTOR 通过 CSS 选择器定位
By.XPATH 通过 XPath 表达式定位

6.1 By.ID

  • id 是唯一的,通过 id 查找元素时可以快速定位到目标元素
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
# 窗口最大化
driver.maximize_window()
driver.find_element(By.ID, "kw").send_keys("软件测试")
driver.find_element(By.ID, "su").click()
sleep(5)

6.2 By.CLASS_NAME

  • 通过类名定位
driver = webdriver.Chrome()
driver.get("https:www.bilibili.com")
driver.maximize_window()
# 只获取class属性的第一个元素
# driver.find_element(By.CLASS_NAME, "nav-search-input").send_keys("软件测试")
# 使用find_elements()时,需要指定下标
driver.find_elements(By.CLASS_NAME, "nav-search-input")[0].send_keys("软件测试")
driver.find_element(By.CLASS_NAME, "nav-search-btn").click()

for ele in driver.find_elements(By.CLASS_NAME, 'channel-link'):
    print(ele.txt)

time.sleep(3)
  • find_element():只获取相关属性的第一个元素

  • find_elements():获取相关属性的所有元素

  • class中间有空格时,只能选取一个作为参数传递

6.3 By.TAG_NAME

  • 通过标签名定位元素,不推荐使用
driver = webdriver.Chrome()
driver.get("https://www.bilibili.com")
driver.maximize_window()
driver.find_element(By.TAG_NAME, "input").send_keys("软件测试")
sleep(3)

6.4 By.NAME

  • 通过 name 属性定位,可能不是唯一的,要根据实际情况进行判断
driver = webdriver.Chrome()
driver.get("https://www.baidu.com")
driver.maximize_window()

driver.find_element(By.NAME, "wd").send_keys("软件测试")
sleep(3)
  • 根据链接中的文字定位
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.baidu.com")
driver.find_element(By.LINK_TEXT, "新闻").click()
sleep(3)
  • 根据链接中部分文字查找定位
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.baidu.com")
driver.find_element(By.PARTIAL_LINK_TEXT, "hao").click()
sleep(3)

6.7 By.CSS_SELECTOR

  • CSS 常用汇总
选择器 样式 示例 示例说明
标签选择器 html 标签 input 选择所有 input 元素
ID 选择器 #id 属性值 #kw 选择所有 id='kw' 的元素
类选择器 .class 属性值 .nav-search-input 选择所有 class='nav-search-input' 的元素
属性选择器 [属性名] [name="wd"] 选择所有 name="wd" 的元素
组合选择器 标签+属性表述 input.s_ipt 选择所有 class='ipt' 的 input 元素
父子关系 元素 1>元素 2 div>a 选择所有父级是 div 的 a 元素
后代关系 元素 1 元素 2 div a 选择 div 中的所有 a 元素
第一子元素 :first-child a:first-child 选择所有 a 元素且该元素是其父级的第一个元素
最后一个元素 :last-child a:last-child 选择所有 a 元素且该元素是其父级的最后一个元素
顺序选择器 :nth-child(n) a:nth-child(2) 选择所有 a 元素且该元素是其父级的第二个子元素
  • 示例
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.baidu.com")
# id
driver.find_element(By.CSS_SELECTOR, "#kw").send_keys("软件测试")
# name属性
driver.find_element(By.CSS_SELECTOR, "[name='wd']").send_keys("软件测试")
# type属性
driver.find_element(By.CSS_SELECTOR, "[type='submit']").click()
# class
driver.find_element(By.CSS_SELECTOR, ".s_btn").click()
# 标签属性
driver.find_element(By.CSS_SELECTOR, "a[href='https://www.hao123.com?src=from_pc_logon']").click()
# 模糊匹配-包含
driver.find_element(By.CSS_SELECTOR, "a[href*='image.baidu.com']").click()
# 模糊匹配-开头
driver.find_element(By.CSS_SELECTOR, "a[href^='https://image.baidu']").click()
# 模糊匹配-尾部
driver.find_element(By.CSS_SELECTOR, "a[href$='image.baidu.com/']").click()
# 组合定位
driver.find_element(By.CSS_SELECTOR, "input.s_ipt").send_keys("软件测试")
# 点击新闻
driver.find_element(By.CSS_SELECTOR, ".s-top-left-new.s-isindex-wrap>a").click()
driver.find_element(By.CSS_SELECTOR, "div#s-top-left a").click()
driver.find_element(By.CSS_SELECTOR, "#s-top-left a").click()
# 点击地图
driver.find_element(By.CSS_SELECTOR, "#s-top-left a:nth-child(3)").click()
driver.find_elements(By.CSS_SELECTOR, "#s-top-left a")[2].click()
# 第一个元素
driver.find_element(By.CSS_SELECTOR, "#s-top-left a:first-child").click()
# 最后一个元素
driver.find_element(By.CSS_SELECTOR, "#s-top-left a:last-child").click()

sleep(3)

6.8 By.XPATH

  • xpath 是一门在 XML 文档中查找信息的语言

  • XML 是可扩展标记语言,主要用于传输数据

  • 为什么可以使用 xpath 定位 html?

    • XPath 是一种用于在 XML 文档中定位元素的语言

    • 虽然 XML 和 HTML 是两种不同的标记语言,但 HTML 可以视为 XML 文档的一种特定形式

    • HTML 文档的结构和标签嵌套遵循 XML 的基本规则,因此 XPath 可以有效地在 HTML 文档中定位元素

    • XPath 定位 HTML 的基本原则是,将 HTML 文档视为 XML 文档,并使用 XPath 表达式来描述元素的位置关系

    • XPath 表达式可以使用标签名、属性、父子关系、索引等来选择特定的元素或元素集合

  • XPath 可以通过相对路径和绝对路径去定位元素,绝对路径从 HTML 根节点开始算,相对路径从任意节点开始

  • 不推荐使用绝对路径,写起来太麻烦了

说明 举例
从根节点开始选取(绝对路径) /html/div/
从任意节点开始选取(相对路径) //div,列举出所有 div 标签
选取当前节点的父节点 //input/.. 会选取 input 的父节点
选取属性或根据属性选取
使用 id 属性定位 //div[@id='id_value']
使用 class 属性定位(有多个值时,需要全部填写) //a[@class="mnav"]
使用 name 属性定位 //div[@name='wd']
多个属性定位 //input[@name="wd" and @class="s_ipt"]
第 n 个元素,使用 index 定位 //div[@id="s-top-left"]/a[3]
最后一个元素 //a[@class="mnav"][last()]
属性包含某字段 //div[contains(@title, 'text')]
属性以某字段开头 //div[starts-with(@title, 'text')]
属性以某字段结尾 //div[ends-with(@title, 'text')]
文本包含 //a[contains(text(), "网盘")]
文本等于 //span[text() = "菜单"]
同级弟弟元素 //div[@id=='id']/following-sibling::div
同级哥哥元素 //div[@id=='id']/preceding-sibling::div
  • 示例 1:
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.baidu.com")
# 绝对路径
driver.find_element(By.XPATH, '/html/body/div/div/div[3]/a').click()
# 根据ID定位
driver.find_element(By.XPATH, '//input[@id="kw"]').send_keys("selenium")
driver.find_element(By.XPATH, '//input[@id="su"]').click()
# 根据class定位
driver.find_element(By.XPATH, '//input[@class="s_ipt"]').send_keys("selenium")
# 根据name定位
driver.find_element(By.XPATH, '//input[@name="wd"]').send_keys("selenium")
# 多个属性组合定位
driver.find_element(By.XPATH, '//input[@name="wd" and @class="s_ipt"]').send_keys("selenium")
# 多数据使用下标定位
driver.find_element(By.XPATH, '//div[@id="s-top-left"]/a[4]').click()
# 通过子元素找父元素
driver.find_element(By.XPATH, '//div[@id="s-top-left"]/../div[3]/a[1]').click()
# 根据span文本内容定位
driver.find_element(By.XPATH, '//span[text() = "“退钱哥”公开应聘足球社会监督员"]').click()
# 根据文本包含
driver.find_element(By.XPATH, '//span[contains(text(), "退钱哥")]').click()
sleep(10)
  • 示例 2:
driver = webdriver.Chrome()
driver.maximize_window()
# driver.get("https://element.eleme.cn/#/zh-CN/component/cascader")
driver.get("https://baidu.com")
# 同级弟弟
# driver.find_element(By.XPATH, "//span[contains(text(),'默认 click 触发子菜单')]/following-sibling::div/div/input").click()
# 同级哥哥(1是离最近的哥哥,数字越大,就离越远)
driver.find_element(By.XPATH, "//a[text()='贴吧']/preceding-sibling::a[1]").click()
sleep(3)

7. Web 元素

7.1 交互

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://www.selenium.dev/selenium/web/inputs.html")
# 清空元素内容
driver.find_element(By.NAME, "email_input").clear()
# 输入内容
driver.find_element(By.NAME, "email_input").send_keys("admin@localhost.dev")
# 点击
driver.find_element(By.NAME, "color_input").click()

7.2 关于元素的信息

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://www.selenium.dev/selenium/web/inputs.html")
# 是否显示
is_email_visible = driver.find_element(By.NAME, "email_input").is_displayed()
# 是否启用
value = driver.find_element(By.NAME, 'button_input').is_enabled()
# 是否被选定
value2 = driver.find_element(By.NAME, "checkbox_input").is_selected()
# 获取特性或属性
email_txt = driver.find_element(By.NAME, "email_input")
value_info = email_txt.get_attribute("value")
# 获取文本内容
driver.get("https://www.selenium.dev/selenium/web/linked_image.html")
text = driver.find_element(By.ID, "justanotherLink").text

print(is_email_visible)
print(value)
print(value2)
print(value_info)
print(text)

driver.quit()

8. 浏览器交互

8.1 获取浏览器信息

title = driver.title    # 获取浏览器标题
url = driver.current_url    # 获取当前url

8.2 导航

driver.forward()	# 前进
driver.back()		# 后退
driver.refresh()	# 刷新

8.3 弹框

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


def setup():
    driver = webdriver.Chrome()
    driver.get("https://www.selenium.dev/documentation/webdriver/interactions/alerts/")
    return driver


def teardown(driver):
    driver.quit()


def test_alert():
    driver = setup()
    element = driver.find_element(By.LINK_TEXT, "See an example alert")
    element.click()
    sleep(3)

    wait = WebDriverWait(driver, timeout=2)
    alert = wait.until(lambda d: d.switch_to.alert)
    text = alert.text
    alert.accept()
    assert text == "Sample alert"


def test_confirm():
    driver = setup()
    element = driver.find_element(By.LINK_TEXT, "See a sample confirm")
    driver.execute_script("arguments[0].click();", element)
    sleep(3)

    wait = WebDriverWait(driver, timeout=2)
    alert = wait.until(lambda d: d.switch_to.alert)
    text = alert.text
    alert.dismiss()
    assert text == "Are you sure?"


def test_prompt():
    driver = setup()
    element = driver.find_element(By.LINK_TEXT, "See a sample prompt")
    driver.execute_script("arguments[0].click();", element)

    wait = WebDriverWait(driver, timeout=2)
    alert = wait.until(lambda d: d.switch_to.alert)
    alert.send_keys("Selenium")
    text = alert.text
    alert.accept()
    assert text == "What is your tool of choice?"
  • 其中driver.execute_script("arguments[0].click();", element)

    • driver.execute_script():用于在当前页面上执行 JavaScript 代码

    • "arguments[0].click();":传递给execute_script()的 JavaScript 代码。arguments[0] 是一个占位符,表示传递给execute_script()方法的第一个参数

    • element:作为 JavaScript 中 arguments[0] 的值传入

  • 相当于:element.click();

9. 定位实战

9.1 单选框 radio 定位

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.iviewui.com/view-ui-plus/component/form/radio")

# 根据按钮点击
driver.find_elements(By.XPATH, "//input[@class='ivu-radio-input' and @type='radio']")[1].click()
sleep(1)
driver.find_elements(By.XPATH, "//input[@class='ivu-radio-input' and @type='radio']")[2].click()
sleep(1)
driver.find_elements(By.XPATH, "//input[@class='ivu-radio-input' and @type='radio']")[3].click()
sleep(2)
# 点击文本
driver.find_element(By.XPATH, "//span[text()='Android']").click()
sleep(1)
driver.find_element(By.XPATH, "//span[text()='Windows']").click()
sleep(1)
driver.find_element(By.XPATH, "//span[text()='Android']/preceding-sibling::span/input").click()
sleep(1)

driver.close()

9.2 CheckBox 多选框定位

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.iviewui.com/view-ui-plus/component/form/checkbox")

# driver.find_element(By.XPATH, "//span[text()='香蕉']").click()
# sleep(1)
# driver.find_element(By.XPATH, "//span[text()='苹果']").click()
# sleep(1)
# driver.find_element(By.XPATH, "//span[text()='西瓜']").click()
# sleep(1)

driver.find_element(By.XPATH, "//span[text()='香蕉']/preceding-sibling::span/input").click()
sleep(1)
driver.find_element(By.XPATH, "//span[text()='苹果']/preceding-sibling::span/input").click()
sleep(1)
driver.find_element(By.XPATH, "//span[text()='西瓜']/preceding-sibling::span/input").click()
sleep(1)

driver.close()

9.3 Select 下拉框定位

  • Select 下拉框
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://sahitest.com/demo/selectTest.htm")

se = Select(driver.find_element(By.ID, "s1"))
sleep(1)
# 根据index下标获取,从0开始
se.select_by_index(1)
sleep(2)
# 根据option的value进行选择
se.select_by_value("50")
sleep(2)
# 根据option的文本内容进行选择
se.select_by_visible_text("Cell Phone")
sleep(2)

driver.close()
  • 非 Select 下拉框
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.iviewui.com/view-ui-plus/component/form/select")

driver.find_element(By.XPATH, "//div[@tabindex='0']").click()
sleep(2)
driver.find_elements(By.XPATH, "//div[@tabindex='0']/following-sibling::div/ul[2]/li")[1].click()
sleep(2)

driver.close()

9.4 联级选择器定位

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.iviewui.com/view-ui-plus/component/form/cascader")

driver.find_element(By.XPATH, "//input[@placeholder='请选择']").click()
sleep(1)
driver.find_element(By.XPATH, "//li[contains(text(), '北京')]").click()
sleep(1)
driver.find_element(By.XPATH, "//li[contains(text(), '故宫')]").click()
sleep(1)

driver.close()

9.5 日期选择器定位

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://www.iviewui.com/view-ui-plus/component/form/date-picker")

driver.find_element(By.XPATH, "//input[@class='ivu-input ivu-input-default ivu-input-with-suffix']").send_keys("2024-08-15")
sleep(1)

driver.find_elements(By.XPATH, "//input[@class='ivu-input ivu-input-default ivu-input-with-suffix']")[1].send_keys("2024-08-27 - 2024-09-30")
sleep(1)

driver.close()

9.6 弹框(Alert、confirm、prompt)

  • alert
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://sahitest.com/demo/alertTest.htm")

driver.find_element(By.NAME, "b1").click()
# 使用alert.text获取弹框文本
print(driver.switch_to.alert.text)
sleep(1)
# 点击确定
driver.switch_to.alert.accept()
driver.close()
  • confirm
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://sahitest.com/demo/confirmTest.htm")

driver.find_element(By.NAME, "b1").click()
# 获取弹框文本
print(driver.switch_to.alert.text)
sleep(1)
# 点击确定
driver.switch_to.alert.accept()
# 点击取消
driver.switch_to.alert.dismiss()
sleep(1)

driver.close()
  • prompt
from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://sahitest.com/demo/promptTest.htm")

driver.find_element(By.NAME, "b1").click()
# 输入文字
driver.switch_to.alert.send_keys("测试alert")
sleep(1)
# 点击确定
driver.switch_to.alert.accept()
# 点击取消
driver.switch_to.alert.dismiss()
sleep(1)

driver.close()

9.7 文件上传 upload

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://sahitest.com/demo/php/fileUpload.htm")

upload = driver.find_element(By.ID, "file")
upload.send_keys(r"E:\Code\PythonProjects\test\selenium\file\xx.jpg")
sleep(1)
driver.find_element(By.NAME, "submit").click()
sleep(1)

driver.close()

9.8 获取具有焦点的 DOM 元素

from time import sleep

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")

# 获取具有焦点的 DOM 元素
attr = driver.switch_to.active_element.get_attribute("title")
print(attr)
posted @ 2024-12-05 01:03  iRuriCatt  阅读(8)  评论(0编辑  收藏  举报