← 返回自动化办公目录
← 返回学习笔记首页
专题: Python 自动化办公系统学习
关键词: Python, 自动化办公, Selenium, Web自动化, 浏览器, WebDriver, 元素定位
一、Selenium概述
Selenium是一个强大的Web浏览器自动化测试框架,最初由Jason Huggins于2004年在ThoughtWorks开发,用于自动化Web应用的测试工作。经过近二十年的发展,Selenium已经成为业界最广泛使用的浏览器自动化工具之一,支持Python、Java、C#、JavaScript、Ruby等多种主流编程语言。它能够模拟真实用户的操作行为——点击按钮、填写表单、滚动页面、提取数据等,是Web自动化测试和数据采集领域不可或缺的核心工具。
Selenium的自动化原理基于WebDriver协议。WebDriver是W3C标准规范,定义了一套与浏览器进行交互的远程控制协议。当你的Python脚本调用Selenium API时,指令通过JSON Wire Protocol(JSON有线协议)发送到浏览器驱动(如ChromeDriver、GeckoDriver),驱动再将指令翻译为浏览器原生的自动化指令,最终实现浏览器操控。这个架构的核心优势在于:驱动直接调用浏览器内核的自动化接口,而非通过JavaScript注入等方式,因此能够实现接近真实用户的操作效果,并且能够处理JavaScript渲染的现代Web页面。
Selenium生态包含三个主要组件:Selenium WebDriver(核心API,提供浏览器操控接口)、Selenium IDE(浏览器插件,支持录制回放,适合初学者快速上手)和Selenium Grid(分布式测试工具,支持在多台机器、多种浏览器上并行执行测试)。在日常的办公自动化场景中,WebDriver是最常用、最核心的部分,我们通常通过Python的selenium库直接调用WebDriver API来完成各种浏览器自动化任务。
Selenium支持几乎所有主流浏览器:Google Chrome(通过ChromeDriver驱动,是最常用的组合,性能和兼容性俱佳)、Mozilla Firefox(通过GeckoDriver驱动,对隐私保护场景有优势)、Microsoft Edge(新Edge基于Chromium内核,通过EdgeDriver驱动,在Windows环境表现优异)以及Apple Safari(通过safaridriver驱动,仅限macOS平台)。对于办公自动化而言,Chrome + ChromeDriver是最推荐的组合,社区资源丰富,问题排查方便。
安装Selenium库
# 安装Selenium库
pip install selenium
# 验证安装
python -c "import selenium; print(selenium.__version__)"
WebDriver架构示意
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
# 配置浏览器选项
options = Options()
options.add_argument('--start-maximized') # 窗口最大化
# 创建WebDriver实例(自动识别已添加到PATH的ChromeDriver)
driver = webdriver.Chrome(options=options)
# 访问目标页面
driver.get('https://www.example.com')
print(f"页面标题: {driver.title}")
# 关闭浏览器
driver.quit()
支持的浏览器一览
浏览器 驱动名称 安装方式 适用平台
Google Chrome ChromeDriver pip install webdriver-manager Windows / macOS / Linux
Mozilla Firefox GeckoDriver pip install webdriver-manager Windows / macOS / Linux
Microsoft Edge EdgeDriver pip install webdriver-manager Windows / macOS / Linux
Apple Safari safaridriver 系统内置 macOS 仅限
二、环境搭建
搭建Selenium开发环境是开始Web自动化的第一步,也是最容易出现问题的环节。核心步骤包括安装Python的selenium库、下载对应版本的浏览器驱动、以及配置驱动路径。浏览器驱动是连接Selenium脚本和浏览器之间的翻译官,它的版本必须与浏览器的版本精确匹配,否则驱动无法正常工作。以Chrome为例,你需要访问ChromeDriver官方网站(chromedriver.chromium.org),下载与你的Chrome浏览器主版本号一致的驱动文件。Chrome的主版本号可以在浏览器地址栏输入chrome://version查看,例如"Chrome 120.0.6099.71"的主版本号就是120。
手动下载驱动并配置PATH环境变量是传统做法,但更推荐使用webdriver-manager这个第三方库,它可以自动检测浏览器版本、自动下载匹配的驱动,大幅降低环境配置的复杂度。只需执行pip install webdriver-manager安装该库,然后在代码中通过ChromeDriverManager().install()自动管理驱动即可。此外,无界面模式(headless mode)是自动化办公中的一个重要特性——在没有图形界面的服务器上(如Linux云服务器),你可以让浏览器在后台运行,不显示窗口,从而节省系统资源并提升执行效率。
浏览器的启动选项配置是环境搭建中的关键技能。通过Options对象,你可以精细控制浏览器行为:禁止GPU加速、禁用自动化提示条、设置窗口大小、配置用户数据目录以保持登录状态、设置代理、修改语言偏好等。合理配置这些选项不仅能提升自动化脚本的稳定性,还能在某些场景下绕过网站的自动化检测。以下分别展示使用webdriver-manager自动配置驱动的完整代码,以及无界面模式的配置方法。
使用webdriver-manager自动管理驱动
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)
driver.get('https://www.baidu.com')
print(driver.title)
driver.quit()
无界面模式(Headless)配置
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--headless') # 启用无界面模式
options.add_argument('--no-sandbox') # 绕过沙盒限制(Linux服务器必备)
options.add_argument('--disable-gpu') # 禁用GPU加速(Windows兼容性)
options.add_argument('--window-size=1920,1080') # 设置虚拟窗口尺寸
options.add_argument('--disable-blink-features=AutomationControlled') # 隐藏自动化标识
driver = webdriver.Chrome(options=options)
driver.get('https://www.example.com')
print(f"页面标题: {driver.title}")
print(f"页面截图已保存至: screenshot.png")
driver.save_screenshot('screenshot.png')
driver.quit()
浏览器选项配置详解
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
# 基础配置
options.add_argument('--start-maximized') # 启动时最大化窗口
options.add_argument('--lang=zh-CN') # 设置浏览器语言
options.add_argument('--user-agent=Mozilla/5.0 ...') # 自定义User-Agent
options.add_experimental_option('excludeSwitches', ['enable-automation']) # 隐藏"Chrome正受到自动软件控制"
options.add_experimental_option('useAutomationExtension', False) # 禁用自动化扩展
# 用户数据目录(保持登录状态)
options.add_argument('--user-data-dir=C:/Users/用户名/AppData/Local/Google/Chrome/User Data')
# 禁用图片加载(提升速度)
prefs = {'profile.managed_default_content_settings.images': 2}
options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(options=options)
print("浏览器已启动,选项配置完成")
driver.quit()
三、元素定位
元素定位是Selenium自动化的核心基本功。浏览器页面本质上是一棵DOM(文档对象模型)树,Selenium通过在这棵树中查找特定元素来执行后续的交互操作。Selenium WebDriver提供了8大元素定位策略(By策略),分别是:By.ID(通过元素ID查找,定位速度最快,ID在页面中应唯一)、By.NAME(通过HTML的name属性查找,常用于表单元素)、By.CLASS_NAME(通过CSS类名查找)、By.TAG_NAME(通过HTML标签名查找,如div/a/input)、By.LINK_TEXT(通过超链接的完整文本查找)、By.PARTIAL_LINK_TEXT(通过超链接的部分文本模糊查找)、By.XPATH(通过XPath表达式查找,灵活强大但性能略低)和By.CSS_SELECTOR(通过CSS选择器查找,性能优异,推荐首选)。
在实际项目中,推荐优先使用ID、CSS_SELECTOR和XPATH这三种策略。ID是最高效的定位方式,因为每个ID在页面中具有唯一性;CSS选择器在速度和表达能力之间取得了最佳平衡,是大多数场景下的首选;XPath则因为其强大的遍历能力(沿DOM树向上/向下/横向搜索),适用于复杂嵌套结构和动态内容页面。对于定位单个元素使用find_element,定位多个元素使用find_elements(返回列表),这在批量采集数据时尤其关键。此外,Selenium 4还引入了相对定位器(Relative Locator),通过视觉位置(上方、下方、左侧、右侧、附近)来定位元素,为元素定位提供了全新的维度。
定位不到元素是自动化脚本最常见的失败原因之一。常见原因包括:页面未完全加载就执行了查找操作(需要使用等待机制)、元素位于iframe中(需要先切换到iframe)、元素在弹出窗口中(需要先切换窗口)、或者元素是动态生成的(需要通过更灵活的策略定位)。掌握多种定位策略并理解DOM树结构,是写出稳定可靠自动化脚本的前提。以下是8大定位策略的完整示例代码和相关操作。
八大定位策略完整示例
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.example.com')
# 1. By.ID — 最快速,推荐
element = driver.find_element(By.ID, 'username')
# 2. By.NAME — 常用于表单
element = driver.find_element(By.NAME, 'password')
# 3. By.CLASS_NAME — 按CSS类名
element = driver.find_element(By.CLASS_NAME, 'btn-primary')
# 4. By.TAG_NAME — 按标签名
element = driver.find_element(By.TAG_NAME, 'h1')
# 5. By.LINK_TEXT — 完整链接文本
element = driver.find_element(By.LINK_TEXT, '点击这里注册')
# 6. By.PARTIAL_LINK_TEXT — 部分链接文本
element = driver.find_element(By.PARTIAL_LINK_TEXT, '注册')
# 7. By.XPATH — 最灵活
element = driver.find_element(By.XPATH, '//input[@id="username"]')
driver.find_element(By.XPATH, '//div[@class="content"]//button[text()="提交"]')
# 8. By.CSS_SELECTOR — 推荐首选
element = driver.find_element(By.CSS_SELECTOR, '#username')
driver.find_element(By.CSS_SELECTOR, '.btn-primary.submit-btn')
driver.find_element(By.CSS_SELECTOR, 'div.content > button[type="submit"]')
driver.quit()
多元素定位与相对定位器
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.relative_locator import locate_with
driver = webdriver.Chrome()
driver.get('https://www.example.com/products')
# 获取所有商品价格元素
prices = driver.find_elements(By.CLASS_NAME, 'product-price')
for price in prices:
print(price.text)
# 获取所有链接
links = driver.find_elements(By.TAG_NAME, 'a')
print(f"页面共有 {len(links)} 个链接")
# Selenium 4 相对定位器:查找"提交按钮"上方的输入框
submit_btn = driver.find_element(By.ID, 'submit')
input_field = driver.find_element(locate_with(By.TAG_NAME, 'input').above(submit_btn))
input_field.send_keys('相对定位器示例')
# 查找登录框右侧的元素
login_btn = driver.find_element(By.ID, 'login-btn')
help_link = driver.find_element(locate_with(By.TAG_NAME, 'a').to_right_of(login_btn))
print(f"右侧元素文本: {help_link.text}")
driver.quit()
四、页面交互
成功定位到元素之后,下一步就是与页面进行交互操作。Selenium提供了丰富的交互API,覆盖了用户在浏览器中的大部分操作场景。最基本的交互操作包括:click()点击元素(按钮、链接、复选框等)、send_keys()输入文字(文本框、文本域)、clear()清除输入框内容、submit()提交表单。这些方法封装了对底层DOM事件的触发,能够模拟真实用户的操作行为。例如在使用send_keys输入文字时,Selenium会依次触发focus、keydown、keypress、input、keyup等事件序列,与真实用户键盘输入时浏览器产生的事件序列完全一致。
对于更复杂的交互场景,Selenium提供了专门的工具类。Select类用于处理HTML下拉选择框(元素),支持通过选项文本、索引或value值来选择选项。ActionChains类用于执行复杂的鼠标和键盘操作序列——拖拽元素(drag_and_drop)、鼠标悬停(move_to_element)、右键点击(context_click)、双击(double_click)、按住不放(click_and_hold)等。键盘操作通过Keys类实现,可以发送回车(Keys.ENTER)、Tab键(Keys.TAB)、组合键(如Ctrl+A、Ctrl+C)等。文件上传场景只需通过send_keys将本地文件的绝对路径发送到文件选择输入框即可,无需处理文件选择对话框。表单填写是办公自动化中最常见的需求,将上述操作组合起来,就能实现Web表单的自动填写和提交。
基础交互操作
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.example.com/login')
# 输入用户名和密码
username = driver.find_element(By.ID, 'username')
password = driver.find_element(By.ID, 'password')
username.clear() # 清除已有内容
username.send_keys('admin')
password.clear()
password.send_keys('my_password')
# 点击登录按钮
driver.find_element(By.ID, 'login-btn').click()
# 复选框操作
checkbox = driver.find_element(By.NAME, 'agree-terms')
if not checkbox.is_selected():
checkbox.click() # 勾选复选框
# 获取输入框当前值
entered_value = username.get_attribute('value')
print(f"输入框中的值: {entered_value}")
driver.quit()
下拉选择与拖拽操作
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.webdriver import ActionChains
driver = webdriver.Chrome()
driver.get('https://www.example.com/form')
# === 下拉选择框 Select ===
select_element = driver.find_element(By.NAME, 'city')
select = Select(select_element)
# 三种选择方式
select.select_by_visible_text('北京') # 按可见文本
select.select_by_value('shanghai') # 按value属性
select.select_by_index(2) # 按索引(从0开始)
# 获取所有选项
all_options = select.options
for opt in all_options:
print(f"选项: {opt.text}, 值: {opt.get_attribute('value')}")
# === ActionChains 拖拽操作 ===
source = driver.find_element(By.ID, 'drag-item')
target = driver.find_element(By.ID, 'drop-zone')
actions = ActionChains(driver)
actions.drag_and_drop(source, target).perform() # 拖拽到目标
# 分步拖拽
actions.click_and_hold(source).move_to_element(target).release().perform()
driver.quit()
键盘操作与文件上传
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
import os
driver = webdriver.Chrome()
driver.get('https://www.example.com/form')
# === Keys 键盘操作 ===
search_box = driver.find_element(By.NAME, 'q')
search_box.send_keys('Selenium教程')
search_box.send_keys(Keys.ENTER) # 回车搜索
# 组合键:Ctrl+A 全选
actions = ActionChains(driver)
actions.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
# 组合键:Ctrl+C 复制
actions.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
# Tab键跳到下一个输入框
actions.send_keys(Keys.TAB).perform()
# === 文件上传 ===
# 直接发送文件路径到文件选择输入框
file_input = driver.find_element(By.CSS_SELECTOR, 'input[type="file"]')
file_path = os.path.abspath('document.pdf')
file_input.send_keys(file_path) # 注意:没有点击操作,直接send_keys即可
print(f"已上传文件: {file_path}")
driver.quit()
五、等待机制
等待机制是Selenium自动化脚本稳定性的基石。现代Web应用大量使用AJAX、JavaScript动态渲染技术,页面元素并非在页面加载完成时全部就绪,而是按需异步加载。如果不加等待直接查找元素,很可能因为元素尚未渲染到DOM中而抛出NoSuchElementException异常。Selenium提供了三大类等待机制来应对这个问题:隐式等待、显式等待和Fluent等待。合理选择和组合这些等待策略,是编写健壮自动化脚本的关键。
隐式等待(implicitly_wait)是最基础的等待方式,设置一个全局的超时时间(以秒为单位)。当查找元素时,如果元素没有立即出现,WebDriver会以固定间隔轮询DOM,直到元素出现或超时。隐式等待设置一次,作用于整个WebDriver生命周期中的所有find_element操作。它的优点是简单易用,缺点是轮询间隔固定(约500ms),无法针对不同元素设置不同等待条件,不够精细。显式等待(WebDriverWait)则是针对特定元素的精细等待方案。通过WebDriverWait配合expected_conditions(预期条件类),可以精确等待某个条件成立(如元素可见、可点击、包含特定文本等),超时抛TimeoutException。显式等待的颗粒度更细,等待条件更丰富,是实际项目中最推荐的方式。
FluentWait是显式等待的增强版,允许自定义轮询间隔和忽略特定异常(在轮询过程中遇到某些异常时不立即失败,而是继续轮询直到超时)。这在处理页面加载过程中可能短暂出现的错误状态(如临时性的StaleElementReferenceException)时特别有用。在实际项目中,最佳实践是将隐式等待(设为较短时间如5秒作为保底)与显式等待(针对关键元素精细等待)结合使用。
隐式等待 vs 显式等待
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
driver = webdriver.Chrome()
# === 隐式等待(全局设置一次)===
driver.implicitly_wait(10) # 所有find_element最多等待10秒
# 此后所有 find_element 调用都会自动等待最多10秒
driver.get('https://www.example.com')
element = driver.find_element(By.ID, 'dynamic-content')
print(f"隐式等待找到元素: {element.text}")
# === 显式等待(精确控制)===
driver.get('https://www.example.com/slow-page')
# 等待元素可见
element = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.ID, 'result'))
)
print(f"元素可见: {element.text}")
# 等待元素可点击
button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, 'submit-btn'))
)
button.click()
print("按钮已点击")
# 等待元素包含特定文本
WebDriverWait(driver, 10).until(
EC.text_to_be_present_in_element((By.ID, 'status'), '操作成功')
)
# 等待元素消失
WebDriverWait(driver, 10).until(
EC.invisibility_of_element_located((By.CLASS_NAME, 'loading-spinner'))
)
driver.quit()
expected_conditions 常用条件汇总
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
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)
# 常用预期条件一览
wait.until(EC.title_is('页面标题')) # 标题精确匹配
wait.until(EC.title_contains('部分标题')) # 标题包含
wait.until(EC.presence_of_element_located((By.ID, 'el'))) # 元素出现在DOM中
wait.until(EC.visibility_of_element_located((By.ID, 'el'))) # 元素可见
wait.until(EC.invisibility_of_element_located((By.ID, 'el'))) # 元素不可见/消失
wait.until(EC.element_to_be_clickable((By.ID, 'btn'))) # 元素可点击
wait.until(EC.text_to_be_present_in_element((By.ID, 'el'), '文本')) # 元素包含文本
wait.until(EC.frame_to_be_available_and_switch_to_it('frame-name')) # 等待frame可用并切换
wait.until(EC.alert_is_present()) # 弹窗出现
wait.until(EC.number_of_windows_to_be(2)) # 窗口数等于2
wait.until(EC.staleness_of(element)) # 元素失效(DOM被刷新)
driver.quit()
FluentWait 自定义等待
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
from selenium.common.exceptions import StaleElementReferenceException
driver = webdriver.Chrome()
driver.get('https://www.example.com')
# FluentWait: 自定义轮询间隔 + 忽略特定异常
wait = WebDriverWait(
driver,
timeout=15, # 最长等待15秒
poll_frequency=0.3, # 每300ms轮询一次(默认500ms)
ignored_exceptions=[StaleElementReferenceException] # 忽略"元素过期"异常
)
# 使用自定义等待查找动态加载的内容
element = wait.until(
EC.presence_of_element_located((By.CLASS_NAME, 'dynamic-data'))
)
print(f"动态内容: {element.text}")
# 自定义等待条件:等待页面中某个数字大于100
def number_greater_than_100(driver):
element = driver.find_element(By.ID, 'counter')
value = int(element.text)
return value > 100
result = wait.until(number_greater_than_100)
print(f"计数器超过100了!")
driver.quit()
六、窗口与框架
现代Web应用中,多窗口、内嵌框架(iframe)和弹窗(alert/confirm/prompt)是非常普遍的设计模式。管理这些不同的上下文环境是Selenium自动化的重要技能。每个浏览器窗口和标签页在Selenium中由一个唯一的窗口句柄(window handle)标识,通过driver.window_handles可以获取当前会话中所有窗口句柄的列表。当点击一个链接打开新标签页或新窗口时,Selenium并不会自动切换到新窗口——你需要显式地通过driver.switch_to.window(handle)进行切换。多窗口管理的核心是保存原始窗口句柄,执行打开新窗口的操作,然后遍历所有句柄找到目标窗口进行切换,完成操作后再切回原始窗口。
iframe(内嵌框架)是页面中嵌入的另一个独立HTML文档,常见于第三方组件(支付表单、社交分享按钮、地图嵌入等)。Selenium无法直接操作iframe内的元素——必须先通过driver.switch_to.frame(frame_reference)切换到该iframe上下文中,其中的frame_reference可以是iframe的索引(从0开始)、名称(name属性)或WebElement对象。操作完成后,通过driver.switch_to.default_content()切回主文档。多层嵌套的iframe需要逐层切换。Alert弹窗(alert/confirm/prompt)是浏览器原生对话框,通过driver.switch_to.alert获取Alert对象后,可以调用accept()确认、dismiss()取消或发送文本(仅prompt)。窗口大小设置也是实用技巧,可以模拟不同设备的屏幕尺寸。
多窗口切换与管理
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.example.com')
# 保存原始窗口句柄
main_window = driver.current_window_handle
print(f"主窗口句柄: {main_window}")
# 点击链接打开新窗口/标签页
driver.find_element(By.ID, 'open-new-window').click()
# 等待新窗口出现并获取所有句柄
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))
# 切换到新窗口
for handle in driver.window_handles:
if handle != main_window:
driver.switch_to.window(handle)
break
print(f"新窗口标题: {driver.title}")
print(f"新窗口URL: {driver.current_url}")
# 在新窗口中操作
driver.find_element(By.ID, 'new-page-btn').click()
# 关闭当前窗口并切回主窗口
driver.close() # 关闭当前窗口
driver.switch_to.window(main_window) # 切回主窗口
print(f"已切回主窗口: {driver.title}")
driver.quit()
iframe切换与Alert弹窗处理
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.example.com/iframe-page')
# === iframe 切换 ===
# 方式1:通过索引切换(第一个iframe)
driver.switch_to.frame(0)
# 方式2:通过name或id切换
driver.switch_to.frame('content-frame')
# 方式3:通过WebElement切换
iframe_element = driver.find_element(By.CSS_SELECTOR, 'iframe[src*="payment"]')
driver.switch_to.frame(iframe_element)
# 在iframe中查找元素
iframe_text = driver.find_element(By.ID, 'iframe-content').text
print(f"iframe内的文本: {iframe_text}")
# 切回主文档
driver.switch_to.default_content()
# === Alert 弹窗处理 ===
driver.find_element(By.ID, 'show-alert').click()
alert = driver.switch_to.alert
print(f"弹窗文本: {alert.text}")
alert.accept() # 点击"确定"
# alert.dismiss() # 点击"取消"
# Confirm 弹窗
driver.find_element(By.ID, 'show-confirm').click()
confirm = driver.switch_to.alert
confirm.dismiss() # 取消确认
# Prompt 弹窗
driver.find_element(By.ID, 'show-prompt').click()
prompt = driver.switch_to.alert
prompt.send_keys('这是输入的文本')
prompt.accept()
driver.quit()
窗口大小控制与新标签页
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
# 设置窗口大小
driver.set_window_size(375, 812) # 模拟iPhone X尺寸
print(f"窗口大小: {driver.get_window_size()}")
driver.set_window_position(100, 50) # 设置窗口位置
print(f"窗口位置: {driver.get_window_position()}")
# 全屏模式
driver.fullscreen_window()
# 最大化窗口
driver.maximize_window()
# 使用JavaScript打开新标签页
driver.execute_script("window.open('https://www.example.com', '_blank');")
driver.switch_to.window(driver.window_handles[1])
print(f"新标签页标题: {driver.title}")
driver.close()
driver.switch_to.window(driver.window_handles[0])
# 使用Ctrl+T快捷键新建标签页
driver.find_element(By.TAG_NAME, 'body').send_keys(Keys.CONTROL + 't')
# 切换回原始标签页
driver.find_element(By.TAG_NAME, 'body').send_keys(Keys.CONTROL + '1')
driver.quit()
七、JavaScript操作
尽管Selenium的WebDriver API覆盖了绝大多数浏览器交互场景,但在某些特殊情况下,直接执行JavaScript代码更加高效或甚至是唯一的选择。Selenium通过driver.execute_script()和driver.execute_async_script()两个方法,允许你直接在浏览器的JavaScript引擎中执行任意代码。execute_script用于同步执行(等待JS执行完毕再返回结果),execute_async_script用于异步执行(适用于需要回调的异步操作,如等待AJAX请求完成)。JS操作的典型应用场景包括:滚动页面到特定位置、修改隐藏元素的属性使其可交互、获取或设置页面的innerHTML内容、绕过某些操作限制(如禁用状态的输入框)。
页面滚动是办公自动化脚本中最常见的需求之一。有些页面采用无限滚动加载(如社交媒体、商品列表),需要通过JS控制滚动条位置来触发内容加载。通过window.scrollTo或arguments[0].scrollIntoView()可以实现精确定位滚动。此外,通过JS获取元素的计算样式、触发自定义事件、操作HTML5本地存储(localStorage/sessionStorage)等,都是execute_script的典型用法。需要注意的是,在JS中操作的元素需要作为参数传递给脚本,返回值可以是基本类型、DOM元素或列表——Selenium会自动将返回的DOM元素封装为WebElement对象。对于AJAX请求的处理,可以通过execute_async_script配合回调函数来判断页面中的异步请求是否已完成。
滚动页面与元素交互
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.example.com/long-page')
# === 滚动操作 ===
# 滚动到底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
print("已滚动到页面底部")
# 滚动到顶部
driver.execute_script("window.scrollTo(0, 0);")
# 滚动到指定像素位置
driver.execute_script("window.scrollTo(0, 500);")
# 滚动到特定元素可见
element = driver.find_element(By.ID, 'target-section')
driver.execute_script("arguments[0].scrollIntoView(true);", element)
print(f"已滚动至元素: {element.text[:30]}")
# 水平滚动
driver.execute_script("window.scrollTo(document.body.scrollWidth, 0);")
# === 修改元素属性 ===
# 修改隐藏输入框的值
driver.execute_script(
"arguments[0].value = arguments[1];",
driver.find_element(By.ID, 'hidden-input'),
'新值'
)
# 让隐藏元素可见
driver.execute_script(
"arguments[0].style.display = 'block';",
driver.find_element(By.ID, 'hidden-section')
)
driver.quit()
获取/设置页面内容
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.example.com')
# === 获取页面内容 ===
# 获取整个页面的HTML
page_html = driver.execute_script("return document.documentElement.outerHTML;")
print(f"页面HTML长度: {len(page_html)} 字符")
# 获取页面文本内容
page_text = driver.execute_script("return document.body.innerText;")
print(f"页面文本: {page_text[:100]}...")
# 获取元素的渲染样式
color = driver.execute_script(
"return window.getComputedStyle(arguments[0]).getPropertyValue('color');",
driver.find_element(By.TAG_NAME, 'h1')
)
print(f"标题颜色: {color}")
# === 操作localStorage ===
# 设置localStorage
driver.execute_script("window.localStorage.setItem('token', 'my-auth-token');")
# 读取localStorage
token = driver.execute_script("return window.localStorage.getItem('token');")
print(f"localStorage token: {token}")
# 清除localStorage
driver.execute_script("window.localStorage.clear();")
# 获取页面性能数据
performance = driver.execute_script("return window.performance.timing;")
print(f"页面加载耗时: {performance['loadEventEnd'] - performance['navigationStart']}ms")
driver.quit()
异步JavaScript与AJAX等待
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('https://www.example.com')
# === 同步执行:模拟点击(替代Selenium原生click)===
btn = driver.find_element(By.ID, 'my-button')
driver.execute_script("arguments[0].click();", btn)
print("通过JS执行点击操作")
# === 执行多个语句 ===
result = driver.execute_script("""
var element = document.getElementById('status');
var text = element.innerText;
element.style.border = '2px solid red';
return text;
""")
print(f"状态文本: {result}")
# === 异步执行:等待AJAX完成 ===
driver.execute_async_script("""
var callback = arguments[arguments.length - 1];
// 模拟等待AJAX请求完成
var checkAjax = function() {
if (window.jQuery && jQuery.active == 0) {
callback('AJAX请求已完成');
} else {
setTimeout(checkAjax, 200);
}
};
checkAjax();
""")
print("所有AJAX请求已处理完毕")
# 注入CSS样式
driver.execute_script("""
var style = document.createElement('style');
style.textContent = '.highlight { background: yellow !important; }';
document.head.appendChild(style);
""")
driver.execute_script("arguments[0].classList.add('highlight');", btn)
driver.quit()
八、高级功能
Selenium不仅支持基本的页面交互,还提供了一系列高级功能,使浏览器自动化能够应对更复杂的场景。截图功能是最实用的调试和数据留存工具之一:save_screenshot保存全屏截图、element.screenshot保存特定元素的截图。这在调试定位问题时尤其有用——你可以截取页面的当前状态,直观地判断元素是否已经加载和显示。Cookie管理通过driver.get_cookies()、add_cookie()和delete_all_cookies()等接口,实现登录态保持、会话管理等功能——你可以预先从浏览器导出Cookie信息,然后在自动化脚本中注入,跳过登录流程直接访问需要认证的页面。
网络请求监控是Selenium 4引入的重要增强功能。通过DevTools Protocol(Chrome DevTools协议),你可以捕获和查看浏览器发出的所有网络请求及其响应数据,包括XHR请求、图片加载、CSS资源等。这为分析页面API接口、监控数据加载提供了强大的支持。下载文件管理也是一个常见需求:通过配置浏览器偏好设置,可以指定文件下载目录并自动处理下载完成后的后续操作。浏览器日志功能可以捕获浏览器控制台的输出信息(console.log、错误信息、警告等),是诊断页面JavaScript错误的利器。保存页面功能可以将当前页面完整保存为HTML文件,包括所有资源引用的处理。以下依次展示截图Cookie管理、DevTools网络监控和下载文件控制的完整代码。
截图与Cookie管理
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
driver = webdriver.Chrome()
driver.get('https://www.example.com')
# === 截图功能 ===
# 全页面截图
driver.save_screenshot('full_page.png')
print("全页面截图已保存")
# 元素截图
element = driver.find_element(By.ID, 'main-content')
element.screenshot('element_screenshot.png')
print("元素截图已保存")
# === Cookie管理 ===
# 获取当前页面的所有Cookie
cookies = driver.get_cookies()
for cookie in cookies:
print(f"Cookie: {cookie['name']} = {cookie['value']}")
# 添加自定义Cookie
driver.add_cookie({
'name': 'session_id',
'value': 'abc123xyz',
'domain': '.example.com',
'path': '/',
'expiry': int(time.time()) + 3600 # 1小时后过期
})
# 按名称获取Cookie
session_cookie = driver.get_cookie('session_id')
print(f"Session Cookie: {session_cookie}")
# 删除Cookie
driver.delete_cookie('session_id') # 删除单个
driver.delete_all_cookies() # 删除所有
# === 实用技巧:注入Cookie保持登录状态 ===
cookies_data = [
{'name': 'token', 'value': 'your_auth_token'},
{'name': 'user_id', 'value': '12345'}
]
driver.get('https://www.example.com')
for c in cookies_data:
driver.add_cookie(c)
driver.refresh() # 刷新页面后即处于登录状态
driver.quit()
DevTools网络请求监控(Selenium 4)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
driver = webdriver.Chrome()
# 启用性能日志收集
options = Options()
options.set_capability('goog:loggingPrefs', {'performance': 'ALL'})
driver = webdriver.Chrome(options=options)
driver.get('https://www.example.com')
# 获取浏览器性能日志
logs = driver.get_log('performance')
for entry in logs:
message = entry['message']
if 'Network.response' in message and 'status' in message:
# 简化为仅打印部分日志
pass
print(f"共捕获 {len(logs)} 条性能日志")
# === Selenium 4 DevTools Protocol 高级用法 ===
from selenium.webdriver.common.devtools.v127.network import RequestWillBeSent
driver = webdriver.Chrome()
# 使用DevTools监听网络请求
def handle_request(request: RequestWillBeSent):
print(f"请求: {request.request.method} {request.request.url}")
# 启用网络跟踪
driver.execute_cdp_cmd('Network.enable', {})
# 在每个请求发送时输出信息
driver.execute_cdp_cmd('Network.onRequestWillBeSent', {
'callback': 'console.log'
})
driver.get('https://www.example.com')
# 获取所有请求的响应体
driver.execute_cdp_cmd('Network.enable', {})
# 捕获某个API响应
api_responses = driver.execute_cdp_cmd('Network.getResponseBody', {
'requestId': 'request_id_here'
})
driver.quit()
文件下载控制与浏览器日志
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import os
# === 配置文件下载 ===
download_dir = os.path.abspath('./downloads')
os.makedirs(download_dir, exist_ok=True)
prefs = {
'download.default_directory': download_dir, # 下载目录
'download.prompt_for_download': False, # 不弹出下载确认
'download.directory_upgrade': True,
'safebrowsing.enabled': False, # 禁用安全浏览
'profile.default_content_settings.popups': 0 # 禁用弹窗
}
options = Options()
options.add_experimental_option('prefs', prefs)
driver = webdriver.Chrome(options=options)
driver.get('https://www.example.com/download')
# 点击下载按钮
driver.find_element(By.ID, 'download-btn').click()
print(f"文件将下载至: {download_dir}")
# 等待文件下载完成(简单轮询检查)
import time
timeout = 30
while timeout > 0:
files = os.listdir(download_dir)
# 检查是否包含下载中的临时文件
has_crdownload = any(f.endswith('.crdownload') for f in files)
has_completed = any(f.endswith('.pdf') or f.endswith('.zip') for f in files)
if has_completed and not has_crdownload:
print(f"下载完成!文件: {[f for f in files if not f.endswith('.crdownload')]}")
break
time.sleep(1)
timeout -= 1
# === 浏览器控制台日志 ===
browser_logs = driver.get_log('browser')
for log in browser_logs:
print(f"[{log['level']}] {log['message'][:100]}")
driver.quit()
九、反检测与稳定性
在实际的自动化办公项目中,脚本的稳定性和隐蔽性往往是决定项目成败的关键因素。许多网站会检测并阻止自动化工具访问——它们通过检查浏览器特征(如navigator.webdriver属性、Chrome自动化扩展、用户代理字符串等)来识别爬虫或机器人。Selenium默认启动的浏览器会暴露出自动化特征,这使得脚本容易被目标网站识别和拦截。因此,隐藏自动化痕迹(即"反检测")成为Web自动化中不可回避的技能。反检测的核心思路是:让Selenium操控的浏览器看起来尽可能像一个真实的用户浏览器。
常用的反检测技术包括:通过excludeSwitches隐藏Chrome的自动化信息栏、禁用自动化扩展、修改navigator.webdriver属性为false、设置真实的User-Agent头部、配置合理的窗口尺寸、使用--disable-blink-features=AutomationControlled参数移除WebDriver特征标记。更高级的方案可以结合第三方库如undetected-chromedriver,它通过修补ChromeDriver的源代码层面特征,实现更彻底的自动化隐藏。稳定性方面,核心策略包括:在每次操作之间加入随机间隔(避免固定频率触发反爬机制)、为失败的操作提供重试机制、编写全面的异常处理逻辑、合理使用等待机制确保元素就绪、定期清理浏览器缓存和Cookie避免状态累积。
反检测配置实战
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
# === 隐藏自动化特征 ===
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option('excludeSwitches', ['enable-automation'])
options.add_experimental_option('useAutomationExtension', False)
# === User-Agent伪装 ===
options.add_argument(
'--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/120.0.0.0 Safari/537.36'
)
# === 其他反检测参数 ===
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--lang=zh-CN')
options.add_argument('--window-size=1920,1080')
driver = webdriver.Chrome(options=options)
# 通过JavaScript覆盖webdriver属性
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
driver.execute_script("""
// 覆盖Chrome自动化属性
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5]
});
Object.defineProperty(navigator, 'languages', {
get: () => ['zh-CN', 'zh', 'en']
});
""")
print("反检测配置已生效")
driver.get('https://www.example.com')
# 验证是否隐藏了自动化特征
is_automated = driver.execute_script("return navigator.webdriver")
print(f"navigator.webdriver = {is_automated}") # 期望: undefined
driver.quit()
随机操作间隔与重试机制
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
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import random
import time
def random_sleep(min_sec=0.5, max_sec=2.0):
"""随机等待,模拟人类操作节奏"""
delay = random.uniform(min_sec, max_sec)
time.sleep(delay)
return delay
def safe_click(driver, locator, retries=3):
"""带重试机制的点击操作"""
for attempt in range(retries):
try:
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable(locator)
)
random_sleep(0.3, 1.0)
element.click()
print(f"点击成功: {locator} (第{attempt + 1}次)")
return True
except (TimeoutException, NoSuchElementException) as e:
if attempt < retries - 1:
wait_time = random.uniform(2, 4)
print(f"点击失败,{wait_time:.1f}秒后重试... (第{attempt + 1}/{retries}次)")
time.sleep(wait_time)
else:
print(f"点击最终失败: {locator}")
raise
def safe_input(driver, locator, text, retries=3):
"""带重试机制的输入操作"""
for attempt in range(retries):
try:
element = WebDriverWait(driver, 10).until(
EC.visibility_of_element_located(locator)
)
random_sleep(0.2, 0.8)
element.clear()
# 模拟人类逐字输入
for char in text:
element.send_keys(char)
time.sleep(random.uniform(0.05, 0.2))
print(f"输入完成: '{text[:10]}...' (第{attempt + 1}次)")
return True
except TimeoutException:
if attempt < retries - 1:
time.sleep(random.uniform(2, 3))
else:
raise
# 使用示例
driver = webdriver.Chrome()
driver.get('https://www.example.com/login')
safe_input(driver, (By.ID, 'username'), 'my_username')
random_sleep()
safe_input(driver, (By.ID, 'password'), 'my_password')
random_sleep()
safe_click(driver, (By.ID, 'login-btn'))
print("登录操作完成")
driver.quit()
异常处理与日志记录
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import (
TimeoutException,
NoSuchElementException,
StaleElementReferenceException,
WebDriverException,
ElementClickInterceptedException
)
import logging
import time
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('selenium_automation.log', encoding='utf-8'),
logging.StreamHandler()
]
)
def robust_automation():
"""健壮的自动化脚本示例"""
driver = None
try:
driver = webdriver.Chrome()
driver.get('https://www.example.com')
driver.implicitly_wait(10)
# 带全面异常捕获的操作
try:
element = driver.find_element(By.ID, 'dynamic-element')
element.click()
logging.info("元素点击成功")
except NoSuchElementException:
logging.warning("元素未找到,尝试备用方案")
# 备用定位策略
try:
element = driver.find_element(By.CSS_SELECTOR, '.fallback-selector')
element.click()
logging.info("备用定位成功")
except Exception as e:
logging.error(f"所有定位策略均失败: {e}")
driver.save_screenshot('error_screenshot.png')
except ElementClickInterceptedException:
logging.warning("元素被遮挡,尝试JS点击")
element = driver.find_element(By.ID, 'dynamic-element')
driver.execute_script("arguments[0].click();", element)
except WebDriverException as e:
logging.critical(f"浏览器驱动异常: {e}")
except Exception as e:
logging.critical(f"未预期的异常: {e}", exc_info=True)
finally:
if driver:
logging.info("关闭浏览器")
driver.quit()
robust_automation()
十、实战案例
理论与实践相结合是掌握Selenium的最佳路径。本章节通过4个完整的实战案例,展示Selenium在真实办公自动化场景中的应用方式。案例涵盖最常见的Web自动化需求:自动登录系统、数据批量采集、Web表单自动提交和定时签到自动化。每个案例都包含完整的代码实现和关键注意事项,可以直接应用于日常工作中。在学习这些案例时,建议你重点关注代码的结构设计(如何分离配置和逻辑、如何复用公共方法)以及异常处理机制——这些都是生产级自动化脚本必不可少的要素。
实战案例的共通模式是:先初始化浏览器配置和驱动,然后按照业务流程依次执行操作步骤,每一步都加入适当的等待和校验,最后优雅地退出浏览器。对于需要长时间运行的任务(如定时签到),需要考虑脚本的健壮性和资源管理——包括断线重连、内存泄漏防范、日志轮转等。对于数据采集类任务,需要注重数据完整性校验和增量采集策略(避免重复采集已获取的数据)。这些案例覆盖了Web自动化开发的典型编程模式,熟练掌握后将能够应对绝大多数办公自动化需求。
案例一:自动登录系统
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
import time
def auto_login(url, username, password):
"""自动登录目标系统"""
driver = webdriver.Chrome()
try:
driver.get(url)
wait = WebDriverWait(driver, 10)
# 步骤1:输入用户名
user_input = wait.until(
EC.presence_of_element_located((By.ID, 'username'))
)
user_input.clear()
user_input.send_keys(username)
# 步骤2:输入密码
pwd_input = driver.find_element(By.ID, 'password')
pwd_input.clear()
pwd_input.send_keys(password)
# 步骤3:输入验证码(如有)
try:
captcha = driver.find_element(By.ID, 'captcha')
captcha_input = input("请查看页面验证码并输入: ")
captcha.send_keys(captcha_input)
except:
print("无验证码输入框,跳过")
# 步骤4:点击登录按钮
login_btn = wait.until(
EC.element_to_be_clickable((By.ID, 'login-btn'))
)
login_btn.click()
# 步骤5:验证登录是否成功
time.sleep(2)
if 'dashboard' in driver.current_url or 'index' in driver.current_url:
print("登录成功!")
return True
else:
error_msg = driver.find_element(By.CLASS_NAME, 'error-msg')
print(f"登录失败: {error_msg.text}")
return False
finally:
# 不立即关闭,方便查看结果
time.sleep(3)
driver.quit()
# 使用示例
auto_login('https://www.example.com/login', 'admin', 'password123')
案例二:数据批量采集
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
import csv
import time
def scrape_product_list(url, max_pages=5):
"""批量采集商品列表数据"""
driver = webdriver.Chrome()
all_products = []
try:
for page in range(1, max_pages + 1):
page_url = f"{url}?page={page}"
driver.get(page_url)
wait = WebDriverWait(driver, 10)
# 等待商品列表加载
wait.until(EC.presence_of_element_located((By.CLASS_NAME, 'product-item')))
# 采集当前页数据
products = driver.find_elements(By.CLASS_NAME, 'product-item')
for product in products:
try:
name = product.find_element(By.CLASS_NAME, 'product-name').text
price = product.find_element(By.CLASS_NAME, 'product-price').text
rating = product.find_element(By.CLASS_NAME, 'product-rating').text
all_products.append({
'name': name,
'price': price,
'rating': rating,
'page': page
})
except Exception as e:
print(f"采集单个商品数据失败: {e}")
continue
print(f"第{page}页采集完成,当前共采集 {len(all_products)} 条数据")
time.sleep(2) # 礼貌性等待,避免被封
finally:
driver.quit()
# 保存到CSV文件
with open('products.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=['name', 'price', 'rating', 'page'])
writer.writeheader()
writer.writerows(all_products)
print(f"数据采集完成,共 {len(all_products)} 条,已保存至 products.csv")
return all_products
# 使用示例
# scrape_product_list('https://www.example.com/products', max_pages=3)
案例三:定时签到与表单自动提交
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
from selenium.webdriver.support.ui import Select
import schedule
import time
import logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
def auto_checkin():
"""定时签到自动化"""
driver = webdriver.Chrome()
try:
logging.info("开始执行签到任务")
driver.get('https://www.example.com/checkin')
wait = WebDriverWait(driver, 10)
# 步骤1:登录
driver.find_element(By.ID, 'username').send_keys('user')
driver.find_element(By.ID, 'password').send_keys('pass')
driver.find_element(By.ID, 'login-btn').click()
# 步骤2:等待签到按钮
checkin_btn = wait.until(
EC.element_to_be_clickable((By.ID, 'daily-checkin'))
)
checkin_btn.click()
# 步骤3:确认签到结果
time.sleep(2)
result = driver.find_element(By.CLASS_NAME, 'checkin-result').text
logging.info(f"签到结果: {result}")
except Exception as e:
logging.error(f"签到失败: {e}")
driver.save_screenshot(f'checkin_error_{time.strftime("%Y%m%d")}.png')
finally:
driver.quit()
def auto_fill_form():
"""Web表单自动提交"""
driver = webdriver.Chrome()
try:
driver.get('https://www.example.com/form')
wait = WebDriverWait(driver, 10)
# 自动填写表单各字段
wait.until(EC.presence_of_element_located((By.NAME, 'fullname'))).send_keys('张三')
driver.find_element(By.NAME, 'email').send_keys('zhangsan@example.com')
driver.find_element(By.NAME, 'phone').send_keys('13800138000')
# 下拉选择
Select(driver.find_element(By.NAME, 'city')).select_by_visible_text('上海')
# 勾选同意条款
driver.find_element(By.NAME, 'agree').click()
# 提交表单
driver.find_element(By.ID, 'submit-btn').click()
# 验证提交结果
success_msg = wait.until(
EC.visibility_of_element_located((By.CLASS_NAME, 'success-message'))
)
print(f"表单提交成功: {success_msg.text}")
except Exception as e:
print(f"表单提交失败: {e}")
driver.save_screenshot('form_error.png')
finally:
driver.quit()
# 定时签到:每天早上9:00执行
# schedule.every().day.at("09:00").do(auto_checkin)
# print("定时签到已启动,将在每天09:00执行")
# 临时测试
auto_fill_form()
# 保持程序运行(启用定时任务时取消注释)
# while True:
# schedule.run_pending()
# time.sleep(60)
案例四:自动登录执行流程总览
# Web自动化脚本的标准执行流程:
#
# 1. 初始化阶段
# - 配置浏览器选项(Headless、User-Agent、反检测参数)
# - 创建WebDriver实例
# - 设置隐式等待超时时间
#
# 2. 访问目标页面
# - driver.get(url)
# - 页面加载完成继续
#
# 3. 定位并交互元素
# - 使用显式等待确保元素就绪
# - 执行点击/输入/选择等操作
#
# 4. 数据提取/结果验证
# - 获取页面文本、属性、截图
# - 验证操作是否成功
#
# 5. 资源清理
# - 关闭浏览器 driver.quit()
# - 保存结果到文件
# - 记录日志
#
# 最佳实践总结:
# - 优先使用CSS_SELECTOR和ID定位
# - 显式等待优于隐式等待
# - 每次操作间隔随机延迟
# - 捕获具体异常而非通用Exception
# - 使用WebDriverWait代替time.sleep
# - 通过Options限制资源加载提升速度
# - 定期截图用于问题排查
# - 用try/finally确保driver.quit()执行
# - Cookie注入可跳过登录步骤
# - 反检测配置可大幅降低封禁概率