目录
- 准备工作
- 安装 Selenium 库
- 下载对应浏览器的 WebDriver
- 基础登录示例 (以 GitHub 为例)
代码详解
(图片来源网络,侵删) - 进阶技巧与最佳实践
- 使用显式等待
- 使用
By类定位元素 - 处理 iframe
- 处理弹窗
- 使用 Page Object Model (POM) 设计模式
- 完整代码示例 (结合最佳实践)
- 常见问题与解决方案
NoSuchElementException(元素未找到)ElementNotInteractableException(元素不可交互)StaleElementReferenceException(元素过时)- 页面加载缓慢
准备工作
在开始编写代码之前,你需要确保环境已经配置好。
a. 安装 Selenium 库
如果你还没有安装 Selenium,可以通过 pip 来安装:
pip install selenium
b. 下载 WebDriver
Selenium 本身不控制浏览器,它需要通过一个叫 WebDriver 的中间件来与浏览器进行通信,你需要为你将要使用的浏览器下载对应的驱动。
- Chrome 浏览器: ChromeDriver
- Firefox 浏览器: GeckoDriver
- Edge 浏览器: EdgeDriver
下载步骤 (以 ChromeDriver 为例):

- 确定你的 Chrome 浏览器版本 (在 Chrome 地址栏输入
chrome://version/查看)。 - 访问 ChromeDriver 下载页面,选择与你 Chrome 版本最匹配的驱动下载。
- 将下载的
chromedriver.exe(Windows) 或chromedriver(macOS/Linux) 文件放在一个固定的、容易找到的路径下(C:\WebDriver),或者将其所在目录添加到系统的环境变量PATH中,为了方便,我们这里假设它和你的 Python 脚本在同一个文件夹下。
基础登录示例 (以 GitHub 为例)
这个例子将演示如何打开 GitHub 登录页面,输入用户名和密码,然后点击登录按钮。
# 1. 导入必要的库
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
import time
# 2. 设置 WebDriver
# 替换 'chromedriver' 为你下载的 chromedriver 文件名
# chromedriver 在系统 PATH 中,可以只写 'chrome'
service = Service(executable_path='chromedriver')
driver = webdriver.Chrome(service=service)
# 3. 打开目标网页
driver.get("https://github.com/login")
# 4. 定位并操作元素
# 定位用户名输入框 (通过 name 属性)
username_input = driver.find_element(By.NAME, "login")
username_input.send_keys("your_github_username") # 替换为你的用户名
# 定位密码输入框 (通过 name 属性)
password_input = driver.find_element(By.NAME, "password")
password_input.send_keys("your_github_password") # 替换为你的密码
# 模拟按下回车键登录 (或者点击登录按钮)
# password_input.send_keys(Keys.RETURN)
# 或者定位登录按钮并点击
# login_button = driver.find_element(By.NAME, "commit")
# login_button.click()
# 5. 等待一下,观察登录结果
# 注意: time.sleep() 不推荐用于生产环境,仅用于演示
time.sleep(5)
# 6. 关闭浏览器
driver.quit()
代码详解
from selenium import webdriver: 导入 Selenium 的 WebDriver 模块。from selenium.webdriver.common.by import By: 导入By类,用于指定元素的定位策略 (推荐使用)。Service(executable_path='chromedriver'): 创建一个 Service 对象,告诉 Selenium ChromeDriver 的位置。webdriver.Chrome(service=service): 初始化一个 Chrome 浏览器实例。driver.get(url): 在浏览器中打开指定的 URL。driver.find_element(By.<STRATEGY>, "value"): 这是核心的元素定位方法。By.NAME: 通过name属性定位,这是最可靠的方式之一。By.ID: 通过id属性定位 (如果存在)。By.CLASS_NAME: 通过class属性定位。By.CSS_SELECTOR: 通过 CSS 选择器定位 (非常强大和灵活)。By.XPATH: 通过 XPath 路径定位 (非常强大,但语法稍复杂)。
element.send_keys(): 在输入框中输入文本。element.click(): 模拟鼠标点击。time.sleep(5): 强制脚本暂停 5 秒。这只是为了让你看到登录效果,在实际自动化中应避免使用。driver.quit(): 关闭浏览器并结束 WebDriver 会话。
进阶技巧与最佳实践
直接使用 time.sleep() 会让脚本变得不可靠,因为网络速度和页面加载时间是不确定的,最佳实践是使用 显式等待。
a. 使用显式等待
显式等待会告诉 WebDriver 在某个条件(如元素可见、可点击)满足之前,一直等待,最多等待指定的时间,如果超时,则抛出异常。
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# ...
# 等最多10秒,直到用户名输入框可见
username_input = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.NAME, "login"))
)
username_input.send_keys("your_username")
# 等最多10秒,直到登录按钮可以点击,然后点击它
login_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.NAME, "commit"))
)
login_button.click()
b. 使用 By 类
从上面的例子可以看出,使用 By.NAME 比直接写字符串 "name" 更清晰,也减少了拼写错误。

c. 处理 iframe
如果登录表单或按钮位于一个 <iframe> 或 <frame> 内,你需要先“切换”到这个 frame 中,才能定位到里面的元素。
# 切换到 iframe (可以通过 id, name, 或 WebElement 定位)
driver.switch_to.frame("frame_id_or_name")
# 现在可以在 iframe 内部定位元素了
element_in_frame = driver.find_element(By.ID, "some_id_in_frame")
# 操作完成后,切回主页面 (非常重要!)
driver.switch_to.default_content()
d. 处理弹窗
当页面出现 JavaScript 弹出的警告框、确认框或提示框时,可以使用以下方法处理:
# 点击一个触发 alert 的按钮 # driver.find_element(By.ID, "alert_button").click() # 切换到 alert alert = driver.switch_to.alert # 获取 alert 的文本 print(alert.text) # 接受 alert (点击 "确定") # alert.accept() # 或者取消 alert (点击 "取消") # alert.dismiss()
e. 使用 Page Object Model (POM) 设计模式
当你的自动化脚本变得复杂时,将页面元素定位和操作逻辑封装到类中,会使代码更易于维护和扩展,这就是 POM 模式的思想。
- 一个 Page 类 代表一个网页。
- 类中的方法代表该页面的操作。
- 类中的属性代表该页面的元素。
完整代码示例 (结合最佳实践)
下面是一个结合了显式等待、By 类和良好注释的完整登录示例。
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
def github_login(username, password):
"""
使用 Selenium 自动登录 GitHub
"""
# --- 1. 初始化 WebDriver ---
# 确保 chromedriver 在同一目录下,或在系统 PATH 中
service = Service(executable_path='chromedriver')
options = Options()
# options.add_argument("--headless") # 如果想在后台运行,取消此注释
driver = webdriver.Chrome(service=service, options=options)
try:
# --- 2. 打开登录页面 ---
driver.get("https://github.com/login")
# --- 3. 等待并填写用户名 ---
# 等最多 10 秒,直到用户名输入框可见
username_field = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.NAME, "login"))
)
username_field.send_keys(username)
# --- 4. 等待并填写密码 ---
# 等最多 10 秒,直到密码输入框可见
password_field = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.NAME, "password"))
)
password_field.send_keys(password)
# --- 5. 等待并点击登录按钮 ---
# 等最多 10 秒,直到登录按钮可以被点击
login_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.NAME, "commit"))
)
login_button.click()
# --- 6. 验证登录是否成功 ---
# 等待页面跳转,并检查是否包含用户名
WebDriverWait(driver, 10).until(
EC.title_contains(username) # 假设用户名在页面标题中
)
print("登录成功!")
print(f"当前页面标题: {driver.title}")
# 你可以在这里添加更多验证逻辑,比如检查页面上的用户头像等
except Exception as e:
print(f"登录过程中发生错误: {e}")
# 在这里可以截图,方便调试
driver.save_screenshot('login_error.png')
finally:
# --- 7. 无论成功失败,最后都关闭浏览器 ---
# time.sleep(5) # 为了观察结果,可以临时加
driver.quit()
if __name__ == "__main__":
# 替换为你的 GitHub 凭据
GITHUB_USERNAME = "your_github_username"
GITHUB_PASSWORD = "your_github_password"
github_login(GITHUB_USERNAME, GITHUB_PASSWORD)
常见问题与解决方案
a. NoSuchElementException: 元素未找到
这是最常见的错误,原因可能是:
- 定位器错误:
id,name,class等写错了,使用浏览器的开发者工具 (F12) 检查元素。 - 时机不对: 脚本在元素加载出来之前就去查找它了。解决方案:使用显式等待。
- 元素在 iframe 中: 元素在另一个 frame 内,但没有切换过去。解决方案:使用
driver.switch_to.frame()。
b. ElementNotInteractableException: 元素不可交互
找到了元素,但无法点击或输入,原因可能是:
-
元素被遮挡: 页面上有其他元素(如弹窗、广告)覆盖了目标元素,尝试先关闭遮挡元素,或者使用 JavaScript 强制点击。
-
元素被禁用: 元素有
disabled属性。 -
元素不在视口内: 元素在页面需要滚动才能看到的地方,可以先滚动到该元素。
from selenium.webdriver.common.action_chains import ActionChains element = driver.find_element(By.ID, "some_element") ActionChains(driver).move_to_element(element).perform() element.click()
c. StaleElementReferenceException: 元素过时
你之前定位了一个元素,但之后页面发生了更新(AJAX 请求导致页面局部刷新),导致之前定位的元素引用失效(变成了“僵尸引用”)。
解决方案:
- 重新定位元素: 在每次操作元素前,都重新
find_element一次。 - 使用更稳定的定位策略: 优先使用
id或name,它们通常比class或xpath更稳定。 - 将操作放在等待条件里: 使用
expected_conditions中返回WebElement的方法,如EC.visibility_of_element_located,它内部会处理元素的刷新问题。
d. 页面加载缓慢
- 禁用图片和 CSS: 加载图片和 CSS 会显著增加页面加载时间,可以通过
ChromeOptions来禁用它们。options = Options() prefs = {"profile.managed_default_content_settings.images": 2} options.add_experimental_option("prefs", prefs) driver = webdriver.Chrome(service=service, options=options) - 使用隐式等待: 在
driver.get()之后,可以设置一个隐式等待,作为所有find_element操作的全局超时。driver.implicitly_wait(10) # 隐式等待最多10秒 # 之后所有的 find_element 都会等待最多10秒
注意: 显式等待通常比隐式等待更推荐,因为它更精确,可以针对特定元素和条件设置。
