
简介DrissionPage v4.0.2 是一份面向 Web 自动化开发、测试及运维人员的 Python 集成工具源码包可用于快速实现网页元素定位、点击输入、数据抓取与分析并支持多线程执行与测试报告生成适合自动化测试、持续集成、教学研究等场景也是计算机专业毕业设计与论文实现的理想参考。该版本在浏览器控制、页面元素封装与脚本执行方面做了进一步整合让开发者能以更低成本完成动态页面数据采集、表单批量填写、回归验证等常见任务。压缩包共 79 个文件整体约 172KB以 39 个 .py 源码与 31 个 .pyi 类型声明文件为主另有 README、requirements、LICENSE 等工程配置文档目录结构清晰便于按模块研读和二次开发。目前已有 572 人学习浏览属于轻量但实用的开源工具包。内含 DrissionPage-v4.0.2 核心源码、页面与元素封装模块、脚本录制与编辑逻辑、数据处理及验证工具等读者可借此掌握浏览器自动化原理、动手搭建运行环境还可结合源码分析设计思路为论文撰写或作品完善提供直接支撑。1. Web 自动化巡检和采集被等待与反爬卡住时我换成了 DrissionPage做 Web 自动化的人大概率都经历过这种局面用 Selenium 启动浏览器要等好几秒定位元素时判断网络状态全靠 time.sleep页面稍微复杂一点脚本就开始飘想用 requests 直接拿数据又发现目标页面全是 JS 动态渲染接口要么带签名要么带加密参数。后来我看到一个叫 DrissionPage v4.0.2 的集成工具包把浏览器控制、数据包请求、元素操作收拢成同一套 API不依赖 WebDriver也没有前置安装驱动的版本匹配问题。这篇文章直接讲它是什么、怎么落地、参数怎么调、坑在哪尤其适合打算把 Web 页面自动化巡检和固定采集流程做成常态化任务的工程师。2. DrissionPage 为什么能同时干 Selenium 和 requests 的活2.1 底层走 CDP 而不是 WebDriver少了中间驱动响应自然快DrissionPage 和 Selenium 最大的差异在底层协议。Selenium 依赖浏览器厂商提供的 WebDriver每个浏览器版本要匹配一个驱动文件然后通过 HTTP 接口转发命令这条链路里多了一层外部进程。DrissionPage 的 d 模式ChromiumPage直接走 Chrome DevTools Protocol建立一条 WebSocket 连接到浏览器的调试端口省掉了驱动进程的转发也就不存在 chromedriver 和浏览器版本必须严格一致的问题。实际体验上的差距很明显。同样一个页面用 Selenium 定位元素可能要等待几百毫秒而 v4.0.2 的 ChromiumPage 在元素已经渲染的情况下基本是毫秒级返回。这是因为 CDP 本身就是 Chrome 调试工具用的协议所有 DOM 查询、点击、输入都直接在浏览器内部执行命令往返次数比 WebDriver 少得多。v4.x 这一代还把连续操作做了批处理你写的是同步代码但浏览器端是异步执行并批量返回结果的。我一般会用 ChromiumPage 代替 Selenium 做交互类任务比如登录、点击、文件上传、页面截图。因为它不需要额外维护 driver部署时只要机器上装了 Chrome 就能跑。对于团队里熟悉 Selenium 的老手转向 DrissionPage 的成本也很低ele()、click()、input() 这套命名几乎不用重新学。2.2 三种模式的适用边界d、s、m 各干各的活DrissionPage 提供了 dbrowser、ssession、mmix三种模式。d 模式控制真实浏览器能拿到完整的渲染结果s 模式内部封装了 requests.Session但请求接口和 d 模式对齐写起来像在操作一个虚拟页面m 模式则是同一个对象里同时保留浏览器控制通道和请求通道典型场景是先通过浏览器登录拿到 cookies再用 s 模式去请求后端接口。选择上不需要纠结。我的习惯是凡是涉及验证码、滑块、扫码登录、动态渲染结果校验的任务直接上 d 模式因为浏览器内的交互和验证是绕不开的凡是登录态已经就绪、只需要循环请求接口拉数据的任务用 s 模式省去浏览器渲染的内存和耗时跑大批量巡检时差别尤其明显。m 模式适合那些先要靠浏览器过验证、然后一次性拉几百个接口的场景能省掉反复让浏览器加载页面的开销。v4.0.2 的 SessionPage 并不是简单地包一层 requests。它对响应对象做了统一封装支持像 page.ele() 那样从返回内容里取元素、取属性也内置了超时重试。以前用 requests 写采集时我要自己写重试、写会话保持、写响应编码处理现在这些在 SessionPage 里都有默认行为大部分情况不用改。2.3 v4.0.2 集成工具包解压后常见结构里到底有哪些东西标题里这个 v4.0.2 的 zip 包我拿到后第一个动作不是直接去 import而是先看目录结构。常见做法是一个集成好的 DrissionPage 工具包会包含这几个部分DrissionPage 主包、requirements.txt、examples 目录、config.ini以及把浏览器调试参数和请求参数外置的配置文件。主包里真正需要业务代码引用的类只有少数几个核心是 ChromiumPage、SessionPage、ChromiumOptions、SessionOptions。集成工具包的价值不仅仅是把版本号锁在 v4.0.2而是它把环境依赖和浏览器参数全部收敛到配置里。团队里不同人各自装 Selenium 再手动下载 driver 的那种状态很容易出现环境不一致导致脚本时好时坏。用这个打包好的方案新同事只要解压、建虚拟环境、装 requirements、改一改 config 里的浏览器路径和超时时间就能开始跑业务脚本。对于要长期维护的 Web 页面自动化巡检项目这种可复现性是省钱的关键。3. 把 v4.0.2 跑起来最小脚本与三个你最好别乱改的参数3.1 从解压到打开第一个页面venv 隔离依赖是第一步我建议所有依赖都装在虚拟环境里不要直接往系统 Python 里塞。先解压然后创建并激活 venv再用 requirements.txt 安装。命令如下unzip DrissionPage_Web自动化操作集成工具_v4.0.2.zip cd DrissionPage_Web自动化操作集成工具_v4.0.2 python -m venv .venv source .venv/bin/activate # Windows 系统执行 .venv\Scripts\activate pip install -r requirements.txt这套命令里venv 是隔离依赖用的避免 DrissionPage 和你机器上其他项目用到的 requests、lxml 版本打架。requirements.txt 里通常会锁定版本比如把 DrissionPage 固定在 4.0.2这样后续更新不会偷偷改变 API 行为。安装完成后先跑一个最小脚本验证环境from DrissionPage import ChromiumPage page ChromiumPage() page.get(https://example.com) print(page.title) page.quit()ChromiumPage() 不带参数时会自动查找系统里可用的 Chrome 或 Chromium找到后通过调试端口启动一个新实例。get() 会按照后面要讲的加载策略等待页面到达可操作状态然后继续执行。这里注意 title 在 v4 里是属性不是方法不加括号如果你是 v3 时代的写法这个地方很容易翻车。quit() 用来关闭浏览器进程短脚本里可以省略但长任务里不写会造成进程残留。3.2 定位器语法ele() 的 CSS、文本、xpath 三种写法DrissionPage 的元素定位核心是 ele()它支持 CSS 选择器、文本定位、xpath 和属性定位。我总结的常用写法如下page.ele(#login-btn) # CSS ID 选择器 page.ele(.user-name:first) # CSS 加伪类取第一个 page.ele(xpath://button[typesubmit]) page.ele(text():登 录) # 按可见文本匹配第一行是最常见的 CSS 写法适合有稳定 id 或 class 的元素。第二行里的 :first 是 v4 提供的伪类用来从一组匹配元素里取第一个相当于 Selenium 里的 find_element 而不是 find_elements。第三行用 xpath 处理结构比较复杂的元素代价是解析稍慢。第四行按文本定位比较实用因为按钮上的文字一般比 class 稳定不会被前端频繁改样式影响。定位不到元素时ele() 默认会抛 NoElementError而不是返回 None。如果你希望找不到就继续走逻辑可以给 timeout 参数一个小值再配合 try/except。我在巡检脚本里通常把 timeout 设成 5 秒超过就认为页面异常而不是无限等下去。3.3 三个必调参数load_mode、timeout、browser_pathv4.0.2 里最影响运行稳定性的参数我认为是加载策略、超时时间和浏览器路径。这三个参数可以通过 ChromiumOptions 注入也可以在配置文件里改。先看代码写法from DrissionPage import ChromiumPage, ChromiumOptions co ChromiumOptions() co.set_load_mode(eager) co.set_timeout(10) co.set_browser_path(/usr/bin/google-chrome) page ChromiumPage(co)set_load_mode(eager) 是让页面在 DOM 加载完成、但外部资源仍在加载时就返回控制权。巡检场景下我们关心的是页面结构和接口数据而不是图片和广告是否加载完所以 eager 一般比 normal 快两三秒。set_timeout(10) 是设置元素查找和网络请求的默认超时时间网络不稳时可以往上调到 20但如果超过 30 秒还没拿到结果问题大概率在代码而不是网速。set_browser_path 是为了应对系统里装了多个浏览器的场景显式指定 Chrome 可执行文件避免找不到浏览器。这三个参数我建议写入配置文件而不是写死在代码里因为巡检脚本可能部署在测试机、云主机、队友电脑上环境差异比代码差异更容易出问题。把浏览器路径和超时时间外置换一台机器只需要改 ini 文件。4. 用 DrissionPage 做 Web 页面自动化巡检登录态复用与结果推送4.1 巡检脚本的常见结构登录、断言、异常处理三层分离Web 页面自动化巡检的核心不是把页面打开而是要回答三个问题登录态是否有效、关键元素是否出现、业务接口是否返回预期结果。我习惯把巡检脚本拆成三层第一层负责登录并保持登录状态第二层定义巡检目标和断言规则比如某个页面的标题、某个数值元素、某个表格行数第三层负责把失败结果推送到告警群或通知系统。登录态复用是巡检里最容易忽略的部分。如果每个巡检任务都重新走一遍登录流程验证码和扫码都会成为自动化流程的新瓶颈。常见做法是用 ChromiumOptions 指定一个 user_data_dir让浏览器把登录后的 cookies 和本地存储持久化到磁盘第二次启动直接复用。4.2 一个可以直接改的巡检模板页面校验加登录态复用下面这段脚本是我在实际巡检项目里常用的简化版本你可以直接复制改成自己的目标地址from DrissionPage import ChromiumPage, ChromiumOptions from datetime import datetime import logging logging.basicConfig(levellogging.INFO) def check_page(page, url, assertions): page.get(url) result {} for name, locator in assertions.items(): try: ele page.ele(locator, timeout5) result[name] ele.text[:50] if ele else MISSING except Exception as e: result[name] fERROR: {str(e)} return result if __name__ __main__: co ChromiumOptions() co.set_load_mode(eager) co.set_user_data_path(./profile) page ChromiumPage(co) # 第一次运行需要手动登录登录完成后会自动保存到 ./profile page.get(https://your-app.example.com/login) page.ele(#username).input(admin) page.ele(#password).input(your_password) page.ele(button[typesubmit]).click() page.wait(3) targets { dashboard: https://your-app.example.com/dashboard, health: https://your-app.example.com/health, } assertions { page_title: h1.title, status_text: #status, } for name, url in targets.items(): result check_page(page, url, assertions) logging.info(f{datetime.now()} | {name} | {result}) page.quit()这段代码里co.set_user_data_path(./profile) 是最关键的一行。它把浏览器用户数据目录固定在本项目的 profile 文件夹首次运行录入的登录态会保存在那里第二次再跑就不用重新输密码。check_page 函数把页面地址和断言规则做成字典新增巡检页面时只需要往 targets 里加一条不用改逻辑。ele 的 timeout 设为 5保证单个页面异常时最多拖 5 秒而不是让整个巡检卡死。4.3 失败结果推送企业微信、钉钉、飞书通用 webhook 写法巡检结果如果只打在日志里几乎等于没有巡检。常见做法是接群机器人的 webhook把失败信息直接推到群里。代码通常长这样import requests import os def send_alert(title, content): webhook os.environ.get(ALERT_WEBHOOK) if not webhook: return payload { msgtype: text, text: {content: f{title}\n{content}} } requests.post(webhook, jsonpayload, timeout5)这个 webhook 地址通过环境变量 ALERT_WEBHOOK 注入不要写死在代码里更不要把 webhook 提交到代码仓库。不同平台的机器人消息结构略有差异但基本都是向一个 URL POST JSON 数据。把 webhook 外置的另一个好处是换群、换平台时不需要改巡检脚本只改环境变量即可。推送动作只需在 check_page 返回结果包含 ERROR 或 MISSING 时调用正常的巡检结果不需要每次发给所有人。5. DrissionPage v4.0.2 避坑排查让我反复翻车的几个问题5.1 元素定位总是超时问题是加载策略等得太久现象脚本跑起来后ele() 频繁报超时尤其是一些图片多、外链多的页面每打开一个都要等很久才开始定位。原因v4 默认的加载策略是 normal也就是要等页面里所有资源都加载完成才返回控制权。巡检页面往往有统计脚本、广告、第三方 SDK这些资源不一定稳定一旦某个域名响应慢整个页面就会长时间处于未完成状态。解决把加载策略改成 eagerDOM 加载完就继续执行。同时给 ele() 设置合理的 timeout例如 5 秒。这是我建议在 v4.0.2 上第一个要做的事它比任何等待代码都更稳定。不要再用 time.sleep 去猜网络结束时间DrissionPage 的策略控制就是用来替代这种玄学等待的。5.2 无头模式点击失灵被新版 headless 参数坑了一次现象加了 set_argument(--headless) 后页面能打开但点击按钮没有反应或者页面报错说浏览器不支持某个特性。原因旧版 headless 模式用的是一个阉割的浏览器环境很多新 Web API 不生效。Chrome 后来推出了 --headlessnewDrissionPage v4.0.2 里如果你还用老参数部分页面交互可能失效。解决使用 ChromiumOptions 里的新无头写法co.set_argument(--headlessnew)如果公司内网页面依赖特殊插件建议先在开发环境用有头模式调通再切无头模式跑定时任务。切换后要回归一遍登录、点击、截图这几个关键动作无头模式不只是隐藏窗口渲染行为还是有差异。5.3 s 模式请求返回 403cookies 没有同步过去现象网页登录成功后用 SessionPage 请求同一个域名的接口返回 403 或者重定向到登录页。原因d 模式的 ChromiumPage 和 s 模式的 SessionPage 是两个独立的会话浏览器里登录产生的 cookies 不会自动带到 SessionPage。单独会话少了登录态接口自然拒绝访问。解决在创建 SessionPage 后把 ChromiumPage 的 cookies 复制过去from DrissionPage import SessionPage s SessionPage() s.cookies page.cookies这里的 page 是之前已经登录的 ChromiumPage 实例。执行完这行再请求接口登录态就带上了。如果接口还需要特定的 token 或签名那就不能只靠 cookies需要从 localStorage 或页面源码里取这个在 v4 里可以用 page.run_js() 拿到。5.4 跑几次后浏览器进程残留端口被占用现象脚本第二次运行报错提示调试端口被占用或者浏览器启动失败但系统里看不到任何 Chrome 窗口。原因脚本中途异常退出quit() 没有执行浏览器进程还挂在后台。再次启动时DrissionPage 尝试连接同一个调试端口却碰上了一个半死的实例。解决把 page 的创建和退出放进 try/finally确保异常退出也会关闭浏览器。也可以直接给 ChromiumOptions 指定一个新的端口co.set_local_port(9333)用固定的自定义端口能减少系统随机端口冲突的概率。我自己的习惯是巡检脚本最后一定要有 page.quit()而且把这个动作写在 finally 里血泪经验告诉我漏掉这一步会耽误一上午。5.5 iframe 内元素定位不准老是报找不到节点现象页面里嵌套了 iframeele() 明明能看到页面上的元素但定位时一直超时。原因v4 的元素查找默认在当前文档里进行不会自动钻进 iframe。如果你要操作的元素在 iframe 内必须切换 frame 边界。解决使用 DrissionPage 的 frame 相关方法先拿到 iframe 元素再操作frame page.get_frame(#main_iframe) frame.ele(.content).click()get_frame() 支持用 iframe 的 id、name 或位置索引。进入 frame 后元素查找都在这个 frame 内部进行。操作完如果需要回到主文档可以调用 frame.exit_frame()。这个点很容易被忽略尤其是做 Web 页面自动化巡检时很多后台管理系统都用了 iframe 布局。6. 进阶用法把巡检脚本做成命令行工具并验证长期收益6.1 用 argparse 把巡检目标外置接入 cron 和任务计划程序固定写死的 targets 字典适合调试但长期巡检需求会变比如今天巡检首页、明天巡检列表页。我一般会给脚本加命令行参数让巡检地址和断言规则从外部传入import argparse parser argparse.ArgumentParser(descriptionDrissionPage 巡检脚本) parser.add_argument(--config, requiredTrue, help巡检配置文件路径) parser.add_argument(--once, actionstore_true, help只跑一次不进入循环) args parser.parse_args()这样脚本就可以被 cron、Windows 任务计划程序或者 CI 平台按需调度。在 Linux 上写 crontab 时记得用绝对路径调用虚拟环境里的 python不要用裸 python否则可能加载到系统依赖。跑定时任务时还要把日志输出到文件方便第二天翻记录。6.2 验证这个方向值不值得长期投入我的几个习惯要做一次完整的验证我建议先挑一个高频巡检页面跑一周记录平均耗时、失败率、定位超时次数再对比原来人工检查和 Selenium 脚本的数据。如果 DrissionPage 版本每周能帮你省下三小时以上就值得把更多页面接进来如果失败率超过 5%先检查是不是页面结构变动太频繁再考虑加页面快照和告警。我自己常犯的错是把所有页面塞进同一个脚本后来发现不同系统用不同模式更合适登录类的用 d 模式接口类的用 s 模式混合的才上 m 模式。希望这些经验和前面提到的参数调整能帮你在这个 v4.0.2 工具包上少走一段弯路也希望这份记录对你手头的 Web 自动化巡检项目真能帮上忙。本文还有配套的精品资源点击获取