selenium自动化零基础学习
selenium简介
selenium是一款用于web浏览器的自动化工具,支持各大主流浏览器和编程语言。通过自动化代码可以模拟人的操作行为,如点击,输入等操作
selenium下载
pip install selenium
可以直接打开终端下载,因为新版本的selenium4.0会自动检索你电脑上的浏览器和版本,然后下载对应的驱动,不过也可以自己手动去浏览器下载对应版本的浏览器驱动(例如谷歌浏览器驱动,和edge浏览器驱动)
接下来,举一个例子作为开篇讲解
# 1. 导入Selenium的浏览器驱动工具
from selenium import webdriver
# 2. 导入元素定位工具(用来找网页上的输入框、按钮)
from selenium.webdriver.common.by import By
# 3. 导入时间等待工具(让程序暂停,给网页加载时间)
from time import sleep
# 4. 创建Edge浏览器的“控制器”
driver = webdriver.Edge()
# 5. 让浏览器打开百度网址
driver.get("https://www.baidu.com")
# 6. 程序暂停1秒(等待网页加载)
sleep(1)
# 7. 找到输入框 → 输入文字 selenium
driver.find_element(By.ID,"chat-textarea").send_keys("selenium")
# 8.点击搜索
driver.find_element(By.ID,"chat-submit-button").click()
# 9. 再暂停1秒(能看到输入效果)
sleep(1)
selenium元素定位
1.通过ID定位
通过selenium自动化工具打开的百度,可以看到它的搜索的标签是<textarea>,id=chat-textarea所以最终的效果就是打开edge浏览器->打开百度网页->在百度输入框输入selenium
2.通过NAME和CLASS_NAME
# 1. 导入Selenium浏览器驱动,用来控制Edge/Chrome浏览器
from selenium import webdriver
# 2. 导入元素定位工具,并重命名为by(用来找网页上的输入框、按钮)
from selenium.webdriver.common.by import By as by
# 3. 导入等待工具,让程序暂停,给网页加载时间
from time import sleep
# 4. 启动Edge浏览器,创建控制器driver(自动化机器人)
driver=webdriver.Edge()
# 5. 让机器人打开百度首页
driver.get("https://www.baidu.com")
# 6. 程序暂停1秒,等待页面初步加载
sleep(1)
# 7. 浏览器窗口最大化(全屏显示,防止元素被遮挡)
driver.maximize_window()
# 8. 程序暂停3秒,等待页面完全加载
sleep(3)
# 9. 通过类名找到百度聊天输入框,并自动输入文字python
driver.find_element(by.CLASS_NAME,"chat-input-scroll-style").send_keys("python")
# 10. 程序暂停3秒,方便查看输入效果
sleep(3)
3.通过TAG_NAME定位
写法如上,只不过通过标签名来定位
4.通过LINK_TEXT和PARTIAL_LINK_TEXT定位
这是通过<a></a>标签来定位的,也就是通过超链接来定位
例子(百度首页)
链接文字是:新闻你写 **“新”、“闻”、“新闻”** 都能找到:
# 必须写完整的“新闻”,才能找到
driver.find_element(By.LINK_TEXT, "新闻").click()
# 包含“新”字就能匹配到新闻链接
driver.find_element(By.PARTIAL_LINK_TEXT, "新").click()
但是link_text是精确匹配,partial_link_text是模糊匹配的,但是如果模糊查询不准确的话存在多个的话,程序会报错
5.通过CSS_SELECTOR定位
这是通过css选择器定位
by.CSS_SELECTOR
- 意思:使用 CSS 选择器 定位网页元素
- CSS 选择器是 Selenium 里最灵活、最强大的定位方式
- 可以按:标签、class、id、元素属性、模糊匹配 来找元素
| 选择器类型 | 语法 | 前端 HTML 示例 | CSS 选择器写法 | 说明 |
|---|---|---|---|---|
| ID 选择器 | #id值 | <input id="kw"> | #kw | 最快、唯一,首选! |
| 类选择器 | .class值 | <button class="s_btn"> | .s_btn | 匹配 class 属性,可重复 |
| 标签选择器 | 标签名 | <input> | input | 匹配标签,范围大 |
| 属性选择器 | [属性="值"] | <input name="wd"> | [name="wd"] | 匹配自定义属性 |
| 组合选择器 | 标签 + 属性 / ID | <input id="kw"> | input#kw | 最精准、最常用 |
例如
from selenium import webdriver
from selenium.webdriver.common.by import By as by
from time import sleep
driver=webdriver.Edge()
driver.get("http://www.baidu.com")
sleep(1)
driver.maximize_window()
sleep(3)
driver.find_element(by.CSS_SELECTOR,"#chat-textarea").send_keys("什么是软件测试")
sleep(3)
css属性匹配三剑客
[herf^="http"] ->以http开头
[herf$="com"] ->以com结尾
[herf*='unf'] ->包含unf字符
子代选择器和后代选择器
# 1. 导入浏览器驱动工具
from selenium import webdriver
# 2. 导入元素定位工具,重命名为by
from selenium.webdriver.common.by import By as by
# 3. 导入等待工具
from time import sleep
# 4. 启动Edge浏览器
driver=webdriver.Edge()
# 5. 打开百度首页
driver.get("http://www.baidu.com")
# 6. 等待1秒,页面初步加载
sleep(1)
# 7. 浏览器窗口最大化
driver.maximize_window()
# 8. 等待3秒,页面完全加载
sleep(3)
# 9. 核心:批量定位百度左上角所有导航链接(新闻、地图、视频等)
elements=driver.find_elements(by.CSS_SELECTOR,"div#s-top-left>a")
# 10. 循环遍历每一个找到的链接
for element in elements:
# 11. 打印链接上显示的文字
print(element.text)
# 12. 等待3秒
sleep(3)
elements=driver.find_elements(by.CSS_SELECTOR,"div#s-top-left>a")讲解
div#s-top-left组合选择器,选择id为s-top-left的div标签
div#s-top-left>a选择id为s-top-left的div标签的直接子代选择器中的a标签
例如百度的导航栏
<div id="s-top-left">
<a>新闻</a> <!-- 亲儿子 -->
<a>地图</a> <!-- 亲儿子 -->
</div>
注意区分div#s-top-left a(空格)
这是子代选择器(亲儿子,孙子,重孙子),匹配范围更大一些
from selenium import webdriver
from selenium.webdriver.common.by import By as by
from time import sleep
driver=webdriver.Edge()
driver.get("http://www.baidu.com")
sleep(1)
driver.maximize_window()
sleep(3)
# 定位地图链接紧跟着的后面的a标签
elements=driver.find_element(by.CSS_SELECTOR,"a[href='http://map.baidu.com']+a")
# 打印上述标签的属性值
print(elements.get_attribute("href"))
sleep(3)
# 打印标签的属性值
get_attribute()
# 导入浏览器控制工具
from selenium import webdriver
# 导入元素定位工具,重命名为by
from selenium.webdriver.common.by import By as by
# 导入等待工具
from time import sleep
# 启动Edge浏览器
driver=webdriver.Edge()
# 打开百度首页
driver.get("http://www.baidu.com")
# 等待1秒,页面初步加载
sleep(1)
# 浏览器窗口最大化
driver.maximize_window()
# 等待3秒,页面完全加载
sleep(3)
# 【核心新知识点】CSS通用兄弟选择器:找到地图链接 后面所有的同级链接
elements=driver.find_elements(by.CSS_SELECTOR,"a[href='http://map.baidu.com']~a")
# 循环遍历所有找到的链接
for element in elements:
# 打印每个链接的文字
print(element.text)
# 等待3秒
sleep(3)
XPATH定位
绝对路径(不推荐)
从顶层的html一层一层的往下写一层一层、从上到下写完整的层级路径,以 单斜杠 / 开头。
例如定位右上角的新闻标签,一步一步都不能出错:/html/body/div[1]/div[1]/div[1]/div[1]/a[3]
而且代码结构一改,就会报错
相对路径(推荐)
不从根节点开始,直接匹配页面中符合条件的元素,以 双斜杠 // 开头,灵活、稳定。
//标签名[@属性="属性值"]/子标签
from selenium import webdriver
from selenium.webdriver.common.by import By as by
from time import sleep
driver=webdriver.Edge()
driver.get("http://www.baidu.com")
sleep(1)
driver.maximize_window()
sleep(3)
driver.find_element(by.XPATH,"//div[@id='s-top-left']/a[1]").click()
sleep(3)
通过文字定位
from selenium import webdriver
from selenium.webdriver.common.by import By as by
from time import sleep
driver=webdriver.Edge()
driver.get("http://www.baidu.com")
sleep(1)
driver.maximize_window()
sleep(3)
driver.find_element(by.XPATH,"//*[text()='换一换']").click()
sleep(3)
这是最关键的部分,拆成 4 个知识点:
1.//
XPath 相对路径
2.*
匹配所有标签(不管是 a 标签、span 标签、button 标签,全都找)
不过还是建议少用通配符*,容易匹配看不见的垃圾元素
3.[]
XPath 筛选条件(相当于:满足 xxx 条件的元素)
4.text()='换一换'
按文字匹配:找到页面显示文字完全等于 换一换 的元素
✅ 整句翻译:在整个网页里,查找 任何标签中,文字正好是「换一换」的元素
click():对找到的元素执行 点击操作
这里需要区分的是,什么时候有@?
@是给标签属性用的,例如:
<a id="kw" class="s_btn" href="http://xxx">百度一下</a>
这里的id,class,herf都是标签属性,而
<span>换一换</span>
这里的换一换是属于标签文本,不用加@
文本模糊匹配
driver.find_element(by.XPATH,"//span[contains(text(),'奋力谱写')]").click()
selenium基础操作
# 1. 导入浏览器驱动,控制Edge
from selenium import webdriver
# 2. 导入元素定位工具,重命名为by
from selenium.webdriver.common.by import By as by
# 3. 导入键盘按键工具(模拟回车、空格、删除等)
from selenium.webdriver.common.keys import Keys
# 4. 导入等待工具
from time import sleep
# 5. 启动Edge浏览器
driver=webdriver.Edge()
# 6. 打开百度首页
driver.get("http://www.baidu.com")
# 7. 等待1秒,页面初步加载
sleep(1)
# 8. 窗口最大化
driver.maximize_window()
# 9. 等待3秒,页面完全加载
sleep(3)
# 10. 找到百度AI输入框,把这个元素存到变量textarea里(方便重复使用)
textarea=driver.find_element(by.ID,"chat-textarea")
# 11. 向输入框中输入文字:什么是python自动化?
textarea.send_keys("什么是python自动化?")
# 12. 等待3秒,查看输入效果
sleep(3)
# 13. 核心!模拟键盘【回车键】,提交问题(替代点击按钮)
textarea.send_keys(Keys.ENTER)
# 14. 等待3秒,查看搜索结果
sleep(3)
更高级的等待方式
我们之前用的sleep(3)是 强制等待:不管元素加载没加载好,死等 3 秒,浪费时间
但是我们现在用更高级的只能等待
# 1. 导入浏览器驱动(控制Edge)
from selenium import webdriver
# 2. 导入元素定位工具(By.ID/CSS_SELECTOR)
from selenium.webdriver.common.by import By
# 3. 导入【显式等待】核心类(智能等待工具)
from selenium.webdriver.support.ui import WebDriverWait
# 4. 导入等待条件(判断元素是否出现、可点击等)
from selenium.webdriver.support import expected_conditions as EC
# 5. 启动Edge浏览器
driver = webdriver.Edge()
# 6. 打开百度首页
driver.get("http://www.baidu.com")
# 7. 窗口最大化(避免元素遮挡)
driver.maximize_window()
# ===================== 核心新知识:显式等待 =====================
# 8. 创建等待对象:最多等10秒,每0.5秒检查一次条件
wait = WebDriverWait(driver, 10)
# 9. 等待【输入框元素出现】,出现后立即返回元素,不浪费时间
input_box = wait.until(EC.presence_of_element_located((By.ID, "chat-textarea")))
# 10. 向输入框输入文字
input_box.send_keys("什么是selenium自动化?")
# 11. 等待【提交按钮可点击】,满足条件后再点击(彻底解决报错!)
submit_btn = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button#chat-submit-button")))
# 12. 点击按钮
submit_btn.click()
# 后续操作...
WebDriverWait是一个等待工具,我们创建一个等待对象,最多等10秒,超过十秒则报错
EC则是一个判断条件,满足了立马执行,不会浪费时间,例如:
|
|---|
selenium基本操作
截图+获取网页名
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By as by, By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver=webdriver.Edge()
wait=WebDriverWait(driver,10)
driver.get("http://www.baidu.com")
driver.maximize_window()
input_box=wait.until(EC.presence_of_element_located((By.ID,"chat-textarea")))
input_box.send_keys("什么是python自动化?")
input_box.send_keys(Keys.ENTER)
sleep(5)
url1=driver.current_url
print(url1)
print(driver.title) #打印网页名
driver.save_screenshot("搜索界面截图.png") # 截图当前页面并且命名
driver.quit()
窗口切换
元素找不到的原因之一:要定位的元素不在当前页面,需要切换窗口
Selenium 默认只停留在原来的百度首页,不会自动切换到新标签
点击百度首页的新闻后,浏览器会新开一个标签页
-
Selenium 默认停留在原百度首页,不会自动切换
-
必须用
driver.window_handles获取所有标签页 ID -
用
driver.switch_to.window(title[-1])切换到新标签页
# 1. 导入固定等待工具
from time import sleep
# 2. 导入浏览器驱动
from selenium import webdriver
# 3. 导入元素定位工具
from selenium.webdriver.common.by import By
# 4. 导入键盘工具(本段未使用)
from selenium.webdriver.common.keys import Keys
# 5. 导入显式等待(智能等待)
from selenium.webdriver.support.ui import WebDriverWait
# 6. 导入等待条件
from selenium.webdriver.support import expected_conditions as EC
# 7. 启动Edge浏览器
driver=webdriver.Edge()
# 8. 创建智能等待器:最长等待10秒
wait=WebDriverWait(driver,10)
# 9. 打开百度首页
driver.get("http://www.baidu.com")
# 10. 窗口最大化
driver.maximize_window()
# 11. 【核心1】等待元素出现 → 模糊匹配文字含"新"的链接(新闻)→ 点击
# 点击后会**自动打开新标签页**
wait.until(EC.presence_of_element_located((By.PARTIAL_LINK_TEXT,"新"))).click()
# 12. 【核心2】获取浏览器**所有标签页/窗口的唯一标识**(窗口句柄)
handls=driver.window_handles
# 13. 打印所有窗口句柄(列表格式,看有几个标签页)
print(handls)
# 14. 【核心3】切换到**最后一个打开的新标签页**
driver.switch_to.window(handls[-1])
# 15. 在新的新闻标签页中,找到含"苦练内功"的链接并点击
wait.until(EC.presence_of_element_located((By.PARTIAL_LINK_TEXT,"苦练内功"))).click()
# 16. 等待3秒,查看效果
sleep(3)
# 17. 关闭浏览器,结束程序
driver.quit()
窗口滚动
绝对滚动
# 导入固定等待工具
from time import sleep
# 导入浏览器驱动
from selenium import webdriver
# 导入元素定位工具
from selenium.webdriver.common.by import By
# 导入键盘工具(本段代码没用到,可删)
from selenium.webdriver.common.keys import Keys
# 导入智能等待(显式等待)
from selenium.webdriver.support.ui import WebDriverWait
# 导入等待条件
from selenium.webdriver.support import expected_conditions as EC
# 1. 启动Edge浏览器
driver = webdriver.Edge()
# 2. 创建智能等待器:最长等待10秒,每隔0.5秒检查一次元素
wait=WebDriverWait(driver,10)
# 3. 打开百度首页(https加密版,更安全)
driver.get("https://www.baidu.com")
# 4. 浏览器窗口最大化,避免元素被遮挡
driver.maximize_window()
# 5. 智能等待:找到文字包含"新"的链接(新闻)→ 出现后立刻点击
# 点击后会【自动打开新的标签页:百度新闻】
wait.until(EC.presence_of_element_located((By.PARTIAL_LINK_TEXT,"新"))).click()
# 6. 获取浏览器【所有标签页的句柄(唯一ID)】,存入变量title
# 注意:变量名不规范,应该叫handles,不是title(title是网页标题)
title=driver.window_handles
# 7. 切换到【最新打开的标签页】(百度新闻页)
# title[-1] = 列表最后一个元素 = 刚打开的新闻标签页
driver.switch_to.window(title[-1])
# ===================== 新知识点:JS滚动页面 =====================
# 8. 编写JS代码:滚动到页面【最底部】
# window.scrollTo(横坐标0, 纵坐标100000) 数字越大滚得越下
js='window.scrollTo(0,100000)'
# 9. 驱动执行JS脚本,让页面滚动到底部
driver.execute_script(js)
# 10. 在新闻页面底部,智能等待找到包含"知道年轻人"的链接并点击
wait.until(EC.presence_of_element_located((By.PARTIAL_LINK_TEXT,"知道年轻人"))).click()
# 11. 等待3秒,查看点击效果
sleep(3)
# 12. 关闭整个浏览器,结束程序
driver.quit()
思考一个问题,为什么需要滚动?你去一个网页找一个链接,虽然说没在当前的可视的窗口,但是找不到吗?
要搞清楚这个问题,需要理解selenium的概念,模拟人的操作,如果是你,这个链接在这个页面的最底下(元素在屏幕之外),你当前看不到,你能点击吗?同理,你做不到的,selenium同样做不到
为什么写js代码?
js='window.scrollTo(0,100000)'
不是python代码,而是一段javascript代码,存成了一个字符串(浏览器指令)
driver.execute_script(js)
让selenium拿着这串JS指令,丢给浏览器去执行
python不会滚动页面,浏览器会JS,所以丢给浏览器自己去执行
scrollTo(x, y) 的意思
让页面滚动到:横向 x 像素、纵向 y 像素的位置
更标准写法
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
document.body.scrollHeight = 网页实际总高度
相对滚动
| 写法 | 名字 | 意思(人话) |
|---|---|---|
scrollTo(x,y) | 绝对位置滚动 | 直接跳到网页的 x,y 坐标处(不管现在在哪) |
scrollBy(x,y) | 相对位置滚动 | 在现在的位置基础上,再滚 x,y 像素 |
selenium嵌套页面
# 1. 导入所有需要的工具包
from selenium import webdriver # 控制浏览器
from selenium.webdriver.support.ui import WebDriverWait # 智能等待
from selenium.webdriver.support import expected_conditions as ec # 等待条件
from selenium.webdriver.common.by import By # 元素定位方式
from time import sleep # 强制等待
# 2. 初始化Chrome浏览器,窗口最大化,打开LOL官网下载页
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("https://lol.qq.com/download.shtml")
# 创建智能等待器,最长等10秒
wait = WebDriverWait(driver, 10)
# ===================== 第一步:点击登录按钮 =====================
# 等待【登录】按钮可点击 → 点击,弹出QQ登录弹窗
wait.until(ec.element_to_be_clickable((By.PARTIAL_LINK_TEXT, "登录"))).click()
sleep(3) # 等待弹窗加载完成
# ===================== 第二步:切换嵌套iframe(核心难点) =====================
# QQ登录弹窗**不是普通页面**,是嵌套在网页里的【iframe内嵌框架】
# 必须先切换进iframe,才能操作里面的元素
# 切换第一层iframe:根据class定位 loginframe
driver.switch_to.frame(wait.until(ec.presence_of_element_located((By.CLASS_NAME, "loginframe"))))
sleep(2)
# 切换第二层iframe:根据ID定位 ptlogin_iframe(双层嵌套)
driver.switch_to.frame(wait.until(ec.presence_of_element_located((By.ID, "ptlogin_iframe"))))
# ===================== 第三步:点击注册账号 =====================
# 现在已经进入iframe内部,可以找到并点击【注册账号】链接
wait.until(ec.element_to_be_clickable((By.LINK_TEXT, "注册账号"))).click()
sleep(3) # 等待新窗口打开
# ===================== 🔥 核心修复:退出iframe(你之前报错的根源) =====================
# 规则:只要进入了iframe,操作完成后**必须退出**!
# 切换新窗口不会自动退出iframe,不退出就找不到新页面的元素
driver.switch_to.default_content()
# ===================== 第四步:切换到新打开的注册窗口 =====================
# 点击注册后,浏览器新建了一个标签页,切换到最新的窗口
driver.switch_to.window(driver.window_handles[-1])
# 等待页面标题包含「QQ注册」,确认页面加载完成
wait.until(ec.title_contains("QQ注册"))
# ===================== 第五步:填写QQ注册表单 =====================
# 1. 输入昵称:等待输入框可见 → 输入内容
wait.until(ec.visibility_of_element_located((By.CSS_SELECTOR, "input.content-input[placeholder='输入昵称']"))).send_keys("没钱的弹药库")
# 2. 输入QQ密码
wait.until(ec.visibility_of_element_located((By.CSS_SELECTOR, "input[placeholder='输入QQ密码']"))).send_keys("WYH20050916")
# 3. 输入手机号
wait.until(ec.visibility_of_element_located((By.CSS_SELECTOR, "input[placeholder='输入手机号码']"))).send_keys("15099729257")
# 勾选用户协议(等待可点击 → 点击)
wait.until(ec.element_to_be_clickable((By.CSS_SELECTOR, "div.q-checkbox__icon"))).click()
# 点击【创建账号】按钮
wait.until(ec.element_to_be_clickable((By.CSS_SELECTOR, "div[dt-eid='em_bas_create_account_btn']"))).click()
# 等待3秒查看效果,关闭浏览器
sleep(3)
driver.quit()
大家可以自己动手实操一下,实操的时候一定要去看网页的html的设计
什么叫内置框架iframe?
就类似于看视频中的画中画,一个网页中真真实实的嵌套一个小网页,这个小网页有着自己的html,就比如打开英雄联盟网页点击登录后弹出的 QQ 登录窗口 = iframe 内嵌网页,这个登录窗口不是官网自己写的,而是直接把腾讯的登录qq.com嵌入进来
易错点
Selenium 操作网页,有 两个完全独立、互不干扰的定位权限:
-
窗口定位:你在哪个标签页(百度首页?新闻页?注册页?)
-
iframe 定位:你在当前标签页的哪个文档(主页面?内嵌 iframe?)
switch_to.window() 只改窗口定位,不改 iframe 定位!
-
只要进过 iframe,切换窗口前,必须退出 iframe
-
switch_to.window()只换标签页,不换 iframe 权限 -
switch_to.default_content()= 万能解锁,退出所有内嵌框架
下拉单选框
注意是select标签
<!DOCTYPE html>
<html>
<body>
<h3>城市选择下拉框</h3>
<!-- 原生select下拉框 -->
<select id="city">
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="gz">广州</option>
<option value="sz">深圳</option>
</select>
</body>
</html>

这是效果
from selenium import webdriver
from selenium.webdriver.common.by import By
# 导入Select类
from selenium.webdriver.support.ui import Select
from time import sleep
# 打开本地下拉框测试文件
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("file:///E:/python_Demo/PyCharm_Demo1/select_test.html")
sleep(1)
# 1. 定位【原生下拉框<select>】
ele = driver.find_element(By.ID, "city")
# 2. 创建Select对象
s = Select(ele)
# ==================== 三个选择方法演示 ====================
# 方法1:按索引选(第1个=0,北京)
s.select_by_index(0)
sleep(1)
# 方法2:按value选(value="sh",上海)
s.select_by_value("sh")
sleep(1)
# 方法3:按可见文字选(页面显示"深圳")
s.select_by_visible_text("深圳")
sleep(2)
driver.quit()
系统弹窗管理
下载atolt工具,可以定位弹窗属性
from pywinauto.findwindows import find_element
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.common.by import By
from time import sleep
from selenium.webdriver.edge.options import Options
from pywinauto import Desktop
edge_options = Options()
# 创建Edge浏览器对象
driver = webdriver.Edge(options=edge_options)
try:
# 最大化浏览器窗口
driver.maximize_window()
# 打开登录页面
driver.get("https://v5.crmeb.net/admin/login?redirect=%2Fadmin%2Findex")
# 创建等待对象
wait=WebDriverWait(driver, 10)
driver.find_element(By.TAG_NAME,"button").click()
wait.until(ec.visibility_of_element_located((By.XPATH,"//div[@class='open-image']/img"))).click()
sleep(2)
wait.until(ec.element_to_be_clickable((By.XPATH,"//ul/li[@title='商品']"))).click()
sleep(3)
wait.until(ec.element_to_be_clickable((By.XPATH,"//span[text()='商品分类']"))).click()
wait.until(ec.element_to_be_clickable((By.XPATH, "//span[text()='添加分类']"))).click()
wait.until(ec.element_to_be_clickable((By.XPATH, "//div/i[@class='el-icon-picture-outline']"))).click()
ele=driver.find_element(By.TAG_NAME,"iframe")
driver.switch_to.frame(ele)
wait.until(ec.element_to_be_clickable((By.XPATH, "//span[text()='上传图片']"))).click()
path = r"E:\python_Demo\PyCharm_Demo1\1.png"
wait.until(ec.presence_of_element_located((By.XPATH, "//i[@class='el-icon-plus']"))).click()
sleep(2)
app=Desktop ()
app['打开']['Edit'].type_keys(path)
sleep(3)
app['打开']['Button'].click()
sleep(3)
driver.switch_to.default_content()
finally:
driver.quit()

selenium鼠标移动操作
在UI设计中,如果遇到一个标签,鼠标悬停的时候,属性改变了,这就是设置了:hover伪类.,例如:
/* 默认样式 */
.el-range__close-icon {
color: #C0C4CC; /* 浅灰 */
opacity: 0.6;
cursor: pointer;
}
/* 悬停样式 :hover 伪类 */
.el-range__close-icon:hover {
color: #606266; /* 深灰 */
opacity: 1;
transform: scale(1.1); /* 轻微放大 */
}
这个时候就需要代码模拟鼠标操作
# 1. 导入Selenium必备库:操控浏览器
from selenium import webdriver
# 显式等待:等待元素加载完成再操作
from selenium.webdriver.support.ui import WebDriverWait
# 等待条件:元素可见、可点击等
from selenium.webdriver.support import expected_conditions as ec
# 元素定位方式:ID、XPATH、CSS等
from selenium.webdriver.common.by import By
# 强制等待:固定暂停几秒
from time import sleep
# Edge浏览器配置选项
from selenium.webdriver.edge.options import Options
# 鼠标操作库:模拟鼠标悬停、点击、拖拽等
from selenium.webdriver.common.action_chains import ActionChains
# 2. 配置Edge浏览器(空配置,默认启动)
edge_options = Options()
# 3. 创建Edge浏览器对象,启动浏览器
driver = webdriver.Edge(options=edge_options)
# try语句:包裹核心代码,无论是否报错,最终都会执行finally关闭浏览器
try:
# 浏览器窗口最大化,避免元素被遮挡
driver.maximize_window()
# 打开CRMEB商城后台登录页面
driver.get("https://v5.crmeb.net/admin/login?redirect=%2Fadmin%2Findex")
# 创建显式等待对象:最多等待10秒,直到元素出现
wait = WebDriverWait(driver, 10)
# ===================== 【问题代码】登录操作(错误) =====================
# 直接点击页面第一个button按钮,未输入账号密码,登录会失败
driver.find_element(By.TAG_NAME,"button").click()
# 点击一个无关的图片元素,无实际作用
wait.until(ec.visibility_of_element_located((By.XPATH,"//div[@class='open-image']/img"))).click()
# 强制等待2秒,给页面加载时间
sleep(2)
# ===================== 点击左侧菜单 =====================
# 【问题代码】XPath错误:页面无ul直接包裹li,可能定位失败
# 等待【订单】菜单可点击,然后点击
wait.until(ec.element_to_be_clickable((By.XPATH,"//ul/li[@title='订单']"))).click()
sleep(3)
# 等待【订单统计】可点击,点击进入页面
wait.until(ec.element_to_be_clickable((By.XPATH,"//span[text()='订单统计']"))).click()
sleep(3)
# ===================== 核心:鼠标操作清空日期框 =====================
# 实例化鼠标操作对象
action_chains = ActionChains(driver)
# 定位日期框的【清空图标】(就是你问的hover变化的i标签)
ele = driver.find_element(By.XPATH,"//i[@class='el-input__icon el-range__close-icon']")
# 鼠标操作:移动到图标上 → 暂停1秒 → 点击图标 → 执行操作
action_chains.move_to_element(ele).pause(1).click(ele).perform()
# ===================== 定位只读日期输入框 =====================
# 等待【开始日期】输入框可见,并赋值给变量
start_date_input = wait.until(ec.visibility_of_element_located((By.XPATH, "//input[@placeholder='开始日期']")))
print("开始日期输入框已定位")
# 等待【结束日期】输入框可见,并赋值给变量
end_date_input = wait.until(ec.visibility_of_element_located((By.XPATH, "//input[@placeholder='结束日期']")))
# ===================== 核心:JS破解readonly属性+赋值日期 =====================
# 执行JS:移除开始日期框的readonly只读属性 → 赋值日期2026/03/17
driver.execute_script("arguments[0].removeAttribute('readonly'); arguments[0].value = '2026/03/17';", start_date_input)
print("开始日期已设置为2026/03/17")
# 执行JS:移除结束日期框的readonly只读属性 → 赋值日期2026/03/24
driver.execute_script("arguments[0].removeAttribute('readonly'); arguments[0].value = '2026/03/24';", end_date_input)
print("结束日期已设置为2026/03/24")
# 强制等待3秒,查看效果
sleep(3)
# 无论代码是否报错,最终都会执行:关闭浏览器
finally:
driver.quit()
ActionChains(driver):创建鼠标操作链move_to_element(ele):鼠标悬停到清空图标上pause(1):悬停后暂停 1 秒click(ele):点击图标perform():执行整个鼠标操作(必须加,否则不生效)
driver.execute_script("JS代码", 元素)
常见的鼠标操作
| 鼠标操作方法 | 作用 | 工作常用场景 |
|---|---|---|
move_to_element(元素) | 鼠标悬停在元素上 | 下拉菜单、hover 显示按钮、你之前的清空小图标 |
click(元素) | 鼠标单击 | 点击按钮、菜单、图标 |
double_click(元素) | 鼠标双击 | 编辑文本、快捷打开、表格行双击 |
context_click(元素) | 鼠标右键单击 | 弹出右键菜单(复制、删除等) |
drag_and_drop(源, 目标) | 鼠标拖拽 | 滑块验证、列表排序、拖动模块 |
click_and_hold(元素) | 鼠标长按不松开 | 滑块拖动、长按加载 |
pause(秒数) | 鼠标动作暂停等待 | 动作之间留反应时间 |
PO模式
什么是PO模式?
Page Object模式,也就是页面对象模型,是自动化测试里工作必用,最核心的设计规范。通俗来讲,就是把每一个网页,单独封装成一个python类:
这个类里面只存当前页面的元素定位,操作方法,测试脚本/业务代码,只调用方法,不写任何定位
PO模式的核心三层结构
1.BasePage基类(公共父类)
封装所有页面的通用的方法:点击,输入,等待,切换iframe,鼠标操作等
# 导入显式等待类
from selenium.webdriver.support.ui import WebDriverWait
# 导入等待条件(可点击、可见等)
from selenium.webdriver.support import expected_conditions as ec
# 导入鼠标操作类(悬停、点击等)
from selenium.webdriver.common.action_chains import ActionChains
# 定义基础页面对象类,所有页面都继承这个类
class BasePage:
# 初始化方法,接收外部传入的浏览器驱动
def __init__(self, driver):
# 将传入的driver赋值给实例变量,供全类使用
self.driver = driver
# 创建显式等待对象,最大等待10秒
self.wait = WebDriverWait(driver, 10)
# 封装通用点击方法:等待元素可点击后点击
# locator:元素定位器(定位方式, 路径)
def click(self, locator):
# 等待元素可点击
element = self.wait.until(ec.element_to_be_clickable(locator))
# 执行点击操作
element.click()
# 封装通用输入方法:等待元素可见后输入文本
def input_text(self, locator, text):
# 等待元素可见
element = self.wait.until(ec.visibility_of_element_located(locator))
# 输入指定文本
element.send_keys(text)
# 封装通用JS赋值方法:破解readonly属性并赋值(日期框专用)
def js_set_value(self, locator, value):
# 等待元素可见
ele = self.wait.until(ec.visibility_of_element_located(locator))
# 执行JS代码:移除readonly属性 + 赋值
self.driver.execute_script(
"arguments[0].removeAttribute('readonly'); arguments[0].value = arguments[1];",
ele, # arguments[0] 对应第一个JS参数:元素对象
value # arguments[1] 对应第二个JS参数:要设置的值
)
# 封装通用鼠标悬停+点击方法(处理hover效果的图标)
def hover_click(self, locator):
# 等待元素可点击
ele = self.wait.until(ec.element_to_be_clickable(locator))
# 创建鼠标操作对象
actions = ActionChains(self.driver)
# 鼠标移动到元素上 + 暂停0.5秒 + 点击 + 执行操作
actions.move_to_element(ele).pause(0.5).click(ele).perform()
2.页面类(LoginPage,OrderPage)
·每一个页面对应一个类
·类里定义元素定位(变量存XPath/CSS)
·类里写页面的操作方法(login(),search_order(),set_date())
# 导入元素定位方式
from selenium.webdriver.common.by import By
# 导入基础父类
from pages.base import BasePage
# 登录页面类,继承BasePage
class LoginPage(BasePage):
# ===================== 页面元素定位(常量) =====================
# 用户名输入框:XPath定位
USER_INPUT = (By.XPATH, "//input[@placeholder='请输入用户名']")
# 密码输入框:XPath定位
PWD_INPUT = (By.XPATH, "//input[@placeholder='请输入密码']")
# 登录按钮:CSS定位
LOGIN_BTN = (By.CSS_SELECTOR, "button.el-button--primary")
# ===================== 页面操作方法 =====================
# 登录方法:接收账号和密码
def user_login(self, username, password):
# 调用父类方法:输入用户名
self.input_text(self.USER_INPUT, username)
# 调用父类方法:输入密码
self.input_text(self.PWD_INPUT, password)
# 调用父类方法:点击登录按钮
self.click(self.LOGIN_BTN)
# 导入元素定位方式
from selenium.webdriver.common.by import By
# 导入基础父类
from pages.base import BasePage
# 订单页面类,继承BasePage
class OrderPage(BasePage):
# ===================== 页面元素定位(常量) =====================
# 左侧订单菜单
ORDER_MENU = (By.XPATH, "//li[@title='订单']")
# 订单统计子菜单
ORDER_STATISTICS = (By.XPATH, "//span[text()='订单统计']")
# 日期清空图标
CLEAR_ICON = (By.CSS_SELECTOR, "i.el-range__close-icon")
# 开始日期输入框
START_DATE = (By.XPATH, "//input[@placeholder='开始日期']")
# 结束日期输入框
END_DATE = (By.XPATH, "//input[@placeholder='结束日期']")
# ===================== 页面操作方法 =====================
# 进入订单统计页面
def go_to_order_statistics(self):
# 点击订单菜单
self.click(self.ORDER_MENU)
# 点击订单统计子菜单
self.click(self.ORDER_STATISTICS)
# 设置订单查询日期
def set_order_date(self, start_date, end_date):
# 鼠标悬停点击清空图标
self.hover_click(self.CLEAR_ICON)
# JS赋值:设置开始日期
self.js_set_value(self.START_DATE, start_date)
# JS赋值:设置结束日期
self.js_set_value(self.END_DATE, end_date)
3.测试用例类
只做业务逻辑,完全不出元素定位,只调用页面类的方法
# 导入Edge浏览器驱动
from selenium import webdriver
# 导入登录页面类
from pages.login_page import LoginPage
# 导入订单页面类
from pages.order_page import OrderPage
# 导入强制等待(仅用于查看效果)
from time import sleep
# 程序主入口:只有直接运行此文件时,才执行内部代码
if __name__ == '__main__':
# ===================== 1. 初始化浏览器 =====================
# 创建Edge浏览器对象
driver = webdriver.Edge()
# 浏览器窗口最大化
driver.maximize_window()
# 打开CRMEB登录页面
driver.get("https://v5.crmeb.net/admin/login")
# ===================== 2. 执行业务流程:登录 =====================
# 实例化登录页面对象,传入driver
login_page = LoginPage(driver)
# 调用登录方法,输入账号密码
login_page.user_login("demo", "crmeb.com")
# 等待2秒,页面加载
sleep(2)
# ===================== 3. 执行业务流程:订单统计 =====================
# 实例化订单页面对象,传入driver
order_page = OrderPage(driver)
# 进入订单统计页面
order_page.go_to_order_statistics()
# 设置查询日期
order_page.set_order_date("2026/03/17", "2026/03/24")
# ===================== 4. 结束操作 =====================
# 等待3秒查看效果
sleep(3)
# 关闭浏览器
driver.quit()
使用PO模式的优点
易维护,可复用,代码清晰,解耦合,团队协作规范
pytest之测试夹具函数
什么是测试夹具(Fixture)?
测试夹具就是自动化的【前置准备+后置清理】工具函数
前置:测试开始前做的事(打开浏览器,初始化驱动,登录系统)
后置:测试结束后的事(关闭浏览器,清楚数据,退出登录)
写一次,所有的测试用例都能复用,不用重复写代码
核心语法:
装饰器:@pytest.fixture → 标记这是一个夹具函数
关键字 yield:
yield 之前 = 前置代码(测试前执行)
yield 之后 = 后置代码(测试后执行)
作用域:控制夹具执行次数
作用域
| 作用域 | 写法 | 含义 | 你的场景 |
|---|---|---|---|
| function(默认) | @pytest.fixture(scope="function") | 每个测试函数执行 1 次 | 每个用例都要重置状态 |
| class | scope="class" | 每个测试类执行 1 次 | 类内用例共享前置 |
| module | scope="module" | 每个.py文件执行 1 次 | 文件内用例共享 |
| session | scope="session" | 整个测试全程只执行 1 次 | ✅ Selenium 驱动全局唯一(必用) |
# 1. 导入需要的工具
import pytest # 测试框架:自动找用例、自动运行
from selenium import webdriver # 操控Edge浏览器
from selenium.webdriver.common.keys import Keys # 键盘按键(回车、空格等)
from selenium.webdriver.common.by import By # 元素定位方式(ID、XPATH等)
# ===================== 核心:测试夹具(全自动前置+后置) =====================
# @pytest.fixture:标记这是 pytest 专用的夹具函数
@pytest.fixture(scpoe='范围',autouse=True)
# 夹具函数名:driver(pytest 靠这个名字自动匹配用例参数)
def driver():
# ===================== 【前置代码】测试开始前自动执行 =====================
# 创建浏览器对象:打开 Edge 浏览器(变量名也叫 driver,是真正的浏览器)
driver = webdriver.Edge()
# 浏览器窗口最大化
driver.maximize_window()
# 自动打开百度官网
driver.get("https://www.baidu.com")
# ===================== 核心关键字:yield =====================
# 作用:暂停夹具,把「浏览器对象」返回给测试用例使用
yield driver
# ===================== 【后置代码】测试结束后自动执行 =====================
# 自动关闭浏览器(无论用例成功/失败,都会执行!)
driver.quit()
# ===================== 测试用例1:检查百度首页标题 =====================
# 函数以 test_ 开头 → pytest 自动识别为测试用例
# 参数 driver:自动接收 上面夹具 返回的「浏览器对象」
def test_baidu_title(driver):
# 获取当前网页的标题(百度首页顶部的文字)
title = driver.title
# 断言:判断 实际标题 == 预期标题,不相等就直接报错
assert title == "百度一下,你就知道"
# 断言通过后,打印提示
print("✅ 百度标题测试用例 执行通过")
# ===================== 测试用例2:测试百度搜索功能 =====================
def test_baidu_search(driver):
# 1. 定位百度搜索框(你原代码ID错了!正确ID是 kw)
search_input = driver.find_element(By.ID, "kw")
# 2. 向搜索框输入文字:软件测试
search_input.send_keys("软件测试")
# 3. 模拟键盘按下回车键(执行搜索)
search_input.send_keys(Keys.ENTER)
# 4. 断言:检查搜索框里的值是否正确
assert "软件测试" in search_input.get_attribute("value")
# 断言通过后,打印提示
print("✅ 百度搜索测试用例 执行通过")
scope干嘛用?
这是你设置的测试夹具的范围,如果scope='function'则每一个测试用例都执行一边,打开浏览器->关闭浏览器,如果你的scope='session',则所有的测试用例都共用一个浏览器,测试用例1执行完接着执行测试用例2,全部执行完毕之后再关闭浏览器
执行流程:
上述python代码,例如执行test_baidu_title这个函数。pytest框架看到这个以test_开头的函数,自动检测出这是pttest代码,自动调用,不用手动调用。在测试函数执行之前,看到这个用例的参数:driver,自动找到同名的夹具函数,然后先执行夹具函数driver(),跑yield之前的代码,然后返回浏览器对象driver,等这个函数所有代码都执行完毕之后再执行yield之后的代码。
什么是pytest框架?
它是一个专门写自动化测试的python工具
怎么才算pytest代码?
1.文件名/函数名以test_开头(pytest自动识别核心规则)
2.使用的pytest功能(夹具@pytest.fixture,断言,装饰器)(注意import pytest)
autouse=True什么意思?
夹具自动执行,不用用例传参激活
conftest.py文件管理测试夹具函数
什么是conftest.py?
1.项目目录全局夹具公共仓库
2.把所有的测试用例都需要的共同的夹具放这里
3.所有测试文件自动能用,不用复制代码,不用手动导入
4.文件名固定死,必须是conftest.py
conftest.py有什么用?
比如你的夹具函数:
# test_baidu.py
@pytest.fixture
def driver():
... # 开浏览器
你每一个test_.py文件测试函数,都需要写一边夹具代码,代码冗余。
把所有的夹具只写一次写在cinftest.py文件里,所有的测试文件都可以自动公用,统一管理,改一次,全项目生效。
规则
文件名固定‘
放在根目录,所有测试用例自动识别
无需导入,不写任何import
夹具函数之作用域设置
什么是夹具函数作用域?
简单来说,就是控制夹具具体执行多少次
| 作用域参数 | 全称 | 执行规则 | 你的浏览器场景 |
|---|---|---|---|
function | 函数级(默认) | 每个测试函数执行 1 次 | 一个用例开一次浏览器 |
class | 类级 | 每个测试类执行 1 次 | 一个类里的用例共用浏览器 |
module | 文件级 | 每个 .py 测试文件执行 1 次 | 一个文件里的用例共用浏览器 |
session | 会话级 | 整个测试过程只执行 1 次 | 全项目所有用例只开 1 次浏览器 |
1.scope="function"(默认)
每一个 test_ 测试用例,都重新执行一次夹具(开浏览器 → 跑用例 → 关浏览器 → 开浏览器 → 跑用例 → 关浏览器)
适用场景:用例需要完全隔离,互不干扰
2.scope='class'
一个测试类只执行一次夹具,类里所有用例共用一个浏览器,但是如果要pytest判定为测试类的话,类名必须以Test开头
# 测试类:只需要按规则写
class TestBaidu:
def test_title(self):
print("测试标题")
# ✅ 你什么都不用写!pytest 自动找、自动运行
同理,module级别的文件名必须以test_开头
pytest之失败重跑设置
# test_baidu.py 测试文件
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
# 你的夹具
@pytest.fixture
def driver():
driver = webdriver.Edge()
driver.get("https://www.baidu.com")
yield driver
driver.quit()
# 你的测试用例
def test_baidu_title(driver):
assert driver.title == "百度一下,你就知道"
# ===================== 你问的这段代码 =====================
# 直接运行这个文件,就自动执行pytest测试
if __name__ == '__main__':
pytest.main(['-vs','--reruns','1'])
讲解:
if __name__ == '__main__':
只有运行这个文件的时候,下面的代码才能执行,如果这个文件被其他别的文件导入的时候,下面的代码不执行
pytest.main([...]):
直接在代码里调用pytest运行测试,不用在命令行(终端)里敲命令。与直接在终端里输入:
pytest -vs --reruns 1
效果完全一样
| 参数 | 拆分 | 含义 |
|---|---|---|
-vs | 合并了 -v + -s | -v:输出详细测试结果-s:打印用例里的 print 内容 |
--reruns | 失败重跑参数 | 对应插件 pytest-rerunfailures |
1 | 重跑次数 | 用例失败 → 自动重跑 1 次 |
或者直接在命令行里使用:
pytest test_baidu.py -v --reruns=2 --reruns-delay=1
| 参数 | 作用 |
|---|---|
--reruns=n | 失败重跑 n 次(最常用:2~3 次) |
--reruns-delay=n | 重跑前等待 n 秒(给页面加载时间) |
pytest之多线程跑测试用例
# 1. 导入依赖:测试框架 + 浏览器驱动 + 元素定位 + 键盘操作
import pytest
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
# 2. 测试夹具:管理浏览器(核心!)
# scope='function':每个测试用例 → 独立打开/关闭1个浏览器
@pytest.fixture(scope='function')
def driver():
# 【前置】创建Edge浏览器 → 最大化 → 打开百度
driver = webdriver.Edge()
driver.maximize_window()
driver.get("https://www.baidu.com")
yield driver # 把浏览器对象交给测试用例
# 【后置】用例执行完 → 自动关闭浏览器
driver.quit()
# 3. 测试用例1:检查百度标题
def test_baidu_title(driver):
title=driver.title
assert title=="百度一下,你就知道"
print("✅ 百度标题测试用例 执行通过")
# 4. 测试用例2:搜索功能(⚠️你这里定位错了!导致重跑)
def test_baidu_search(driver):
# 错误定位:chat-textarea 是百度AI对话框,不是搜索框
search_input=driver.find_element(By.ID, "chat-textarea")
search_input.send_keys("软件测试")
search_input.send_keys(Keys.ENTER)
assert "软件测试" in search_input.get_attribute("value")
print("✅ 百度搜索测试用例 执行通过")
# 5. 测试用例3:检查新闻链接
def test_baidu_news(driver):
news_link=driver.find_element(By.LINK_TEXT, "新闻")
assert driver.current_url.startswith("http")
print("✅ 百度新闻测试用例 执行通过")
# 6. 测试用例4:检查地图链接
def test_map_link(driver):
map_link=driver.find_element(By.LINK_TEXT, "地图")
assert driver.current_url.startswith("http")
print("✅ 百度地图测试用例 执行通过")
# 7. 测试用例5:检查图片链接
def test_picture(driver):
picture_link=driver.find_element(By.LINK_TEXT, "图片")
assert driver.current_url.startswith("http")
print("✅ 百度图片测试用例 执行通过")
# 8. 主函数:代码启动测试
if __name__ == "__main__":
pytest.main([
'-vs', # 详细日志 + 打印print
'-n=5', # 开启5个进程 = 同时开5个浏览器
'--reruns=1', # 用例失败自动重跑1次
__file__ # 运行当前文件
])
pytest之断言
assert是pytest唯一的断言方式,作用是:
判断实际结果和预期结果是否一致
- 一致 → 用例通过(绿色)
- 不一致 → 用例失败(红色),自动抛出异常
1. 相等 / 不相等断言
# 用例:判断百度标题是否相等
def test_baidu_title(driver):
# 实际结果
title = driver.title
# 预期结果
expect_title = "百度一下,你就知道"
# 断言相等
assert title == expect_title
# 断言不相等(例子)
assert title != "谷歌"
2. 包含 / 不包含断言
def test_baidu_search(driver):
driver.find_element(By.ID, "kw").send_keys("软件测试")
driver.find_element(By.ID, "su").click()
# 断言:搜索结果标题包含关键词
assert "软件测试" in driver.title
# 断言不包含
assert "抖音" not in driver.title
3. 真假断言(True / False)
def test_link_enabled(driver):
# 判断新闻链接是否可点击
news_btn = driver.find_element(By.LINK_TEXT, "新闻")
# 断言为真
assert news_btn.is_enabled() is True
# 简写(推荐)
assert news_btn.is_enabled()
4. 为空 / 不为空断言
def test_search_input(driver):
input_text = driver.find_element(By.ID, "kw").text
# 断言输入框为空
assert input_text == ""
# 断言不为空
assert input_text is not None
5. 异常断言
def test_no_element(driver):
# 用 pytest.raises 断言:找不到元素会抛 NoSuchElementException
with pytest.raises(Exception):
# 定位一个不存在的元素,预期报错
driver.find_element(By.ID, "不存在的ID")
pytest之日志设置
一、日志级别
| 级别 | 英文 | 用途(工作场景) |
|---|---|---|
| 调试 | DEBUG | 最详细(打开浏览器、定位元素、执行步骤) |
| 普通 | INFO | 关键流程(用例开始 / 结束、搜索成功) |
| 警告 | WARNING | 不影响运行的提醒 |
| 错误 | ERROR | 元素找不到、用例失败 |
| 严重 | CRITICAL | 系统崩溃 |
# 1. 导入需要的工具
from loguru import logger # 导入日志库loguru的核心对象logger
import time,os # 导入time(时间)、os(系统路径)模块
# 格式化当前时间:年-月-日_时-分-秒
t=time.strftime("%Y-%m-%d_%H-%M-%S",time.localtime())
# 打印时间,方便你看
print(t)
# 1. 获取当前这个py文件的【绝对完整路径】
abs_path=os.path.abspath(__file__)
print(abs_path) # 打印:E:\python_Demo\PyCharm_Demo1\xxx.py
# 2. 获取当前文件所在的【文件夹路径】
log_path=os.path.dirname(abs_path)
print(log_path) # 打印:E:\python_Demo\PyCharm_Demo1
# 3. 获取上一级文件夹路径
demo_path=os.path.dirname(log_path)
print(demo_path) # 打印:E:\python_Demo
# 4. 拼接最终日志存放的文件夹:E:\python_Demo\PyCharm_Demo1
now_path=os.path.join(demo_path,"PyCharm_Demo1")
# 拼接:文件夹路径 + 时间名字 + .log后缀
log_file_name=now_path+'\\'+t+'.log'
logger.info("系统正常运行") # 普通信息日志
logger.debug("调试日志") # 调试日志(最详细)
logger.error("错误级别") # 错误日志
logger.warning("警告") # 警告日志
pytest之allure生成测试报告
什么是allure?
ALLURE是一款轻量级,可视化的测试报告工具,专门配合pytest使用
生成 Allure 报告的2 个核心步骤
- 运行测试用例 → 生成临时数据(json 格式,不能直接看)
- 把临时数据 → 生成网页版 HTML 报告(可以打开看)
import pytest # 测试核心框架,用来写用例、运行用例
import os # 系统操作库,执行cmd命令(生成allure报告)
from selenium import webdriver # 操控浏览器(Edge/Chrome)
from selenium.webdriver.common.keys import Keys # 键盘按键(回车、空格)
from selenium.webdriver.common.by import By # 元素定位方式(ID/文本)
import allure # 生成Allure测试报告的库
# Allure装饰器:给测试报告分组(大项目/功能模块)
@allure.epic("百度自动化测试") # 最高级分类:项目名称
@allure.feature("基础功能测试") # 二级分类:功能模块
# pytest规则:测试类必须以 Test 开头
class TestBaidu:
@allure.title("测试百度标题") # Allure:用例名称
def test_baidu_title(self, driver): # pytest用例:test开头
title = driver.title # 获取网页标题
assert title == "百度一下,你就知道" # 断言:标题必须等于这个
print("✅ 百度标题测试用例 执行通过")
@allure.title("测试百度搜索")
def test_baidu_search(self, driver):
# ❌ 错误定位:chat-textarea 是百度AI聊天框,不是搜索框!
search_input = driver.find_element(By.ID, "chat-textarea")
search_input.send_keys("软件测试") # 输入文字
search_input.send_keys(Keys.ENTER) # 按回车搜索
# 断言:输入框里的值包含 软件测试
assert "软件测试" in search_input.get_attribute("value")
@allure.title("测试百度新闻链接")
def test_baidu_news(self, driver):
driver.find_element(By.LINK_TEXT, "新闻") # 根据链接文字定位元素
assert driver.current_url.startswith("http") # 断言网址以http开头
# 地图、图片用例逻辑完全一样
if __name__ == "__main__":
# 步骤1:运行所有测试用例
pytest.main([
"-vs", # 显示详细运行日志
"--clean", # 清理临时文件
"--clean-logs", # 清理旧日志
'-n=5', # 多线程:开5个进程,同时跑5个用例(提速)
"--alluredir=./allure-results", # 生成Allure临时数据(json文件)
__file__ # 运行当前文件
])
# 步骤2:执行cmd命令 → 把临时数据 生成 网页报告
os.system("allure generate ./allure-results -o ./allure-report --clean")
命令解释
--alluredir=./allure-results生成报告原始数据(必须有这一步)allure generate把原始数据 → 生成 HTML 网页报告--clean覆盖旧报告,不报错
代码运行后的结果
- 自动打开 5 个 Edge 浏览器,同时执行 5 个用例
- 生成文件夹
allure-results(报告原始数据) - 生成文件夹
allure-report(网页报告,双击index.html打开) - 控制台显示结果
pytest之allure错误报告截图
什么是钩子函数(Hook)?
pytest 运行过程中,在固定的时间点,会自动调用你写的函数,不用你手动去调。
pytest:用例执行完 / 用例失败 → 自动执行你写的代码
这个 “自动触发” 的动作,就是钩子
pytest 常见钩子
-
pytest_runtest_setup:用例执行前自动跑 -
pytest_runtest_teardown:用例执行后自动跑 -
pytest_runtest_makereport:用例执行完、生成报告时跑 -
pytest_session_start:整个测试开始时跑 -
pytest_session_finish:整个测试结束时跑
更多推荐
所有评论(0)