3、Selenium基础入门:WebDriver核心概念、元素定位八大方法、浏览器基本操作
好,咱们直接进入正题。Selenium 这东西,说白了就是让浏览器听你指挥的工具。你写一行代码,浏览器就乖乖打开网页、点击按钮、填写表单。我刚开始接触自动化测试那会儿,觉得这玩意儿挺神奇的,后来才发现,核心就三个东西:WebDriver、元素定位、浏览器操作。今天咱们一个一个掰开揉碎了讲。
3.1 WebDriver 核心概念
WebDriver 是 Selenium 的灵魂。你可以把它理解成一个「遥控器」。你通过这个遥控器给浏览器发指令,浏览器执行完再把结果返回来。
我个人习惯把 WebDriver 比作「司机」。你告诉司机去哪(打开网址)、怎么走(点击哪里)、停多久(等待时间),司机就照做。不同的浏览器需要不同的司机——Chrome 用 ChromeDriver,Firefox 用 GeckoDriver。嗯,这里要注意:驱动版本必须和浏览器版本匹配,否则会报错。我在项目中遇到过好几次,升级了浏览器忘了升级驱动,结果脚本全挂,排查了半天才发现是版本不匹配。
核心要点:
- WebDriver 是浏览器原生支持的自动化接口
- 每个浏览器有独立的驱动(driver)可执行文件
- 驱动通过 HTTP 协议与浏览器通信
- 一个 WebDriver 实例对应一个浏览器窗口
初始化一个 WebDriver 很简单,代码就几行:
from selenium import webdriver
# 创建 Chrome 浏览器实例
driver = webdriver.Chrome() # 前提:chromedriver 在 PATH 中
# 或者指定驱动路径
# driver = webdriver.Chrome(executable_path='/path/to/chromedriver')
# 打开网页
driver.get('https://www.example.com')
# 用完记得关闭
driver.quit()
你想想看,这就像你打开浏览器、输入网址、回车。只不过现在是用代码来做。为什么推荐用 quit() 而不是 close()?close() 只关闭当前标签页,quit() 会关闭整个浏览器并释放驱动进程。我建议一律用 quit(),省得内存泄漏。
3.2 元素定位八大方法
自动化最核心的活儿就是「找到元素」。你找不到按钮,怎么点?你找不到输入框,怎么填?Selenium 提供了 8 种定位方式,我按常用程度排个序:
| 定位方法 | Python 写法 | 适用场景 |
|---|---|---|
| ID | find_element(By.ID, "id值") |
最优先,唯一且稳定 |
| Name | find_element(By.NAME, "name值") |
表单元素常用 |
| Class Name | find_element(By.CLASS_NAME, "class值") |
样式类定位,注意可能重复 |
| Tag Name | find_element(By.TAG_NAME, "标签名") |
定位一组同类元素 |
| Link Text | find_element(By.LINK_TEXT, "完整链接文字") |
定位超链接 |
| Partial Link Text | find_element(By.PARTIAL_LINK_TEXT, "部分文字") |
链接文字太长时用 |
| XPath | find_element(By.XPATH, "xpath表达式") |
万能定位,但性能稍差 |
| CSS Selector | find_element(By.CSS_SELECTOR, "css选择器") |
速度快,语法简洁 |
我个人习惯的优先级是:ID > CSS > XPath > 其他。为什么?ID 最快最稳,CSS 比 XPath 快,XPath 虽然万能但容易写得又臭又长。我曾经接手过一个项目,里面全是 //div[@class='...']/span[2]/a[1] 这种 XPath,页面稍微改个结构就全崩了。你想想看,这维护成本得多高?
3.3 八大方法详解与实战
3.3.1 ID 定位
最推荐的方式。ID 在页面中应该是唯一的,所以定位最快。
# 定位搜索框
search_box = driver.find_element(By.ID, "search-input")
search_box.send_keys("Selenium教程")
3.3.2 Name 定位
表单元素经常有 name 属性,比如用户名、密码输入框。
driver.find_element(By.NAME, "username").send_keys("admin")
3.3.3 Class Name 定位
注意:class 可能重复,find_element 只返回第一个。
driver.find_element(By.CLASS_NAME, "btn-primary").click()
3.3.4 Tag Name 定位
适合获取所有同类标签,比如获取页面所有链接。
all_links = driver.find_elements(By.TAG_NAME, "a")
for link in all_links:
print(link.get_attribute("href"))
3.3.5 Link Text 与 Partial Link Text
专门定位 <a> 标签,用可见文字来定位。
# 精确匹配
driver.find_element(By.LINK_TEXT, "点击这里注册").click()
# 模糊匹配
driver.find_element(By.PARTIAL_LINK_TEXT, "注册").click()
3.3.6 XPath 定位
XPath 是重头戏。它可以在 DOM 树中任意穿梭,但写不好就是灾难。
# 绝对路径(不推荐)
driver.find_element(By.XPATH, "/html/body/div[2]/form/input[1]")
# 相对路径(推荐)
driver.find_element(By.XPATH, "//input[@id='username']")
# 包含文本
driver.find_element(By.XPATH, "//button[contains(text(), '提交')]")
# 多条件组合
driver.find_element(By.XPATH, "//input[@type='text' and @name='email']")
我的经验:写 XPath 时尽量用相对路径,少用索引。比如 //div[@class='list']//a[1] 这种,页面加个元素就废了。多用 contains()、text() 这些函数,灵活很多。
3.3.7 CSS Selector 定位
CSS 选择器比 XPath 简洁,性能也更好。我越来越喜欢用它。
# ID 选择器
driver.find_element(By.CSS_SELECTOR, "#username")
# class 选择器
driver.find_element(By.CSS_SELECTOR, ".btn-primary")
# 属性选择器
driver.find_element(By.CSS_SELECTOR, "input[name='email']")
# 子元素选择器
driver.find_element(By.CSS_SELECTOR, "div.form-group > input")
# 伪类选择器
driver.find_element(By.CSS_SELECTOR, "button:contains('提交')") # 部分浏览器支持
避坑指南:我曾经在定位一个动态 ID 的元素时,ID 每次刷新都会变(比如 id="msg_12345")。这时候用 ID 定位就废了。我的做法是用 CSS 的 ^=(以...开头)或 $=(以...结尾)来匹配:[id^='msg_']。这招很实用。
3.4 浏览器基本操作
定位到元素之后,剩下的就是操作了。浏览器基本操作就那么几个,我列一下:
3.4.1 窗口操作
# 最大化窗口
driver.maximize_window()
# 设置窗口大小
driver.set_window_size(1024, 768)
# 获取窗口位置
print(driver.get_window_position())
# 滚动页面(用 JavaScript)
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
3.4.2 导航操作
# 打开网址
driver.get("https://www.baidu.com")
# 后退
driver.back()
# 前进
driver.forward()
# 刷新
driver.refresh()
# 获取当前 URL
print(driver.current_url)
# 获取页面标题
print(driver.title)
3.4.3 元素交互操作
# 点击
element.click()
# 输入文本
element.send_keys("Hello World")
# 清空输入框
element.clear()
# 获取元素文本
print(element.text)
# 获取属性值
print(element.get_attribute("href"))
# 判断是否可见
print(element.is_displayed())
# 判断是否可用
print(element.is_enabled())
3.4.4 等待机制
这个必须单独拎出来说。页面加载需要时间,元素可能还没渲染出来你就去定位,肯定报错。我刚开始学的时候经常踩这个坑。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 显式等待:等待元素出现,最多等10秒
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myElement"))
)
# 隐式等待:全局设置,每次定位都等
driver.implicitly_wait(10) # 最多等10秒
我的建议:显式等待比隐式等待更靠谱。隐式等待是「死等」,不管元素有没有出现都等满时间。显式等待是「聪明等」,元素一出现就继续执行。我一般用显式等待 + 合适的 expected_conditions,比如 element_to_be_clickable、visibility_of_element_located。
3.5 实战小案例:登录百度
咱们把今天学的串起来,写一个完整的例子:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 1. 启动浏览器
driver = webdriver.Chrome()
driver.maximize_window()
try:
# 2. 打开百度
driver.get("https://www.baidu.com")
# 3. 等待搜索框出现
search_box = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "kw"))
)
# 4. 输入搜索内容
search_box.send_keys("Selenium教程")
# 5. 点击搜索按钮
search_button = driver.find_element(By.ID, "su")
search_button.click()
# 6. 等待搜索结果加载
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "result"))
)
# 7. 打印当前标题
print(f"搜索完成,当前页面标题:{driver.title}")
finally:
# 8. 关闭浏览器
driver.quit()
这个例子涵盖了今天讲的大部分内容:WebDriver 初始化、元素定位、等待、操作、关闭。你把这个跑通了,Selenium 基础就算入门了。
嗯,最后说一句:自动化脚本写得好不好,关键看定位稳不稳。多花时间研究元素定位,后面你会感谢自己的。下一章咱们讲更高级的——如何处理弹窗、下拉框、iframe 这些烦人的东西。