DrissionPage v4.0.2双引擎机制:替代Selenium的Web自动化新选择

📅 发布时间:2026/10/8 22:16:03
DrissionPage v4.0.2双引擎机制:替代Selenium的Web自动化新选择
简介DrissionPage v4.0.2 是一款面向开发者、测试人员和运维人员的 Web 自动化集成工具集成脚本录制、元素操作、数据处理、多线程执行与报告生成等能力可快速完成网页自动化操作、表单填报和数据抓取广泛应用于自动化测试、数据分析、持续集成及教学研究等场景。压缩包共79个文件以39个 Python 脚本与31个类型标注文件py/pyi为核心另含说明文档、配置文件、许可文件等整体大小约172KB结构清晰便于查阅和二次开发。已有572人学习下载。随包附带的完整源代码使计算机专业学生可直接用于毕业设计或论文研究深入理解 Web 自动化工具的实现原理同时支持与建站模板、系统软件工具协同为网站建设和管理流程提供自动化解决方案。下载后可获得完整源码、类型定义、使用说明与配置示例是一份兼顾实用与学习的 Web 自动化资源。1. 不换 Selenium 也能做 Web 自动化DrissionPage 到底解决了什么问题做 Web 自动化的人大概率都被 Selenium 折腾过环境要装浏览器驱动、定位元素要等加载、登录态一换浏览器就丢。DrissionPage 是这套流程里少见的替代方案它把浏览器操控和 HTTP 请求放进了同一套 API你不用在 requests 和 Selenium 之间来回切换也不用为了一个动态页面单独起一个浏览器。v4.0.2 这个版本值得关注因为它修正了早期版本里不少接口签名和等待策略的问题是很多从业者愿意锁版本的候选。本文面向做数据采集、日常操作自动化、爬虫脚本维护的工程师目标是让你看完就能用这套工具跑通一个真实流程并避开我踩过的坑。2. 为什么值得换浏览器操作和 HTTP 请求一套 API 的取舍逻辑2.1 DrissionPage 的“双引擎”设计ChromiumPage 和 SessionPage 各管什么DrissionPage 最核心的设计是把两条技术路线合在了一起。一条是直接控制 Chromium 内核浏览器Chrome、Edge 都可以走的是 DevTools 协议另一条是类似 requests 的纯 HTTP 请求模式官方叫 SessionPage。前者负责渲染 JS、点击、填写表单这类需要真实浏览器环境的操作后者负责快速抓接口、下载文件这类不需要渲染的请求。我在实际项目里最常用到的是 ChromiumPage因为它解决了前端框架Vue、React页面难以直接拿数据的问题。SessionPage 更轻速度接近 requests适合应对接口返回的 JSON 数据。两者并非互斥DrissionPage 还提供了 WebPage 类可以在同一个对象上切换浏览器模式和请求模式做到“登录用浏览器取数用请求”。from drission_page import ChromiumPage, SessionPage, WebPage # 浏览器模式 page ChromiumPage() page.get(https://example.com) # 请求模式 session SessionPage() session.get(https://example.com/api/data) # 混合模式 web WebPage() web.change_mode() # 切换浏览器/请求模式这段代码里的ChromiumPage()会尝试拉起本机已安装的 Chrome 或 Edge不需要额外指定 chromedriver因为 DevTools 协议是浏览器原生支持的。SessionPage()内部封装了 requests.Session所以你能复用连接池。WebPage.change_mode()是切换模式的入口值得注意的是切换后 cookies 不会自动同步这一点的处理后面排坑章节会细说。2.2 版本怎么选v4.0.2 的安装方式与依赖关系drissionpage的版本迭代比较快大版本之间 API 有明显变化。v4.0.2 属于 4.x 系列的中期版本这个系列的特点是包名从DrissionPage改成了drission_page下划线形式导入语句统一用from drission_page import ...。如果你在网上搜到旧教程写from DrissionPage import ...那大概率是 3.x 的语法在 v4.0.2 环境里会直接导入失败。pip install drission_page4.0.2安装这个版本建议用虚拟环境隔离避免和项目里其他依赖冲突。验证安装是否成功可以进 Python 解释器执行python -c from drission_page import ChromiumPage; print(ok)这条命令只做一件事导入 ChromiumPage。如果输出ok说明安装没问题。依赖方面v4.0.2 对 Python 版本的要求不算苛刻3.7 以上的解释器基本都能跑如果你用的是 3.12建议先确认 pip 解析依赖时有没有报编译错误避免后续使用中遇到lxml这类依赖安装失败的问题。2.3 动手前的环境确认浏览器内核与系统适配很多新人第一步就翻车不是因为代码写错而是浏览器没准备好。v4.0.2 默认控制的浏览器是 Chromium 内核Chrome、Edge、Brave 这些都能用。但有个前置条件浏览器必须存在且版本不能太老。常见做法是在本机装一个稳定版 Chrome然后用ChromiumPage()直接初始化。如果你需要控制一个已经打开的浏览器可以先用命令行带调试端口启动浏览器再传入端口号chrome.exe --remote-debugging-port9222from drission_page import ChromiumPage page ChromiumPage(addr_or_opts127.0.0.1:9222)我一般会在需要调试脚本时这样用好处是浏览器里的登录态手动维护脚本只负责操作不需要每次都走登录流程。另一个容易被忽略的点是系统路径Linux 服务器上如果 Chrome 不在默认路径需要在初始化时显式指定浏览器路径参数否则会报找不到可执行文件的错。Windows 上多数时候可以免配置直接运行。3. 把第一行自动化跑起来最小脚本与核心 API 用法3.1 最小可复现脚本打开目标站点并提取数据先写一个能直接跑的最小脚本目的是验证环境、熟悉 API而不是一上来就搞复杂业务。下面的例子打开一个页面拿到网页标题和指定元素的文本然后关闭浏览器。from drission_page import ChromiumPage # 初始化浏览器 page ChromiumPage() # 访问目标页面 page.get(https://example.com) # 获取页面标题 print(page.title) # 定位元素并输出文本 text_ele page.ele(h1) print(text_ele.text) # 关闭浏览器 page.quit()page.get()是访问 URL 的入口它自带一个默认的等待行为会等页面加载到基本可用才返回不需要像 Selenium 那样手动写driver.get()后再加一个time.sleep()。page.ele()是定位元素的通用方法传h1表示按标签名查找返回值是一个元素对象调用.text可以拿到可见文本。page.quit()用于关闭浏览器进程释放系统资源。这段脚本的关键价值在于整个流程没有任何显式等待也没有 WebDriverWait。DrissionPage 的内部机制在get()阶段帮我们处理了大部分等待问题这是它和 Selenium 体验上最大的差异。3.2 元素定位的三个维度文本、CSS 选择器、xpath 怎么选DrissionPage 的元素定位方式比较灵活ele()方法会根据传入参数的格式自动判断匹配方式。常用的有三种文本定位、CSS 选择器定位、xpath 定位。文本定位是它的一大特色直接传中文或英文文本就能找到元素这在处理复杂嵌套页面时能省掉写一长串 CSS 的麻烦。from drission_page import ChromiumPage page ChromiumPage() page.get(https://example.com) # 文本定位找到文本为“联系我们”的链接 ele page.ele(联系我们) # CSS 选择器定位 ele_css page.ele(#nav .item a) # xpath 定位 ele_xpath page.ele(xpath://div[classcontent]//a)文本定位的匹配逻辑是“包含即命中”也就是说页面里多个元素都包含“联系我们”四个字时返回的是第一个。CSS 选择器写法和 jQuery 一致适合定位有明确 class 或 id 的控件。xpath 定位需要前缀xpath:适合层级结构复杂、CSS 难以表达的表格或列表场景。我在实际使用中总结的经验是能用文本定位就用文本定位代码可读性最好需要遍历同类元素时用eles()方法它会返回所有匹配元素的列表方便循环处理。ele()只会返回第一个匹配项这一点要记住别在页面上有多个相同文本时误以为返回的是自己想要的元素。3.3 页面交互三件套点击、输入、下拉选择自动化脚本最常见的交互就是点击按钮、填写输入框、选择下拉选项。DrissionPage 对这三类操作都做了简化不需要先定位再执行动作元素对象本身就是动作的承载者。from drission_page import ChromiumPage page ChromiumPage() page.get(https://example.com/login) # 输入账号密码 username page.ele(#username) username.clear() username.input(test_user) password page.ele(#password) password.input(123456) # 点击登录按钮 page.ele(登录).click() # 下拉选择按可见文本选择 select_ele page.ele(select[nametype]) select_ele.select.select_by_text(企业用户)input()方法有两种用法一是直接向输入框填值二是先clear()再输入避免原值残留。click()方法会等待元素可点击后执行这个等待是内置的默认超时时间可以通过参数调整。下拉选择有点不一样page.ele()定位到select标签后需要调用.select子对象再用select_by_text()按可见文本选择也可以用select_by_value()按 value 属性选择。这里有个容易出错的操作部分前端框架如 Element UI的下拉框是自绘组件不是原生select标签直接调用.select会报找不到属性。这种情况要点击下拉框后再点击弹出的选项文本。# 自绘下拉框的处理方式 page.ele(角色).click() # 展开下拉 page.ele(管理员).click() # 点击具体选项这种“先展开再点选项”的思路在处理所有自绘组件时都适用核心原则是把它当成两次独立的点击事件处理。4. 把脚本调稳配置项、等待策略与数据落地4.1 浏览器启动参数不显示窗口、开启无头模式的三个配置服务器上跑自动化通常没有显示器可用这时必须开启无头模式。DrissionPage 允许在初始化时传入浏览器启动参数常用的是禁用 GPU、无头模式、屏蔽沙箱。from drission_page import ChromiumPage # 无头模式运行 page ChromiumPage(chrome_options{ args: [ --headless, --no-sandbox, --disable-gpu, --window-size1920,1080 ] })chrome_options里通过args列表传入 Chromium 的命令行参数。--headless表示无头模式--no-sandbox是 Linux 服务器上常见的必需项--disable-gpu避免 GPU 相关错误--window-size指定页面视口大小。我一般会加上 window-size宽屏页面在小视口下可能触发响应式布局导致元素定位失败。要注意的是无头模式下的浏览器行为和有头模式不完全一致。最典型的差异是某些 JS 动画在无头模式下执行更快或更慢可能导致等待时机不对还有部分站点会在检测到无头浏览器时返回验证码页面。这属于一个持续的坑后面排坑章节会展开讲。4.2 等待策略显式等待的 timeout 参数怎么设DrissionPage 的内置等待已经解决了一部分问题但遇到异步加载的接口数据还是需要显式等待某个元素出现。它提供的等待方法比 Selenium 简洁直接在元素对象上调用即可。from drission_page import ChromiumPage from drission_page.errors import ElementNotFoundError page ChromiumPage() page.get(https://example.com) # 等待元素出现超时 10 秒 try: ele page.wait.ele_displayed(#data-list, timeout10) print(ele.text) except ElementNotFoundError: print(10秒内元素未出现)wait.ele_displayed()的timeout参数单位是秒它会轮询页面直到元素出现且可见。另一种常用的是page.wait.load_start()用于等待页面开始新一轮加载这个在点击触发跳转后使用比较多。还有page.wait.doc_loaded()会等待文档完整加载适合页面主资源加载完即可操作的场景。参数设置的原则是短超时适合确定会出现的内容设 3 到 5 秒即可长超时适合弱网环境或依赖接口返回的内容设 10 到 15 秒。不要因为怕超时就全篇设 60 秒这样脚本失败时排查的时间成本会很高。4.3 把数据落成本地文件JSON 和 CSV 两种写法自动化流程跑通了数据总得存下来。我常用的两种落地格式是 JSON 和 CSVJSON 适合保留嵌套结构CSV 适合表格化数据、方便后续用 Excel 或 pandas 处理。import json from drission_page import ChromiumPage page ChromiumPage() page.get(https://example.com/list) items [] for li in page.eles(css:.list-item): item { title: li.ele(.title).text, link: li.ele(a).attrs.get(href) } items.append(item) # 写入 JSON 文件 with open(result.json, w, encodingutf-8) as f: json.dump(items, f, ensure_asciiFalse, indent2)page.eles()返回所有匹配元素循环里用li.ele()做相对定位这样比在全局页面里重新查一次更稳定。attrs.get(href)用于提取元素属性值不一定会有所以用 dict 的get方法防止 KeyError。CSV 的写法也不复杂核心是用 csv 模块构成二维结构后写盘import csv with open(result.csv, w, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[title, link]) writer.writeheader() for item in items: writer.writerow(item)用utf-8-sig而不是utf-8是我血泪换来的经验Excel 直接打开 UTF-8 编码的 CSV 时中文会变成乱码加 BOM 头后能直接识别。类似的细节还有newline不加的话在 Windows 上每行数据后面会多一个空行。5. DrissionPage 排坑记录版本、登录态与元素操作的四个高频问题5.1 问题一下载了 v4.0.2 还是提示找不到模块现象pip 显示安装成功但import drission_page报 ModuleNotFoundError。原因最常见的是同时装了多个版本或安装时因为网络问题实际拉取的是旧包。另一种常见情况是 IDE 的解释器路径和命令行 pip 的解释器不一致导致包装到了另一个 Python 环境里。解决先查当前解释器里是否真的有这个包pip show drission_page如果版本不是 4.0.2就用虚拟环境重新装。稳妥的做法是pip uninstall drission_page后再指定版本安装。还可以在代码里打印包版本来自查from drission_page import __version__ print(__version__)它能直接帮你确认运行时用的版本跟命令行pip show的结果对照一下就能判断是不是环境混了。5.2 问题二SessionPage 请求模式拿不到 JS 渲染后的数据现象用 SessionPage 请求一个网址解析 HTML 时发现关键数据节点为空但浏览器里打开页面明明有内容。原因SessionPage 走的是纯 HTTP 请求拿到的只是服务器返回的静态 HTML。前端页面里的数据如果是 Vue、React 渲染出来的或者通过 AJAX 后加载的静态 HTML 里根本没有完整数据。解决换用 ChromiumPage 访问该页面。如果页面里既有静态部分又有动态渲染的数据可以用page.html属性拿到浏览器渲染完成后的完整页面源码再交给解析逻辑处理。另一个思路是直接找页面底层接口用 SessionPage 请求 JSON 数据但这需要先分析接口地址和参数可用但调试成本不小。5.3 问题三登录态在浏览器模式和请求模式之间“消失”现象用 WebPage 的浏览器模式登录了网站切到请求模式后发现带不上登录状态请求结果变成了未登录状态。原因DrissionPage 的浏览器模式和请求模式虽然是同一个对象但它们的 Cookie 存储机制是独立的。浏览器模式的 Cookie 在浏览器内核里请求模式的 Cookie 在 requests.Session 里change_mode()不会自动同步。解决手动从浏览器模式取出 Cookie塞给请求模式代码很简单from drission_page import WebPage web WebPage() web.get(https://example.com/login-page) # 执行登录操作 web.ele(#username).input(test_user) web.ele(#password).input(123456) web.ele(登录).click() # 取出浏览器模式下的 cookies设置给请求模式 web.change_mode() cookies web.cookies() web.set.cookies(cookies)web.cookies()会返回当前浏览器模式的 Cookie 字典集合web.set.cookies()可以把这些 Cookie 写入请求模式的 Session 中。顺序是先取后设务必在change_mode()切换完成后再设置。5.4 问题四元素明明存在却定位失败或点击无效现象查找元素时报 ElementNotFoundError或者元素找到了但click()没反应不报错也不跳转。原因分两类。一是元素被 iframe 包裹DrissionPage 和 Selenium 类似默认上下文在主文档里定位不到 iframe 内部元素二是元素在页面上存在但被遮挡比如弹窗、固定导航条盖住了目标按钮浏览器执行点击时点到了遮挡层上。解决iframe 的场景要先切入对应 iframe 再定位。点击无效的场景改用强制点击# iframe 内元素定位 frame page.get_frame(#iframe-id) target frame.ele(提交) target.click() # 被遮挡元素的强制点击 ele page.ele(确定) ele.click(by_jsTrue)get_frame()返回 iframe 内的文档操作对象之后在该对象上做定位就像在一个独立页面里操作。click(by_jsTrue)是直接通过 JS 触发该元素的点击事件不经过可见性检查绕开遮挡问题。这个参数在 v4.0.2 里是可靠的但也别一遇点击问题就无脑用先排查是不是 iframe 或遮挡更稳妥。5.5 问题五版本升级后 API 签名变了旧脚本跑不通现象原来的自动化脚本跑得好好的某天重新部署后报 TypeError说参数不匹配或者方法不存在。原因开发环境里用pip install drission_page不带版本号时会把依赖升到最新版本而新版 API 和 v4.0.2 不完全兼容。这类库的作者迭代速度快接口变动频繁锁版本是唯一可靠的解法。解决项目根目录维护 requirements.txt锁定精确版本drission_page4.0.2部署时用pip install -r requirements.txt。即使以后决定升级也要先在测试环境跑一遍回归用例再更新生产依赖。这是所有依赖第三方库的自动化项目必须养成的习惯否则就是给自己埋雷。6. 把自动化收尾登录态复用、异常重试与效果验证6.1 用 cookies 复用省掉每次登录频繁登录是自动化脚本最烦的瓶颈验证码、二次验证都会阻断流程。我的做法是把第一次登录获得的 cookies 存到本地文件后续脚本启动时先加载不存在就提醒手工登录一次。import json from drission_page import ChromiumPage cookie_file cookies.json page ChromiumPage() page.get(https://example.com) # 从文件加载 cookies try: saved_cookies json.load(open(cookie_file, encodingutf-8)) page.set.cookies(saved_cookies) page.get(https://example.com/home) except FileNotFoundError: input(请手动在打开的浏览器中完成登录然后回车继续...) # 保存登录后的 cookies cookies page.cookies() json.dump(cookies, open(cookie_file, w, encodingutf-8), ensure_asciiFalse)加载 cookies 后重新get()是因为有些站点只在特定站点域下识别登录态直接刷新当前页不一定生效。set.cookies()接受字典或 Cookie 列表以实际返回结构为准即可。6.2 异常重试的通用装饰器写法网络波动、页面加载超时、临时验证码都会让脚本中断。直接加循环会让代码很丑我会用一个装饰器统一处理重试逻辑。import time from functools import wraps def retry(times3, interval2): def decorator(func): wraps(func) def wrapper(*args, **kwargs): for i in range(times): try: return func(*args, **kwargs) except Exception as exc: if i times - 1: raise exc print(f第{i1}次失败{interval}秒后重试: {exc}) time.sleep(interval) return wrapper return decorator retry(times3, interval3) def fetch_data(page): page.get(https://example.com/api) return page.htmlretry装饰器的两个参数控制重试次数和间隔。它只捕获函数内部的异常超出次数就抛出原始错误方便定位问题。网络类异常可用短间隔触发风控的场景要用长间隔避免密集请求导致封禁。6.3 验证自动化脚本跑得稳的 3 个检查点脚本写完后不是能跑一次就算完了。我平时收尾前会过一遍这三项第一步检查异常输出是否可读手动调用一次函数看报错信息能否直接指出哪个环节断了第二步检查重复执行的一致性连续跑三次对比数据量是否一致若每次都不一样大概率是等待条件没写准第三步检查 cookies 复用是否生效重启脚本后看是否需要重新登录经常需要重新登录的脚本在无人值守时几乎没有可用性。DrissionPage 这个方向我前后用了大半年让我最满意的不是它比 Selenium 快多少而是它把“等待”这个黑匣子做透明了调试时不再靠猜。希望这篇笔记里的配置习惯和排坑记录能帮到你让你少走几段弯路。本文还有配套的精品资源点击获取