4、浏览器操作:打开与关闭浏览器、窗口大小设置、前进与后退、页面刷新、窗口切换与句柄管理、页面截图
浏览器操作这块,说白了就是咱们和浏览器打交道的「基本功」。我刚开始学 Selenium 的时候,觉得不就是打开、关闭嘛,有啥好学的?结果真到项目里,各种窗口乱跳、句柄搞混、截图失败……踩的坑一个接一个。今天咱们就把这些操作捋清楚,保证你以后遇到类似问题心里有底。
4.1 打开与关闭浏览器
打开浏览器,最常用的就是 webdriver.Chrome() 或者 webdriver.Firefox()。但这里有个细节——我建议你养成指定浏览器路径的习惯,尤其是公司电脑装了多个版本的时候。
from selenium import webdriver
# 指定 Chrome 驱动路径(推荐)
driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
# 或者直接调用(前提是驱动在 PATH 里)
driver = webdriver.Chrome()
# 打开一个网页
driver.get('https://www.example.com')
# 关闭当前窗口
driver.close()
# 退出整个浏览器进程
driver.quit()
close() 和 quit() 的区别很大。close 只关当前窗口,quit 会关掉所有窗口并结束驱动进程。我见过有人只用了 close,结果测试跑完 Chrome 进程还挂着,内存泄漏了。
嗯,这里要特别提一句:每次用完一定要调 quit()。我曾经在写一个批量脚本时忘了加,跑了 200 次用例,电脑直接卡死……从那以后我都在 finally 块里写 driver.quit()。
4.2 窗口大小设置
窗口大小设置,说白了就是模拟不同分辨率的用户。你想想看,有些页面在 1920 宽屏上显示正常,一缩到 1366 就崩了。所以这个功能在响应式测试里特别有用。
# 最大化窗口
driver.maximize_window()
# 设置固定尺寸(宽 x 高)
driver.set_window_size(1366, 768)
# 获取当前窗口尺寸
size = driver.get_window_size()
print(f"当前窗口宽度:{size['width']},高度:{size['height']}")
maximize_window(),这样能避免很多因为窗口太小导致的元素定位失败。尤其是那些用了固定定位的弹窗,窗口小了根本点不到。
还有一个冷知识——set_window_size 的参数单位是像素,但不同操作系统的 DPI 缩放会影响实际显示效果。我在 Mac 上遇到过,设了 1366 结果实际显示只有 1024 的效果,后来发现是 Retina 屏的缩放问题。解决办法是手动算一下缩放比例,或者直接用 maximize_window 省心。
4.3 前进与后退
前进后退,模拟的是浏览器的「←」和「→」按钮。这个在测试多步骤流程时特别常用,比如注册流程中用户点返回修改信息。
# 先打开两个页面
driver.get('https://www.example.com/page1')
driver.get('https://www.example.com/page2')
# 后退到 page1
driver.back()
# 再前进到 page2
driver.forward()
说实话,这个功能看起来简单,但坑也不少。我遇到过一个问题:如果页面用了大量的 AJAX 加载,back() 之后页面可能没有完全刷新。比如你从购物车页后退到商品列表页,列表可能还是缓存状态。这时候我一般会在 back() 之后加个 time.sleep(1) 或者显式等待,确保页面稳定了再操作。
back() 结果页面根本没变化。后来发现 SPA 的路由变化不触发浏览器历史记录,得用 JavaScript 的 window.history.back() 才行。所以遇到单页应用,建议先确认一下路由机制。
4.4 页面刷新
刷新页面,最常见的场景就是测试「提交表单后页面是否重置」或者「刷新后数据是否丢失」。
# 方法一:直接刷新
driver.refresh()
# 方法二:用 get 重新加载当前 URL(效果一样)
driver.get(driver.current_url)
我个人习惯用 refresh(),因为它更语义化。但要注意一点:刷新后页面上的所有状态都会丢失,包括你之前定位到的元素引用。我踩过这个坑——刷新前存了一个元素对象,刷新后直接去点它,结果报了 StaleElementReferenceException。解决办法是刷新后重新定位元素。
refresh() 会直接确认,不会等你处理弹窗。所以测试前最好先确认页面状态。
4.5 窗口切换与句柄管理
窗口切换,这是很多新手最头疼的部分。说白了,每个浏览器窗口或标签页都有一个唯一的「句柄」(handle),就像人的身份证号。你要操作哪个窗口,就得先切换到那个句柄。
# 获取所有窗口句柄
handles = driver.window_handles
print(f"当前有 {len(handles)} 个窗口")
# 切换到新打开的窗口(通常是最后一个)
driver.switch_to.window(handles[-1])
# 或者根据标题切换
for handle in handles:
driver.switch_to.window(handle)
if "目标标题" in driver.title:
break
# 关闭当前窗口后,记得切回主窗口
driver.close()
driver.switch_to.window(handles[0])
嗯,这里有个经典场景:点击一个链接,新标签页打开。我刚开始写的时候,以为 click() 之后自动就切过去了,结果定位了半天都找不到元素。后来才明白,Selenium 不会自动切换窗口,你得手动切。
WebDriverWait 等待句柄数量增加,然后再切。这样比直接 time.sleep 靠谱多了。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 点击前记录
original_handles = driver.window_handles
# 点击打开新窗口的按钮
driver.find_element(By.ID, 'open-new-window').click()
# 等待新窗口出现
WebDriverWait(driver, 10).until(
lambda d: len(d.window_handles) > len(original_handles)
)
# 切换到新窗口
new_handle = [h for h in driver.window_handles if h not in original_handles][0]
driver.switch_to.window(new_handle)
还有一个容易忽略的点:关闭窗口后,句柄列表会更新。如果你之前存了句柄列表,关闭一个窗口后,那个列表就失效了。我建议每次切换前都重新获取 window_handles,别偷懒。
4.6 页面截图
截图功能,说白了就是「有图有真相」。测试失败时截个图,比写一百行日志都管用。我每次跑回归测试,都会在断言失败的地方自动截图,方便排查。
# 截取当前页面全屏
driver.save_screenshot('screenshot.png')
# 或者用 get_screenshot_as_file(效果一样)
driver.get_screenshot_as_file('/path/to/screenshot.png')
# 截取某个元素(需要先定位)
element = driver.find_element(By.ID, 'error-message')
element.screenshot('element_screenshot.png')
os.path.abspath() 转一下。
还有一个高级用法——全页面截图。默认的 save_screenshot 只截取可视区域,如果页面很长,滚动条以下的内容就没了。我一般用这个方案:
# 获取页面总高度
total_height = driver.execute_script("return document.body.scrollHeight")
viewport_height = driver.execute_script("return window.innerHeight")
# 设置窗口高度为总高度(这样就能截全了)
driver.set_window_size(1366, total_height)
driver.save_screenshot('full_page.png')
# 截完记得恢复窗口大小
driver.set_window_size(1366, viewport_height)
PIL 库手动拼接多张截图,或者直接用第三方工具如 selenium-wire。
最后说一句:截图命名最好带上时间戳和用例名。我习惯用 f"{test_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png",这样一眼就能看出是哪条用例、什么时候失败的。不然截图一多,找起来真要命。
好了,浏览器操作这块就聊到这儿。说白了,这些操作都不难,但细节决定成败。你想想看,窗口没切对、截图没保存、刷新后元素失效……这些小问题一旦出现,排查起来特别费时间。我的建议是:把这些操作封装成工具函数,比如 switch_to_new_window()、take_screenshot(),以后直接调用,省心又省力。
下一章咱们聊聊「元素定位」,那可是自动化测试的核心中的核心。到时候见!