7.自动化测试常用函数

目录:

  1. 开始前:环境与 "第一屏代码"(图片 2 的启动代码)

  2. 元素定位:cssSelector 与 xpath

  3. 操作测试对象:click、send_keys、clear、取文本

  4. 获取页面信息:title 与 URL

  5. 窗口:句柄、切换、大小、截图、关闭

  6. 等待:自动化测试的灵魂(强制 / 隐式 / 显式 / 混合实验)

  7. 浏览器导航:get 与 navigate

  8. 弹窗:Alert 接口

  9. 文件上传:send_keys 传路径

  10. 浏览器参数:无头模式与加载策略

  11. 本次实操踩坑实录(5 个真实坑)

1. 开始前:环境与"第一屏代码"

课件所有函数都挂在一个 driver 对象上,先看懂它,后面 everything 才有落脚点。

python 复制代码
import time                                                    # 强制等待
from selenium import webdriver                                 # Selenium 入口
from selenium.webdriver.chrome.service import Service          # 指定 chromedriver
from selenium.webdriver.common.by import By                    # 定位方式
from webdriver_manager.chrome import ChromeDriverManager       # 自动管理 chromedriver

# 1、打开浏览器
# 让 Selenium 自动匹配已安装的 Chrome 版本,并自动下载对应驱动,无需手动处理驱动
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
driver.maximize_window()                                       # 最大化窗口
time.sleep(2)

# 2、输入百度网址
driver.get("https://www.baidu.com")
time.sleep(3)                                                  # 多等几秒,让页面完全加载

# 3、输入关键词"迪丽热巴"
# 新版首页可见的搜索框是 div#chat-input-area 容器里的 textarea(id=chat-textarea),
# 旧版隐藏的 #kw 已不可交互,这里直接对可见元素原生输入
print("正在输入关键词...")
box = driver.find_element(By.ID, "chat-textarea")              # 等价 xpath://*[@id="chat-input-area"]//textarea
box.send_keys("迪丽热巴")
time.sleep(1)

# 4、点击"百度一下"按钮
# 新版首页可见按钮是 button#chat-submit-button,旧版隐藏的 #su 已废弃
print("正在点击搜索...")
btn = driver.find_element(By.ID, "chat-submit-button")         # 等价 xpath://*[@id="chat-submit-button"]
btn.click()
time.sleep(20)                                                 # 留出时间查看采集结果

# 查看提交后落到哪个页面(搜索结果页 or 百度安全验证页)
print("跳转后网址 =", driver.current_url[:80])
print("跳转后标题 =", driver.title)

# 5、关闭浏览器
print("执行完毕,关闭浏览器...")
driver.quit()

2. 元素定位:cssSelector 与 xpath

课Web 自动化测试的操作核心是能够找到页面对应的元素,然后才能对元素进行具体的操作。定位方式必须唯一 。

web⾃动化测试的操作核⼼是能够找到⻚⾯对应的元素,然后才能对元素进⾏具体的操作。

常⻅的元素定位⽅式⾮常多,如id,classname,tagname,xpath,cssSelector

常⽤的主要由cssSelector和xpath

由于百度版本的更替可能会导致定位元素的名字发生了变化,但是底层逻辑不变

2.1 cssSelector(CSS 选择器)

两类:

2.2 xpath 六种语法

例说明索引从 1 开始**://div/ul/li[3] 取的是"第 3 个 li",不是程序员习惯的"下标 3(即第 4 个)"。这是 xpath 和 Python/Java 数组下标最大的区别,写错一位就定位到隔壁元素,是高频 bug。

2.3 课件的思考题:能直接右键 Copy selector,为什么还要学语法?

手动复制的表达式不一定唯一 。例如复制热搜标题得到的 #title-content,页面上每条热搜都有一个同 id 的节点,find_element 只会拿到第一个,find_elements 会拿到一堆------都不"唯一"。学语法是为了手动改表达式 ,把不唯一的定位改唯一(比如加上父级限定 #hotsearch-content-wrapper > li:nth-child(1) .title-content)。

我的补充见解 :复制来的 xpath 还经常是" fullPath 型"的(/html/body/div[2]/div/...),页面一改版就全废。手写"短 xpath"(//*[@id='kw'] 这类基于 id/文本的)抗改版能力强得多。

3. 操作测试对象:click、send_keys、clear、取文本

获取到了⻚⾯的元素之后,接下来就是要对元素进⾏操作了。常⻅的操作有点击、提交、输⼊、清除、获取⽂本。

3.1 点击/提交对象

python 复制代码
#常见的自动化函数的使用
#1点击提交元素
import os                                                    # 读取环境变量控制后台运行
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 方式A:原生 click() 点击当前首页可见的"百度一下"按钮 ----------
driver.get("https://www.baidu.com")                          # 打开百度首页
time.sleep(2)                                                # 等首屏渲染
box = driver.find_element(By.ID, "chat-textarea")            # 定位当前首页可见搜索框(textarea)
box.send_keys("软件测试")                                     # 先输入关键词,点击后才有意义
btn = driver.find_element(By.ID, "chat-submit-button")       # 当前首页可见的"百度一下"按钮(button 标签)
assert btn.is_displayed(), "按钮不可见,click() 会报 element not interactable"  # 点击前先断言可见
btn.click()                                                  # 原生点击:等价于课件 driver.findElement(...).click()
time.sleep(20)                                                # 等待跳转完成
url_a = driver.current_url                                   # 读取跳转后的网址
print("方式A 原生click 跳转后网址 =", url_a[:80])
assert url_a != "https://www.baidu.com/", "点击后网址未变化,说明点击未生效"      # 断言点击确实触发了提交
# 说明:自动化会话可能落到百度安全验证页(wappass...),也属于"提交已触发",均为通过

3.2 模拟按键输⼊

python 复制代码
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver

driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

driver.get("https://www.baidu.com")                          # 打开百度首页
time.sleep(2)                                                # 等首屏渲染

# ---------- 普通文本输入 ----------
box = driver.find_element(By.ID, "chat-textarea")            # 当前首页可见搜索框(隐藏的 #kw 无法 send_keys)
box.send_keys("我爱学习")                                     # send_keys:模拟键盘逐字输入
time.sleep(5)
val = box.get_attribute("value")                             # 读回输入框当前值用于断言
print("输入后 value =", val)
assert val == "我爱学习", "输入内容与预期不一致"                                # 断言输入成功

3.3 清除⽂本内容

输⼊⽂本后⼜想换⼀个新的关键词,这⾥就需要⽤到 clear()

python 复制代码
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

driver.get("https://www.baidu.com")                          # 打开百度首页
time.sleep(2)                                                # 等首屏渲染
box = driver.find_element(By.ID, "chat-textarea")            # 定位当前首页可见搜索框

# ---------- 4.1 先输入第一个关键词 ----------
box.send_keys("我爱游戏")                                     # 课件原例第 1 步:输入旧关键词
time.sleep(2)

print("clear 前 value =", box.get_attribute("value"))

# ---------- 4.2 clear() 清空 ----------
box.clear()                                                  # clear:一键清空输入框全部文本
time.sleep(2)
val_empty = box.get_attribute("value")                       # 读回清空后的值
print("clear 后 value =", repr(val_empty))
assert val_empty == "", "clear() 未清空输入框"                                # 断言确实清空

# ---------- 4.3 再输入新关键词 ----------
box.send_keys("我爱学习")                                     # 课件原例第 3 步:输入新关键词
time.sleep(2)
val_new = box.get_attribute("value")                         # 读回新值
print("重新输入后 value =", val_new)
assert val_new == "我爱学习", "重新输入失败"                                  # 断言新关键词就位

driver.quit()                                                # 关闭浏览器释放驱动

3.4 获取⽂本信息

如果判断获取到的元素对应的⽂本是否符合预期呢?获取元素对应的⽂本并打印⼀下~~

python 复制代码
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

driver.get("https://www.baidu.com")                          # 打开百度首页
time.sleep(2)                                                # 等首屏渲染

# ---------- 5.1 获取节点文本 text(等价于课件 Java 的 getText()) ----------
title_span = driver.find_element(By.CSS_SELECTOR, "#hotsearch-content-wrapper > li:nth-child(4) span.title-content-title")
txt = title_span.text                                        # .text:元素在页面上"看得见"的文字
print("第3条热搜文本 =", txt)
assert len(txt) > 0, "热搜文本为空"                                          # 断言确实取到文本

# ---------- 5.2 获取属性值 get_attribute() ----------
su = driver.find_element(By.ID, "su")                        # 定位隐藏的"百度一下"按钮 #su
val = su.get_attribute("value")                              # get_attribute("value"):按钮文字在 value 属性里
print("#su 的 value 属性 =", val)
assert val == "百度一下", "属性值与预期不符"                                  # 断言属性读取正确
# 注意:对 #su 用 .text 会得到空字符串------按钮文字是 value 属性而不是节点文本,这就是课件说的"文本和属性值不要混淆"
print("#su 的 .text =", repr(su.text))
kw = driver.find_element(By.ID, "kw")                        # 定位隐藏搜索框
print("#kw 的 name 属性 =", kw.get_attribute("name"))        # 读取 name 属性(wd)

driver.quit()                                                # 关闭浏览器释放驱动
  1. 获取页面信息:title 与 URL

4.1获取当前⻚⾯标题

getTitle()

python 复制代码
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver

driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 6a.1 读取百度首页的标题 ----------
driver.get("https://www.baidu.com")                          # 打开百度首页
time.sleep(2)                                                # 等首屏渲染
t1 = driver.title                                            # driver.title 等价课件 getTitle(),读 <title> 标签
print("首页标题 getTitle() =", t1)
assert t1 == "百度一下,你就知道", "首页标题不符"            # 断言标题正确

# ---------- 6a.2 页面跳转后再读一次标题,观察变化 ----------
box = driver.find_element(By.ID, "chat-textarea")            # 新版首页可见输入框
box.send_keys("软件测试")
btn = driver.find_element(By.ID, "chat-submit-button")       # 新版首页可见按钮
btn.click()                                                  # 提交搜索触发页面跳转
time.sleep(20)                                                # 等跳转完成
t2 = driver.title                                            # 跳转后的标题
print("跳转后标题 getTitle() =", t2[:40])
assert t2 != t1, "跳转后标题毫无变化,getTitle() 未反映新页面"  # 断言标题随页面变化
print("说明:getTitle() 读的是当前所在页面的标题,页面一换结果就跟着换")

driver.quit()                                                # 关闭浏览器释放驱动

4.2获取当前⻚⾯URL

getCurrentUrl()

python 复制代码
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 6b.1 读取百度首页的 URL ----------
driver.get("https://www.baidu.com")                          # 打开百度首页
time.sleep(2)                                                # 等首屏渲染
u1 = driver.current_url                                      # driver.current_url 等价课件 getCurrentUrl()
print("首页 getCurrentUrl() =", u1)
assert u1.startswith("https://www.baidu.com"), "首页URL不符"  # 断言 URL 正确

#---------- 6b.2 页面跳转后再读一次 URL,观察变化 ----------
box = driver.find_element(By.ID, "chat-textarea")            # 新版首页可见输入框
box.send_keys("迪丽热巴")
btn = driver.find_element(By.ID, "chat-submit-button")       # 新版首页可见按钮
btn.click()                                                  # 提交搜索触发页面跳转
time.sleep(20)                                                # 等跳转完成
u2 = driver.current_url                                      # 跳转后的 URL
print("跳转后 getCurrentUrl() =", u2[:80])
assert u2 != u1, "跳转后URL毫无变化,getCurrentUrl() 未反映新页面"  # 断言 URL 随页面变化
print("说明:getCurrentUrl() 读的是当前所在页面的地址,跳到哪读哪")
print("(自动化会话提交后可能落到'百度安全验证'页,URL 已变化即说明读取正常)")

driver.quit()                                                # 关闭浏览器释放驱动

5. 窗口:句柄、切换、大小、截图、关闭

为什么需要句柄

人能用眼睛看出"当前在哪个窗口",程序不能。每个窗口/标签页有一个唯一字符串标识,叫句柄(handle),程序靠它认窗口。

当我们⼿⼯测试的时候,我们可以通过眼睛来判断当前的窗⼝是什么,但对于程序来说它是不知道当

前最新的窗⼝应该是哪⼀个。对于程序来说它怎么来识别每⼀个窗⼝呢?每个浏览器窗⼝都有⼀个唯

⼀的属性句柄(handle)来表⽰,我们就可以通过句柄来切换

可以理解为多一个窗口就多一个句柄 窗口换句柄也会跟着更换

接下来的代码就可以很好的演示出来

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
try:
    driver.get("https://www.baidu.com")
    time.sleep(2)

    # ---- 1) 获取当前页面句柄 getWindowHandle() ----
    cur = driver.current_window_handle
    print("== getWindowHandle() 获取当前页面句柄 ==")
    print("当前句柄 =", cur)

    # ---- 2) 获取所有页面句柄 getWindowHandles() ----
    print("== getWindowHandles() 获取所有页面句柄 ==")
    handles = driver.window_handles
    print("句柄个数 =", len(handles), "列表 =", handles)
    assert len(handles) == 1, "只开了一个标签页,句柄应只有 1 个"
    print("PASS:只有一个标签页时,Handles 列表里就是当前这 1 个句柄")

    # ---- 再开一个新标签页,观察句柄列表变化 ----
    print("== 新开一个标签页后重新获取所有句柄 ==")
    driver.switch_to.new_window("tab")          # 开新标签页(句柄演示用)
    handles2 = driver.window_handles
    print("新标签页打开后句柄个数 =", len(handles2))
    print("句柄列表 =", handles2)
    print("当前句柄 =", driver.current_window_handle,
          "(new_window 会自动切到新标签页,所以当前句柄变了)")
    assert len(handles2) == 2, "两个标签页应对应 2 个句柄"
    assert cur in handles2, "旧句柄仍然在列表里"
    print("PASS:每多一个窗口就多一个唯一句柄,旧句柄不变")
    print("示例07 运行结束:getWindowHandle / getWindowHandles 演示 PASS")
finally:
    driver.quit()

5.1切换窗口

python 复制代码
# 演示痛点
#   a. 打开新页面后,不切换句柄,getTitle/getCurrentUrl 读到的还是旧页面;
#   b. 去掉等待后,获取跳转后页面的元素会失败 -> 配上 WebDriverWait 才稳定。
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager



service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

try:
    driver.get("https://www.baidu.com")
    time.sleep(2)
    cur = driver.current_window_handle
    print("== 停留页(旧窗口)==")
    print("旧窗口句柄 =", cur)
    print("旧窗口标题 =", driver.title)

    # ---- 制造一个新窗口:点首页热搜链接(target=_blank 会开新标签页)----
    opened = False
    try:
        link = driver.find_element(By.CSS_SELECTOR, "#hotsearch-content-wrapper li a")
        driver.execute_script("arguments[0].click();", link)   # JS 点击,避开遮挡
        for _ in range(10):
            if len(driver.window_handles) > 1:
                opened = True
                break
            time.sleep(0.5)
    except Exception as e:
        print("热搜链接点击失败,改用 new_window 兜底:", type(e).__name__)
    if not opened:
        driver.switch_to.new_window("tab")
        driver.get("https://example.com")
    # 统一站回旧窗口,才能演示"不切换就读不到新页面"
    driver.switch_to.window(cur)
    time.sleep(1)

    print("== 痛点a:新窗口已打开,但句柄没切换 ==")
    print("当前句柄仍是 =", driver.current_window_handle)
    print("此时 getTitle() 读到的还是旧页面:", driver.title)
    print("句柄列表已有", len(driver.window_handles), "个:", driver.window_handles)

    # ---- 课件同款循环:切换到"不是当前句柄"的那个窗口(即最新页面)----
    print("== switchTo().window(w) 切换到最新页面 ==")
    all_window = driver.window_handles
    time.sleep(20)
    for w in all_window:
        if w != cur:
            driver.switch_to.window(w)
    print("切换后句柄 =", driver.current_window_handle)
    print("切换后标题 =", driver.title[:50])
    print("切换后URL  =", driver.current_url[:70])
    assert driver.current_window_handle != cur, "应已切到新窗口"

    # ---- 痛点b:去掉等待取元素会失败,配 WebDriverWait 才稳定 ----
    print("== 痛点b:等待 vs 不等待 取新页面元素 ==")
    try:
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.TAG_NAME, "body")))
        print("带 WebDriverWait 取 body 元素:成功(稳定写法)")
    except Exception as e:
        print("带等待仍失败:", type(e).__name__)
    print("说明:课件提醒'去掉等待后获取跳转后的页面元素失败',"
          "慢页面上不等就直接 find_element 会抛 NoSuchElementException")

    # ---- 切回旧窗口,验证标题又变回去 ----
    driver.switch_to.window(cur)
    print("== 切回旧窗口 ==")
    print("切回后标题 =", driver.title)
    assert driver.title.startswith("百度"), "切回后应回到百度首页标题"
    print("示例08 运行结束:switchTo().window() 切换窗口演示 PASS")
finally:
    driver.quit()

5.2窗口设置大小

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager


service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

try:
    driver.get("https://www.baidu.com")
    time.sleep(2)

    def show(tag):
        size = driver.get_window_size()
        print(f"{tag} -> 宽={size['width']} 高={size['height']}")
        return size
    print("== §3.2 窗口设置大小,逐个函数演示 ==")
    show("初始窗口")

    # 1) 窗口最大化
    driver.maximize_window()
    s_max = show("maximize() 最大化后")
    time.sleep(2 )

    # 2) 手动设置窗口大小(课件 setSize(new Dimension(1024, 768)))
    driver.set_window_size(1024, 768)
    time.sleep(2)
    s_set = show("setSize(1024, 768) 后")
    assert s_set["width"] == 1024 and s_set["height"] == 768, "setSize 应精确生效"
    print("PASS:setSize 后 get_window_size 读回正是 1024x768")

    # 3) 窗口最小化(无头环境下可能不改变尺寸,只演示调用不报错)  无法演示
    try:
        driver.minimize_window()
        time.sleep(2)
        show("minimize() 最小化后")
        print("PASS:minimize() 调用成功")
    except Exception as e:
        print("minimize() 在当前环境不支持:", type(e).__name__)

    # 4) 全屏窗口
    try:
        driver.fullscreen_window()
        time.sleep(2)
        s_full = show("fullscreen() 全屏后")
        print("PASS:fullscreen() 调用成功,全屏尺寸 >= 最大化尺寸:",
              s_full["width"] >= s_max["width"])
    except Exception as e:
        print("fullscreen() 在当前环境不支持:", type(e).__name__)

    # 再设回一个小尺寸,肉眼/读回都能确认"手动设置"生效
    driver.set_window_size(800, 600)
    time.sleep(2)
    show("再次 setSize(800, 600) 后")
    print("示例09 运行结束:窗口设置大小四个函数演示 PASS")
finally:
    driver.quit()

5.3 屏幕截图

我们的⾃动化脚本⼀般部署在机器上⾃动的去运⾏,如果出现了报错,我们是不知道的,可以通过抓拍来记录当时的错误场景

python 复制代码
#   Python 对应(一步到位,无需 commons-io):
#     driver.get_screenshot_as_file(路径)      -> 直接存成 png 文件
#     driver.get_screenshot_as_png             -> 返回 png 字节串(备选)
# 用途:脚本自动跑报错时,抓拍当时的错误场景留证。
# 运行方式:直接运行=有头;设环境变量 DEMO_HEADLESS=1=无头
# =====================================================================
import os
import time

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

try:
    driver.get("https://www.baidu.com")
    time.sleep(2)

    base = os.path.join(os.path.dirname(os.path.abspath(__file__)), "截图记录")
    os.makedirs(base, exist_ok=True)

    # ---- 简单版本:固定文件名 my.png ----   用第一种方法截屏不能保存同名的文件 如果我们想保存另外的还需要手动
    print("== 简单版本:getScreenshotAs(FILE) 存成 my.png ==")
    p1 = os.path.join(base, "my.png2")  #这里原来是"my.png"被我改成"my.png2"才能保存另外的一张
    driver.get_screenshot_as_file(p1)
    print("已保存:", p1)
    print("文件大小 =", os.path.getsize(p1), "字节")
    assert os.path.getsize(p1) > 0, "截图文件不应为空"
    print("PASS:简单版本截图成功")
finally:
    driver.quit()

5.4关闭窗口

python 复制代码
import os
import time

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

try:
    driver.get("https://www.baidu.com")
    time.sleep(2)

    base = os.path.join(os.path.dirname(os.path.abspath(__file__)), "截图记录")
    os.makedirs(base, exist_ok=True)
    # ---- 高阶版本:日期文件夹 + 时间戳文件名(课件同款思路)----
    print("== 高阶版本:autotest-日期/名字-时分秒.png ==")
    day = time.strftime("%Y-%m-%d")          # 对应课件 times.get(0)
    hms = time.strftime("%H%M%S")            # 对应课件 times.get(1)
    folder = os.path.join(base, "autotest-" + day)
    os.makedirs(folder, exist_ok=True)
    p2 = os.path.join(folder, "baidu_homepage-" + hms + ".png")
    driver.get_screenshot_as_file(p2)
    print("已保存:", p2)
    print("文件大小 =", os.path.getsize(p2), "字节")
    assert os.path.getsize(p2) > 0, "截图文件不应为空"
    print("PASS:高阶版本截图成功(每次运行文件名不重复,便于留证)")

    # ---- 备选:拿 png 字节串,不落地文件 ----
    png_bytes = driver.get_screenshot_as_png()   # 注意带括号:是方法不是属性
    print("== 备选:get_screenshot_as_png 返回字节数 =", len(png_bytes))
    print("示例10 运行结束:屏幕截图演示 PASS,截图在", base)
finally:
    driver.quit()

而这里的自动化截图以时间为依托 我就可以截取不同时间的信息了更高效和方便

python 复制代码
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

try:
    driver.get("https://www.baidu.com")
    time.sleep(2)
    cur = driver.current_window_handle
    print("== 准备两个窗口 ==")
    print("旧窗口句柄 =", cur, "标题 =", driver.title)

    driver.switch_to.new_window("tab")       # 开第二个标签页
    new = driver.current_window_handle
    driver.get("https://www.baidu.com")
    time.sleep(1)
    print("新窗口句柄 =", new)
    print("当前句柄个数 =", len(driver.window_handles))

    # ---- 1) close() 关闭"当前"窗口(新标签页)----
    print("== close() 关闭当前窗口(新标签页)==")
    driver.close()
    time.sleep(10)
    print("close 后剩余句柄 =", driver.window_handles)
    assert len(driver.window_handles) == 1, "close 只关一个窗口,应剩 1 个"
    print("PASS:close() 只关当前窗口,另一个窗口还在")

    # ---- 2) 注意a:close 后先切到未被关闭的窗口 ----
    try:
        print("close 后不切换直接读标题:", driver.title)
    except Exception as e:
        print("close 后不切换就操作,报错:", type(e).__name__,
              "(句柄还停在已关闭的窗口上)")
    driver.switch_to.window(cur)             # 注意:切到未被关闭的窗口
    print("切回未关闭的旧窗口后,标题 =", driver.title)
    print("PASS:切换后可正常继续操作")

    # ---- 3) 注意b:关掉最后一个窗口,driver 失效需重新定义 ----
    print("== 关闭最后一个窗口,验证 driver 失效 ==")
    driver.close()
    try:
        driver.title
        print("意外:会话居然还可用")
    except Exception as e:
        print("所有窗口关闭后 driver 已失效:", type(e).__name__)
    print("按课件注意重新定义 driver ...")
    driver = webdriver.Chrome(service=service)   # 重新定义
    driver.get("https://www.baidu.com")
    time.sleep(1)
    print("新 driver 标题 =", driver.title)
    print("PASS:重新定义后 driver 恢复可用")
    print("示例11 运行结束:close() 关闭窗口演示 PASS")
finally:
    try:
        driver.quit()
    except Exception:
        pass

6.等待

通常代码执⾏的速度⽐⻚⾯渲染的速度要快,如果避免因为渲染过慢出现的⾃动化误报的问题呢?可以使⽤selenium中提供的三种等待⽅法:

6.1 强制等待

Thread.sleep()

优点:使⽤简单,调试的时候⽐较有效

缺点:影响运⾏效率,浪费⼤量的时间

python 复制代码
import time                                                  # 本示例主角:time.sleep 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.chrome.options import Options        # Chrome 启动参数
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

t0 = time.time()                                             # 记录开始时间,用于量化"浪费"
driver.get("https://www.baidu.com")                          # 打开百度首页
time.sleep(2)                                                # 强制等待 2 秒:不管页面是否早已渲染好,都死等
box = driver.find_element(By.ID, "chat-textarea")            # 定位可见搜索框
box.send_keys("强制等待演示")                                 # 输入关键词
time.sleep(1)                                                # 再死等 1 秒(调试时常用,生产脚本应改智能等待)
print("两段 sleep 总耗时 =", round(time.time() - t0, 2), "秒(含页面加载)")
assert box.get_attribute("value") == "强制等待演示", "输入失败"                  # 断言等待期间输入已生效

driver.quit()                                                # 关闭浏览器释放驱动
print("示例11 运行结束:强制等待 sleep 演示 PASS")

6.2 隐式等待

隐式等待是⼀种智能等待,他可以规定在查找元素时,在指定时间内不断查找元素。如果找到则代码

继续执⾏,直到超时没找到元素才会报错。

隐式等待作⽤域是整个脚本的所有元素 。即只要driver对象没有被释放掉(driver.quit()),隐式等待就⼀直⽣效。

优点:智能等待,作⽤于全局

python 复制代码
import time                                                  # 计时用
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.chrome.options import Options        # Chrome 启动参数
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver

driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 12.1 设置隐式等待 5 秒(全局生效) ----------
driver.implicitly_wait(5)                                    # 隐式等待:找不到元素时最多重试 5 秒再报错
driver.get("https://www.baidu.com")                          # 打开百度首页(不再需要 sleep)
box = driver.find_element(By.ID, "chat-textarea")            # 隐式等待下:元素一出现立即返回,不必死等
print("隐式等待下定位搜索框成功,tag =", box.tag_name)

# ---------- 12.2 验证"找不到时等满超时才报错" ----------
t0 = time.time()                                             # 开始计时
try:
    driver.find_element(By.ID, "not-exist-element-xyz")      # 故意找一个不存在的元素
except Exception as e:                                       # 5 秒后抛 NoSuchElementException
    cost = time.time() - t0                                  # 实际等待时长
    print("不存在元素报错耗时 =", round(cost, 2), "秒,异常类型 =", type(e).__name__)
    assert 4.5 <= cost <= 6.5, "隐式等待时长不符合 5 秒设定"                    # 断言确实等满了 5 秒

driver.quit()                                                # 关闭浏览器释放驱动

6.3 显⽰等待

显⽰等待也是⼀种智能等待,在指定超时时间范围内只要满⾜操作的条件就会继续执⾏后续代码

new WebDriverWait(driver, Duration.ofSeconds(3)).until($express)

$press:涉及到selenium.support.ui.ExpectedConditions包下的ExpectedConditions类

返回值:boolean

优点:显⽰等待是智能等待,可以⾃定义显⽰等待的条件,操作灵活
缺点:写法复杂

python 复制代码
import time                                                  # 计时用
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from selenium.webdriver.support.ui import WebDriverWait      # 显式等待主体
from selenium.webdriver.support import expected_conditions as EC  # 预定义等待条件集合
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 13.1 element_to_be_clickable:等到元素可见且可点击 ----------
driver.get("https://www.baidu.com")                          # 打开百度首页
wait = WebDriverWait(driver, 10)                             # 课件 WebDriverWait(driver, Duration.ofSeconds(10))
btn = wait.until(EC.element_to_be_clickable((By.ID, "chat-submit-button")))  # 等到按钮可点击才返回该元素
print("element_to_be_clickable 命中按钮 =", btn.tag_name, btn.get_attribute("id"))

# ---------- 13.2 presence_of_element_located:DOM 中存在即通过 ----------
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "#hotsearch-content-wrapper > li")))  # 热搜出现
print("presence_of_element_located 通过:热搜列表已进入 DOM")

# ---------- 13.3 text_to_be_present_in_element:课件 textToBe 的 Python 等价 ----------
ok = wait.until(EC.text_to_be_present_in_element(
    (By.CSS_SELECTOR, "#hotsearch-content-wrapper > li:nth-child(3) span.title-content-title"), ""))  # 文本非空即满足包含关系
# 更贴近课件的用法:断言按钮文案
ok2 = wait.until(EC.text_to_be_present_in_element((By.ID, "chat-submit-button"), "百度一下"))
print("text_to_be_present_in_element 返回值 =", ok, ok2)
assert ok2, "按钮文本条件未满足"

# ---------- 13.4 url_to_be:等待跳转到指定 URL ----------
driver.execute_script("document.getElementById('kw').value='软件测试'")  # JS 赋值隐藏搜索框
driver.execute_script("document.getElementById('su').click()")          # JS 提交
try:
    wait.until(EC.url_contains("baidu.com"))               # 等待 URL 含 baidu.com(结果页或验证页都满足)
    print("url 条件通过,当前 =", driver.current_url[:70])
except Exception as e:                                       # 超时则打印而非崩溃
    print("url 条件超时:", str(e)[:80])

# ---------- 13.5 条件不满足时 until 会抛 TimeoutException ----------
t0 = time.time()                                             # 计时
try:
    WebDriverWait(driver, 3).until(EC.presence_of_element_located((By.ID, "no-such-node")))  # 3 秒内必失败
except Exception as e:                                       # 捕获超时异常
    print("3 秒显式等待超时耗时 =", round(time.time() - t0, 2), "秒,异常 =", type(e).__name__)

driver.quit()                                                # 关闭浏览器释放驱动

那么这里如果显示和隐式等待一起使用呢?会出现什么情况吗?

python 复制代码
import os
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager


driver_path = ChromeDriverManager().install()
driver = webdriver.Chrome(service=Service(driver_path))

# 本地练习页:一个元素 3 秒后才插入 DOM
html = os.path.join(os.path.dirname(os.path.abspath(__file__)), "练习页_等待.html")
with open(html, "w", encoding="utf-8") as f:
    f.write("<html><head><meta charset='utf-8'><title>等待练习页</title></head><body>"
            "<div id='now'>立即出现的元素</div>"
            "<script>setTimeout(function(){var d=document.createElement('div');"
            "d.id='late';d.innerText='延迟3秒才出现的元素';"
            "document.body.appendChild(d);},3000);</script></body></html>")

try:
    # ---------- 课件同款配置:隐式 5s + 显式 10s ----------
    driver.implicitly_wait(5)                                # 隐式等待 5 秒(全局)
    wait = WebDriverWait(driver, 10)                         # 显式等待 10 秒

    # ---------- 实验1:元素延迟 3 秒出现 ----------
    driver.get("file:///" + html.replace("\\", "/"))
    t0 = time.time()
    el = wait.until(EC.presence_of_element_located((By.ID, "late")))
    cost1 = time.time() - t0
    print("实验1 隐式5s+显式10s 等延迟3秒元素,耗时 = %.1fs" % cost1,
          ",元素文本 =", el.text)
    assert cost1 < 10, "元素3秒就出现了,不该等到接近超时"

    # ---------- 实验2:元素不存在,看超时耗时 ----------
    t0 = time.time()
    try:
        wait.until(EC.presence_of_element_located((By.ID, "not-exist")))
    except Exception as e:
        cost2 = time.time() - t0
        print("实验2 隐式5s+显式10s 等不存在元素,超时耗时 = %.1fs" % cost2,
              ",异常 =", type(e).__name__)
        print("课件预期:耗时在 10s、11s 左右浮动,而不是 5+10=15s")
        assert cost2 < 15, "混用下耗时应小于简单相加的 15 秒"

    driver.implicitly_wait(0)                                # 复位,避免影响后续脚本习惯
    print("结论:不要混合隐式和显式等待,可能会导致不可预测的等待时间。")
    print("示例13b 运行结束:隐式+显式混用实验 PASS")
finally:
    driver.quit()

结果:重试多次,最终打印的等待时间有10s、11s...
结论:不要混合隐式和显式等待,可能会导致不可预测的等待时间。

7.浏览器导航

7.1打开网址

python 复制代码
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.chrome.options import Options        # Chrome 启动参数
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 14.1 用简洁方法 get() 打开第一个网站 ----------
driver.get("https://www.baidu.com")                          # 课件简洁写法 driver.get(...)
time.sleep(2)                                                # 等首屏渲染
print("get('https://www.baidu.com') 后:")
print("  title =", driver.title)
print("  url   =", driver.current_url)
assert driver.title == "百度一下,你就知道", "第一个网站未打开"                    # 断言打开成功

# ---------- 14.2 再打开第二个网站(等价于课件 navigate().to(...)) ----------
print("Python 是否有 navigate() 对象:", hasattr(driver, "navigate"),
      "(False 说明 get() 就是 to() 的等价写法)")
driver.get("https://example.com")                            # 等价课件 navigate().to(...)
time.sleep(2)                                                # 等首屏渲染
print("get('https://example.com')(= navigate().to())后:")
print("  title =", driver.title)
print("  url   =", driver.current_url)
assert "example" in driver.current_url, "第二个网站未打开"                        # 断言跳转成功
print("PASS:get() 与 navigate().to() 等价,打开谁 title/url 就跟到谁")

driver.quit()                                                # 关闭浏览器释放驱动
print("示例14 运行结束:打开网站演示 PASS")

7.2浏览器的前进、后退、刷新

python 复制代码
import os                                                    # 环境变量/路径处理
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver

driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

base = os.path.dirname(os.path.abspath(__file__))            # 脚本所在目录
pa = os.path.join(base, "练习页_导航A.html")                  # 练习页 A
pb = os.path.join(base, "练习页_导航B.html")                  # 练习页 B(带加载时间戳)

with open(pa, "w", encoding="utf-8") as f:
    f.write("<html><head><meta charset='utf-8'><title>导航页A</title></head>"
            "<body><h1>这是页面 A</h1></body></html>")
with open(pb, "w", encoding="utf-8") as f:
    f.write("<html><head><meta charset='utf-8'><title>导航页B</title></head>"
            "<body><h1>这是页面 B</h1><div id='ts'></div>"
            "<script>document.getElementById('ts').innerText="
            "'加载时间戳:' + Date.now();</script></body></html>")

def uri(p):
    return "file:///" + p.replace("\\", "/")

try:
    # ---------- 造浏览历史:A -> B ----------
    driver.get(uri(pa))                                      # 历史记录第 1 条:页面 A
    time.sleep(2)
    print("打开页面A:title =", driver.title)
    driver.get(uri(pb))                                      # 历史记录第 2 条:页面 B
    time.sleep(2)
    ts1 = driver.find_element(By.ID, "ts").text              # B 页第一次加载的时间戳
    print("打开页面B:title =", driver.title, "|", ts1)

    # ---------- 1) 后退 back()(课件 navigate().back()) ----------
    driver.back()                                            # 后退到上一页
    time.sleep(2)
    print("back() 后退后:title =", driver.title, "| url 结尾 =",
          driver.current_url.split("/")[-1])
    assert driver.title == "导航页A", "back() 应回到页面 A"                       # 断言后退成功

    # ---------- 2) 前进 forward()(课件 navigate().forward()) ----------
    driver.forward()                                         # 前进到下一页
    time.sleep(2)
    print("forward() 前进后:title =", driver.title, "| url 结尾 =",
          driver.current_url.split("/")[-1])
    assert driver.title == "导航页B", "forward() 应回到页面 B"                    # 断言前进成功

    # ---------- 3) 刷新 refresh()(课件 navigate().refresh()) ----------
    ts2 = driver.find_element(By.ID, "ts").text              # 刷新前读一次时间戳
    driver.refresh()                                         # 重新加载当前页
    time.sleep(2)
    ts3 = driver.find_element(By.ID, "ts").text              # 刷新后读时间戳
    print("refresh() 刷新前:", ts2)
    print("refresh() 刷新后:", ts3)
    assert driver.title == "导航页B", "刷新后应仍是页面 B"                        # 断言页面没跑偏
    assert ts3 != ts2, "时间戳没变,说明 refresh 没有真正重新加载"                 # 断言确实重新加载
    print("PASS:时间戳变化证明 refresh() 重新加载了页面")
    print("示例14b 运行结束:back / forward / refresh 演示 PASS")
finally:
    driver.quit()                                            # 关闭浏览器释放驱动

8.弹窗

弹窗是在⻚⾯是找不到任何元素的,这种情况怎么处理?使⽤selenium提供的Alert接⼝

8.1警告弹窗+确认弹窗

python 复制代码
import os                                                    # 环境变量 + 写本地演示页
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 本地演示页:警告按钮 + 确认按钮 + 结果区 ----------
html_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "练习页_弹窗61.html")
with open(html_path, "w", encoding="utf-8") as f:
    f.write("<html><head><meta charset='utf-8'><title>弹窗61练习页</title></head><body>"
            "<button id='b1' onclick=\"alert('此网页显示 hello!')\">警告弹窗</button>"
            "<button id='b2' onclick=\"document.getElementById('r').innerText = "
            "confirm('此网页显示 Press a button') ? '点了确定' : '点了取消'\">确认弹窗</button>"
            "<div id='r'></div></body></html>")
driver.get("file:///" + html_path.replace("\\", "/"))        # 打开本地演示页
time.sleep(1)                                                # 等渲染

# ---------- 15.1 警告弹窗:switchTo().alert() + accept() ----------
driver.find_element(By.ID, "b1").click()                     # 点击触发警告弹窗
alert = driver.switch_to.alert                               # 课件:switchTo().alert() 切到弹窗对象
time.sleep(5)                                              # 等页面回调写结果

print("== 警告弹窗(只有确定按钮)==")
print("alert.text 读到弹窗文字 =", alert.text)                # 弹窗文字也能读
assert alert.text == "此网页显示 hello!", "警告弹窗文本不符"                    # 断言弹窗确实弹出
alert.accept()                                               # 课件:alert.accept() 点"确定"
print("accept() 后弹窗已关闭,页面恢复正常操作")

# ---------- 15.2 确认弹窗:dismiss() 走取消分支 ----------
print("== 确认弹窗(确定/取消两个按钮)==")
driver.find_element(By.ID, "b2").click()                     # 触发确认弹窗
alert = driver.switch_to.alert                               # 切到弹窗对象
time.sleep(5)
alert.dismiss()                                              # 课件:alert.dismiss() 点"取消"
time.sleep(5)                                              # 等页面回调写结果
r = driver.find_element(By.ID, "r").text
print("dismiss() 点取消后,页面结果 =", r)
assert r == "点了取消", "dismiss 未走取消分支"                                 # 断言取消分支生效

# ---------- 15.3 确认弹窗:accept() 走确定分支 ----------
driver.find_element(By.ID, "b2").click()                     # 再次触发确认弹窗
alert = driver.switch_to.alert                               # 切到弹窗对象
alert.accept()                                               # 这次点"确定"
time.sleep(5)                                              # 等页面回调写结果
r = driver.find_element(By.ID, "r").text
print("accept() 点确定后,页面结果 =", r)
assert r == "点了确定", "accept 未走确定分支"                                 # 断言确定分支生效
print("PASS:同一个 confirm 弹窗,dismiss/accept 分别走到两条分支")

driver.quit()                                                # 关闭浏览器释放驱动
print("示例15 运行结束:警告弹窗+确认弹窗(switchTo().alert/accept/dismiss)PASS")

8.2提示弹窗

python 复制代码
import os                                                    # 环境变量 + 写本地演示页
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver

from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 本地演示页:提示按钮 + 结果区 ----------
html_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "练习页_弹窗62.html")
with open(html_path, "w", encoding="utf-8") as f:
    f.write("<html><head><meta charset='utf-8'><title>弹窗62练习页</title></head><body>"
            "<button id='b3' onclick=\"var v=prompt('Please enter yourname','');"
            "document.getElementById('r').innerText=(v===null)?'取消了':"
            "'输入:' + v\">提示弹窗</button>"
            "<div id='r'></div></body></html>")
driver.get("file:///" + html_path.replace("\\", "/"))        # 打开本地演示页
time.sleep(1)                                                # 等渲染

# ---------- 15b.1 提示弹窗:send_keys 输入 + accept 提交 ----------
print("== 提示弹窗第一轮:sendKeys('hello') + accept() ==")
driver.find_element(By.ID, "b3").click()                     # 触发提示弹窗(带输入框)
alert = driver.switch_to.alert                               # 课件:switchTo().alert()
alert.send_keys("hello")                                     # 课件:alert.sendKeys("hello") 往弹窗输入框打字h
time.sleep(5)
alert.accept()                                               # 点"确定",把输入值提交给页面
time.sleep(0.5)                                              # 等页面回调写结果
r = driver.find_element(By.ID, "r").text
print("accept 后页面结果 =", r)
assert r == "输入:hello", "send_keys 的内容未被提交"                           # 断言输入值被页面接收

# ---------- 15b.2 提示弹窗:send_keys 输入 + dismiss 放弃 ----------
print("== 提示弹窗第二轮:sendKeys('world') + dismiss() ==")
driver.find_element(By.ID, "b3").click()                     # 再次触发提示弹窗
alert = driver.switch_to.alert                               # 切到弹窗对象
alert.send_keys("world")                                     # 先打字
time.sleep(5)
alert.dismiss()                                              # 课件:alert.dismiss() 点"取消"放弃输入
time.sleep(0.5)                                              # 等页面回调写结果
r = driver.find_element(By.ID, "r").text
print("dismiss 后页面结果 =", r)
assert r == "取消了", "dismiss 后不应提交输入值"                               # 断言取消分支生效
print("PASS:send_keys 输入的值,accept 才提交、dismiss 就丢弃")

driver.quit()                                                # 关闭浏览器释放驱动
print("示例15b 运行结束:提示弹窗(sendKeys/accept/dismiss)PASS")

9 ⽂件上传

点击⽂件上传的场景下会弹窗系统窗⼝,进⾏⽂件的选择。

selenium⽆法识别⾮web的控件,上传⽂件窗⼝为系统⾃带,⽆法识别窗⼝元素

但是可以使⽤sendkeys来上传指定路径的⽂件,达到的效果是⼀样的

python 复制代码
import os                                                    # 生成演示页与待上传样本
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver


driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path))  # 启动浏览器

# ---------- 16.0 准备演示页(结构照课件:body > div > div > input[type=file]) ----------
base = os.path.dirname(os.path.abspath(__file__))            # 示例目录
html_path = os.path.join(base, "练习页_上传.html")            # 演示页路径
with open(html_path, "w", encoding="utf-8") as f:            # 写页面:div 套 div 再套 file 输入框
    f.write("<html><head><meta charset='utf-8'><title>上传练习页</title></head><body>"
            "<div><div><input type='file' id='fu'></div></div>"
            "<div id='r'>未选择文件</div>"
            "<script>document.getElementById('fu').onchange=function(){"
            "document.getElementById('r').innerText='页面已接收文件:'"
            "+this.files[0].name};</script></body></html>")
sample = os.path.join(base, "upload_sample.txt")             # 待上传的样本文件(绝对路径)
with open(sample, "w", encoding="utf-8") as f:               # 写样本内容
    f.write("selenium 文件上传测试样本")
driver.get("file:///" + html_path.replace("\\", "/"))        # 打开本地演示页
time.sleep(1)                                                # 等渲染

# ---------- 16.1 课件第 1 行:cssSelector 定位 file 输入框 ----------
ele = driver.find_element(By.CSS_SELECTOR,
                          "body > div > div > input[type=file]")   # 课件原选择器,逐层路径
print("定位到元素:tag =", ele.tag_name,
      "| type =", ele.get_attribute("type"))

# ---------- 16.2 课件第 2 行:sendKeys 文件绝对路径完成上传 ----------
print("待上传文件路径 =", sample)
ele.send_keys(sample)                                        # 课件核心:sendKeys(路径)= 代替系统弹窗选文件
time.sleep(1)                                                # 等 onchange 回调
value = ele.get_attribute("value")                           # input.value 回读
echo = driver.find_element(By.ID, "r").text                  # 页面 JS 回显
print("send_keys 后 input.value =", value)
print("页面 onchange 回显        =", echo)
assert "upload_sample.txt" in value, "文件路径未写入 input"                    # 断言路径已写入
assert echo == "页面已接收文件:upload_sample.txt", "浏览器未接收文件"           # 断言浏览器真的收到了文件
print("PASS:没碰系统弹窗,send_keys(路径) 就达到了手动选文件一样的效果")
print("(input.value 显示 C:\\fakepath\\... 是浏览器安全策略,属正常现象)")

driver.quit()                                                # 关闭浏览器释放驱动
print("示例16 运行结束:文件上传 send_keys 演示 PASS")

10.浏览器参数设置

10.1 设置无头模式

python 复制代码
import os                                                    # 路径处理
import time                                                  # 强制等待
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.chrome.options import Options        # ChromeOptions:本例主角
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver

# ---------- 课件第 1、2 行:new ChromeOptions() + addArguments("-headless") ----------
options = Options()                                          # 课件 new ChromeOptions()
options.add_argument("--headless")                           # 课件 addArguments("-headless"):无头开关
options.add_argument("--window-size=1920,1080")              # 无头下给一个虚拟视口,截图/布局才正常

# ---------- 课件第 3 行:new ChromeDriver(options) ----------
driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver
driver = webdriver.Chrome(service=Service(driver_path), options=options)  # 带无头参数启动
print("浏览器已在后台启动:此刻你桌面上应该看不到任何 Chrome 窗口")

# ---------- 课件第 4 行:driver.get(...),并证明无头下功能正常 ----------
driver.get("https://www.baidu.com")                          # 课件 driver.get("https://www.baidu.com")
time.sleep(2)                                                # 等后台渲染
print("无头模式读标题 title =", driver.title)                 # 功能证明1:标题读得到
assert driver.title == "百度一下,你就知道", "无头模式页面异常"                    # 断言页面正常打开
box = driver.find_elements(By.ID, "chat-textarea")           # 功能证明2:元素找得到
print("无头模式找搜索框:命中", len(box), "个")
assert box, "无头模式下找不到搜索框"
shot = os.path.join(os.path.dirname(os.path.abspath(__file__)), "截图_无头模式.png")
driver.get_screenshot_as_file(shot)                          # 功能证明3:后台也能截图
print("无头模式截图已保存 =", shot, "(", os.path.getsize(shot), "字节)")

# ---------- 课件第 5 行:driver.quit() ----------
driver.quit()                                                # 课件 driver.quit()
print("示例17 运行结束:全程无窗口,无头模式演示 PASS")

10.2设置浏览器加载模式

python 复制代码
import os                                                    # 环境变量控制后台运行
import time                                                  # 计时用
from selenium import webdriver                               # Selenium 入口
from selenium.webdriver.chrome.service import Service        # 指定 chromedriver
from selenium.webdriver.chrome.options import Options        # ChromeOptions:本例主角
from selenium.webdriver.common.by import By                  # 定位方式
from webdriver_manager.chrome import ChromeDriverManager     # 自动管理 chromedriver

HEADLESS = os.environ.get("DEMO_HEADLESS", "0") == "1"       # 批量验证置 1 后台跑
driver_path = ChromeDriverManager().install()                # 匹配本地 chromedriver

def make_opts(strategy):
    o = Options()                                            # 每组实验独立的参数对象
    o.page_load_strategy = strategy                          # 课件 setPageLoadStrategy(...)
    if HEADLESS:
        o.add_argument("--headless")                         # 验证环境兼容
        o.add_argument("--no-sandbox")
        o.add_argument("--disable-dev-shm-usage")
    return o

# ---------- 实验1:策略 NONE(课件演示档) ----------
d1 = webdriver.Chrome(service=Service(driver_path), options=make_opts("none"))
t0 = time.time()                                             # 计时开始
d1.get("https://www.baidu.com")                              # none:get 几乎立即返回
cost_none = time.time() - t0                                 # get 耗时
print("== 策略 none(课件 setPageLoadStrategy(NONE))==")
print("get() 返回耗时 = %.2f 秒(不等页面加载完就返回了)" % cost_none)
n0 = len(d1.find_elements(By.ID, "chat-textarea"))           # 返回瞬间页面可能还没渲染
print("get 返回的瞬间找搜索框:命中 %d 个(0 说明页面还没加载出来)" % n0)
time.sleep(3)                                                # 页面在后台继续加载
n1 = len(d1.find_elements(By.ID, "chat-textarea"))           # 等一会再找
print("等 3 秒后再找搜索框:命中 %d 个(页面后台加载完成)" % n1)
assert n1 > 0, "none 策略下页面最终应加载出元素"                              # 断言最终加载完成
print("title 此刻 =", d1.title)
d1.quit()
#
# ---------- 实验2:策略 normal(默认档,作对照) ----------
d2 = webdriver.Chrome(service=Service(driver_path), options=make_opts("normal"))
t0 = time.time()                                             # 计时开始
d2.get("https://www.baidu.com")                              # normal:get 阻塞到加载完成
cost_normal = time.time() - t0                               # get 耗时
print("== 策略 normal(默认,对照组)==")
print("get() 返回耗时 = %.2f 秒(等页面加载完才返回)" % cost_normal)
n2 = len(d2.find_elements(By.ID, "chat-textarea"))           # 返回瞬间元素就该在
print("get 返回的瞬间找搜索框:命中 %d 个" % n2)
assert n2 > 0, "normal 策略返回时页面应已就绪"                                # 断言返回即就绪
d2.quit()

print("对比结论:none 的 get 耗时(%.2fs) 明显小于 normal(%.2fs),"
      "代价是返回后元素可能还没出现,需要自己等待" % (cost_none, cost_normal))
print("示例17b 运行结束:浏览器加载策略演示 PASS")

11. 本次实操踩坑实录

这 5 个坑全部是本次真机运行中实际遇到的,更有复习价值:

相关推荐
小园子的小菜1 小时前
Python协程深度解析:从原理演进到实战避坑
后端·python
砚底藏山河1 小时前
量化实战:截面因子有效性检验(IC 分析与分层回测)
java·python·金融·maven
快乐の番薯1 小时前
卷王问卷考试系统自动化功能测试
运维·功能测试·自动化
GitFun2 小时前
给策略加了条-8%止损线,11年只触发1次
python·股票·量化交易
马六六i2 小时前
市面上正规的IP驱动产业新场景新工具有哪些
大数据·网络·python·tcp/ip
I Am a robert girl3 小时前
稀有事件估计的迭代去对齐:从源码视角拆解重要性采样新范式
开发语言·python·机器学习·重要性采样·蒙特卡洛方法·稀有事件估计
天若有情6733 小时前
开源|Comfort Lang v1.0.1,一款主打清爽交互的新型命令式编程语言
python·开源·交互·编程语言·项目分享·repl·comfort lang
打工仔折腾 AI4 小时前
System Prompt 替代 Few-shot:用规则约束大模型输出的省钱实践
java·人工智能·python·spring·langchain·prompt·ai agent 实战
打工仔折腾 AI4 小时前
从零写一个CAD 05:以鼠标为中心的滚轮缩放,招法能复用但顺序不能反
开发语言·后端·python·性能优化·计算机外设·swift·ai agent 实战