news 2026/10/14 3:04:11

DrissionPage:基于 Python 的自研内核网页自动化工具全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DrissionPage:基于 Python 的自研内核网页自动化工具全解析
  • 网页爬虫
  • 浏览器控制

【免费下载链接】DrissionPage

Python based web automation tool. Powerful and elegant.

项目地址:https://gitcode.com/gh_mirrors/dr/DrissionPage
点击查看免费下载

导读

DrissionPage 是当前仓库 DrissionPage 所承载的一款基于 Python 的网页自动化工具,其核心主张是"简洁而强大"。本文以仓库 README 为主线,结合 Chromium 内核实现、Session 页面封装 与 定位语法解析器 等源码,系统讲解它的运行环境、自研内核对比 Selenium 的优势、内置亮点功能、ini 配置体系与 POM 使用模式。读完本文,你将掌握 DrissionPage 的架构定位、核心 API 用法以及如何在真实项目中落地这套自动化方案。

运行环境与支持范围

根据 README「运行环境」一节的说明,DrissionPage 对运行环境的要求非常宽松:

  • 操作系统:Windows、Linux、Mac 全平台支持;
  • Python 版本:3.6 及以上;
  • 浏览器:支持 Chromium 内核浏览器(如 Chrome 和 Edge)以及 electron 应用。

这一节的实际含义是:DrissionPage 的浏览器控制能力建立在 Chromium 的 DevTools 协议(CDP)之上,因此凡是能暴露调试端口的 Chromium 内核浏览器都能接入。仓库入口文件 DrissionPage/init.py 只导出了四个公开类:Chromium、SessionPage、ChromiumOptions、SessionOptions,印证了"一个工具覆盖两种页面操作模式"的设计——Chromium负责真实浏览器(d 模式),SessionPage负责基于 requests 的纯请求模式(s 模式)。

版本方面,当前仓库 version.py 记录版本号为5.0.0b0(5.0 首个测试版),文档内容与该版本行为一致,安装与使用请以当前仓库实际代码为准。

理念:简洁而强大

README 用一句话概括项目理念:简洁而强大("Simpler and more powerful")。这一理念贯穿了源码设计的每个层面:

  • 入口极简:只需一行Chromium()即可启动并接管浏览器(见 chromium.py 的__new__逻辑,它会自动寻找端口、启动进程或接管已存在的浏览器);
  • 定位极简:内置一套"文本即语法"的定位系统(详见下文"极简定位语法");
  • 封装极简:大量常用功能被收敛成set、wait、states、scroll等挂件(widget),避免在业务代码中堆积样板逻辑,这在 chromium_base.py 的挂件实现中清晰可见。

自研内核:与 Selenium 的对比

README「强大的自研内核」一节明确指出,本库采用全自研内核,不基于 Selenium 的 webdriver,并列出以下对比优点。我们逐一结合源码验证。

1. 不基于 webdriver,无需下载浏览器驱动

Selenium 需要为每个浏览器版本下载对应 driver;DrissionPage 直接通过 CDP WebSocket 与浏览器通信。从 chromium.py 可以看到,连接的核心动作是构造ws://{address}/devtools/browser/{browser_id}地址并创建Driver实例,全程不涉及任何 driver 可执行文件。

2. 运行速度更快

两条技术路径共同带来速度提升:

  • 传输层轻量化:基于 WebSocket 的 CDP 直连,省去 driver 进程转发;
  • 解析引擎用 lxml:README 在亮点功能中特别强调"内置 lxml 作为解析引擎,解析速度成几个数量级提升"。从 locator.py 可以看到,当定位结果是 CSS 时,代码会尝试用lxml.cssselect将 CSS 翻译成 XPath 后走 XPath 查询,充分利用 lxml 的解析性能。

3. 跨 iframe 查找元素,无需切入切出

Selenium 操作 iframe 必须执行switch_to.frame()来回切换;DrissionPage 把 iframe 视为普通元素,可以直接在 frame 内继续查找。源码在 chromium_base.py 提供get_frame()/get_frames()方法,并且底层维护了Tabs._frames映射(chromium.py),记录每个 frame 属于哪个 tab,再通过 CDP 的DOM.performSearch全局搜索(includeUserAgentShadowDOM=True)实现跨 frame 查找,逻辑更统一、更清晰。

4. 可同时操作多个标签页,无需切换

浏览器对象Chromium持有标签页管理器Tabs(chromium.py),内部以{session_id: target_id}、{target_id: {session_id}}等映射维护所有标签页会话。每个ChromiumTab都是独立对象(chromium_tab.py),tab.get()、tab.ele()各自独立执行,天然支持多标签页并发操作,无需切换焦点。

5. 直接读取浏览器缓存保存图片,无需 GUI 点击另存

元素截图与资源获取均通过 CDP 完成。页面级截图走Page.captureScreenshot(chromium_base.py),图片等二进制资源可通过脚本从缓存读取,全程无 GUI 交互。

6. 可以对整个网页截图,包括视口外部分

get_screenshot(full_page=True)的实现(chromium_base.py)通过self.rect.size获取整页宽高,再以captureBeyondViewport=True配合clip视口参数调用 CDP 截图,覆盖视口外内容。

7. 可处理非 open 状态的 shadow-root

README 特别提到可处理"非open状态的 shadow-root"。元素对象提供sr属性(chromium_element.py),通过DOM.describeNode获取shadowRoots并包装为ShadowRoot对象,配合DOM.performSearch的includeUserAgentShadowDOM参数,使查找能穿透 closed shadow DOM。

亮点功能逐个拆解

README「亮点功能」一节罗列了自研内核之外的大量人性化设计,下面结合源码逐个展开。

极简的定位语法

这是 DrissionPage 最具辨识度的能力。它把 CSS、XPath、文本、属性等查找方式统一为一种极简字符串语法,由 locator.py 负责解析。常用写法包括:

写法含义内部处理
#id/.class按 id / class 查找_preprocess展开为@id/@class后走 XPath
t:div/tag:div按标签名查找生成//*[name()="div"]
text:登录文本模糊匹配生成//*/text()[contains(.,"登录")]/..
text=登录文本精确匹配生成//*[text()="登录"]
text^xxx/text$xxx文本以 xxx 开头 / 结尾生成starts-with/substring表达式
@class=xxx单属性精确查找生成//*[@class="xxx"]
@@class=a@id=b多属性"与"查找多个条件用and连接
@\|class=a@id=b多属性"或"查找多个条件用or连接
@!class排除某属性生成not(...)条件
xpath://.../css:...原生 XPath / CSS直接透传
ax:role=button@name=确定无障碍树查找解析成role、accessibleName键值

从上表可以看到,=:^$四个符号分别表示精确、模糊、开头、结尾匹配,:^$三种前缀都可用在文本、属性和标签上。解析逻辑在str_to_xpath_loc()与_preprocess()(locator.py)中逐分支生成 XPath,多属性@@/@|/@!的"与 / 或 / 非"组合由_make_multi_xpath_str()(locator.py)完成。此外get_loc()还兼容 Selenium 风格的('id', 'value')元组定位(translate_loc()),迁移旧代码成本很低。

定位入口统一为ele(locator, index)与eles(locator):index控制返回第几个(负数表示倒数),返回ChromiumElement或元素列表。BaseElement._ele()(base.py)在找不到元素时返回NoneElement,并可通过全局设置Settings.set_raise_when_ele_not_found(True)改为抛出ElementNotFoundError。

无处不在的等待与自动重试

README 指出"无处不在的等待和自动重试,使不稳定的网络变得易于控制"。在源码中有三层体现:

  1. 页面加载等待:ChromiumBase._d_connect()(chromium_base.py)通过Page.navigate发起导航,随后_wait_loaded()轮询_ready_state(complete/interactive)直到加载完成或超时;
  2. 元素查找等待:wait_for_ele()在超时时间内反复调用DOM.performSearch,直到找到目标元素或超时,这与wait.eles_loaded()、wait.ele_displayed()等显式等待方法一脉相承;
  3. 请求自动重试:Chromium.get()和SessionPage.get()/post()都接受retry、interval参数。以 session_page.py 的_make_response()为例,默认按retry_times(默认 3 次)循环发起请求,每次失败后sleep(interval)(默认 2 秒)再重试,直到成功或达到上限。

这些默认值来自 configs.ini 的[others]段(retry_times = 3、retry_interval = 2),可用ChromiumOptions.set_retry()修改。

强大的下载工具

README 提到"提供强大的下载工具,操作浏览器时也能享受快捷可靠的下载功能"。浏览器级下载由DownloadManager(downloader.py)实现:它监听 CDP 的Browser.downloadWillBegin与Browser.downloadProgress事件,把下载任务包装成DownloadMission,支持:

  • 指定保存路径(set_path());
  • 重命名与强制后缀(set_rename()、set_suffix());
  • 同名文件的处理策略(set_file_exists():rename/overwrite/skip);
  • 任务取消(cancel())与跳过(skip())。

同时,ChromiumBase._download_by_browser()(chromium_base.py)提供编程式下载:动态创建一个带download属性的<a>元素并触发点击,把下载行为统一交给下载管理器,从而实现"操作浏览器时也能快捷下载"。

反复使用已经打开的浏览器,调试方便

这是开发调试体验的关键设计。Chromium()的__new__(chromium.py)会先探测目标地址(默认127.0.0.1:9222)上是否已有可控制的浏览器:

  • 若已存在且端口可连通(connect_browser()中test_connect()成功),则直接接管该浏览器,不重新启动(browser.py);
  • 若不存在则按配置启动一个新浏览器实例。

因此调试时可以先用命令行chrome --remote-debugging-port=9222打开浏览器并登录好账号,再运行脚本直接复用会话,无需每次从零启动。existing_only配置项进一步强制"只接管已存在浏览器,否则报错"。

ini 文件保存常用配置,自动调用

README 强调"使用 ini 文件保存常用配置,自动调用,提供便捷的设置,远离繁杂的配置项"。仓库自带默认配置文件 configs.ini,各段作用如下:

配置段关键项默认值说明
[paths]download_path、tmp_path空下载目录、临时目录
[chromium_options]address127.0.0.1:9222浏览器调试地址
browser_pathchrome浏览器可执行文件路径
arguments一组--启动参数含--no-first-run、--disable-popup-blocking等
extensions[]加载的插件目录列表
prefs弹窗、通知相关偏好写入用户目录 Preferences 文件
flags{}实验特性开关
load_modenormal页面加载模式
userDefault浏览器用户目录 profile
auto_portFalse是否自动分配端口
system_user_pathFalse是否复制系统浏览器用户目录
existing_onlyFalse是否只接管已存在浏览器
new_envFalse是否使用全新环境
[session_options]headersSafari UA 等一组头requests 会话默认请求头
[timeouts]base、page_load、script10、30、30三种超时(秒)
[proxies]http、https空代理设置
[others]retry_times、retry_interval3、2请求重试次数与间隔

ChromiumOptions(read_file=True)构造时会通过OptionsManager自动读取 ini(chromium_options.py),并把arguments中解析出的--user-data-dir、--profile-directory同步为user_data_path与user。所有set_*方法都返回对象自身,支持链式调用;最后用save()/save_to_default()写回 ini,实现配置持久化。

值得展开的是arguments中几个常用启动参数,可通过ChromiumOptions的语义化方法设置:

  • headless(True)→ 追加--headless=new无头模式;
  • no_imgs()/no_js()/mute()→ 分别追加--blink-settings=imagesEnabled=false、--disable-javascript、--mute-audio;
  • incognito()→ 同时追加--incognito与--inprivate(兼容 Edge);
  • ignore_certificate_errors()→--ignore-certificate-errors;
  • set_user_agent()→--user-agent;
  • set_proxy()→--proxy-server(自动解析代理账号密码);
  • set_load_mode()→ 可选normal、eager、none,对应页面加载完成判定策略(chromium_base.py 中eager模式在 DOM 触发后即可Page.stopLoading)。

这些语义化方法定义在 chromium_options.py,比手写原始参数更不易出错。

内置 lxml 解析引擎

如前所述,CSS 定位会优先尝试用lxml.cssselect翻译为 XPath(locator.py);而s_ele()系列方法(chromium_base.py)会把实时页面 HTML 交给make_session_ele()生成 lxml 元素对象,供快速批量解析。这就是"解析速度成几个数量级提升"的实现基础。

使用 POM 模式封装,可直接用于测试

POM(Page Object Model)是测试领域的主流设计模式。DrissionPage 的公开类本身就是天然 Page Object:

  • 每个页面/标签对象(ChromiumTab、SessionPage)封装了该页面的全部操作;
  • 元素对象(ChromiumElement、SessionElement)封装了查找与交互;
  • 测试代码只需继承或组合这些对象即可组织页面层与用例层,无需重复实现底层协议细节。

同时 settings.py 提供了set_raise_when_ele_not_found、set_raise_when_click_failed、set_raise_when_wait_failed等开关,把"找不到就静默返回 / 抛异常"的行为统一配置,便于在测试与脚本两种场景间切换。

高度集成的便利功能

从源码结构看,便利功能被封装成大量"挂件",按职责挂在页面或元素上(chromium_base.py):

  • page.wait→ 等待页面、元素状态(waiter.py);
  • page.set→ 修改属性、cookie、UA、代理、下载设置等(setter.py);
  • page.states→ 查询页面/元素状态(states.py);
  • page.actions→ 鼠标键盘动作链(actions.py);
  • page.scroll→ 滚动控制(scroller.py);
  • page.rect→ 尺寸与坐标(rect.py);
  • page.console→ 浏览器控制台监听(console.py);
  • page.screencast→ 录屏功能(screencast.py);
  • page.listen→ 网络与元素事件监听(listener.py);
  • 元素侧还有ele.set、ele.states、ele.wait、ele.rect、ele.sr(shadow-root)、ele.pseudo(伪元素)等。

此外页面对象还内置run_js()(执行 JS)、run_cdp()(直接调 CDP 命令)、add_init_js()(新文档注入脚本)、session_storage()/local_storage()(读写本地存储)、handle_alert()(处理弹窗)、get_screenshot()(截图)、save()(保存页面/PDF)、clear_cache()(清理缓存)、back()/forward()/refresh()(导航)等大量开箱即用的方法。

两种页面模式与核心用法

基于源码入口(init.py),DrissionPage 提供两条主线用法,本文给出最小可运行示例。

d 模式:Chromium 对象操作真实浏览器

from DrissionPage import Chromium, ChromiumOptions # 使用默认配置(自动读取 configs.ini),启动或接管浏览器 browser = Chromium() # 或自定义配置后启动 co = ChromiumOptions() co.set_local_port(9333).headless(True).set_user_agent('Mozilla/5.0 ...') browser = Chromium(co) # 获取最新标签页并访问 tab = browser.latest_tab tab.get('https://example.com') # 极简定位 + 交互 search = tab.ele('#search-input') search.clear() search.input('DrissionPage') tab.ele('t:button@text:搜索').click() # 按标签+属性+文本组合定位 # 多标签页操作:无需切换 tab2 = browser.new_tab('https://example.org') print(tab.title, tab2.title) # 直接读取当前标签页 cookie print(tab.cookies())

其中browser.get_tab()、browser.get_tabs()可按 id、序号、标题或 URL 获取标签页;browser.close_tabs()可批量关闭(others=True关闭其他);browser.reconnect()可在浏览器意外断线后重连;browser.quit()关闭浏览器并可选择删除临时用户数据目录。

s 模式:SessionPage 对象发起纯请求

from DrissionPage import SessionPage page = SessionPage() # 自动读取 configs.ini 的 session_options page.get('https://example.com') # 支持自动重试与编码识别 print(page.title) # 从 <title> 提取 print(page.html) # 渲染后的文本 data = page.ele('xpath://div[@class="list"]')

从源码看,SessionPage基于requests.Session封装(session_page.py),在_make_response()中自动补全Referer、Host等请求头,并用set_charset()(session_page.py)依次从content-type、HTML<meta charset>、apparent_encoding三个来源确定编码,避免中文网页乱码。

双模式协同:cookies 互通

ChromiumTab同时继承ChromiumBase与SessionPage(chromium_tab.py),因此一个标签页对象可调用change_mode('s')切换到 s 模式、change_mode('d')切回 d 模式,并支持cookies_to_session()/cookies_to_browser()双向搬运 cookie(chromium_tab.py)。典型场景是:先用浏览器登录获取 cookie,再把 cookie 同步给 requests 会话去并发抓取,兼顾反爬与速度。

项目结构与扩展建议

README 的目录组织在源码中对应清晰的包结构(项目根目录):

  • _base/:BasePage、DrissionElement等抽象基类;
  • _browsers/:Chromium浏览器对象与ChromiumContext隔离环境;
  • _configs/:ChromiumOptions、SessionOptions及默认 configs.ini;
  • _elements/:ChromiumElement、SessionElement、NoneElement;
  • _functions/:定位、cookie、工具、文案等底层函数;
  • _pages/:ChromiumBase、ChromiumTab、ChromiumFrame、SessionPage;
  • _units/:actions、waiter、setter、states、listener、downloader等挂件。

对于有扩展需求的团队,建议基于BasePage/DrissionElement派生自己的页面对象,把重复的登录、翻页、解析逻辑收敛为业务 Page 类,配合Settings的异常开关实现可复用的 POM 测试体系。

结语

DrissionPage 通过 CDP 直连 Chromium 内核,用一套自研的极简定位语法与丰富的挂件体系,把浏览器自动化从"驱动配置繁琐、定位语法割裂、iframe 切换痛苦"的传统体验中解放出来。本文所涉及的特性均可回溯到 DrissionPage 包内的对应源码:内核连接看 chromium.py,定位语法看 locator.py,配置体系看 configs.ini 与 chromium_options.py,双模式协同看 chromium_tab.py。如需上手,直接阅读仓库 README.md 并结合上述源码文件实践即可。

  • 网页爬虫
  • 浏览器控制

【免费下载链接】DrissionPage

Python based web automation tool. Powerful and elegant.

项目地址:https://gitcode.com/gh_mirrors/dr/DrissionPage
点击查看免费下载
上一篇:Playnite游戏库管理终极指南:免费整合20+平台与70多种模拟器
下一篇:ComfyUI_UltimateSDUpscale 分块放大实战:6G显存也能出图的参数配置

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 3:03:58

SLF4J在SpringBoot中的日志门面实践与优化

1. SLF4J在SpringBoot中的核心价值作为Java生态中最主流的日志门面框架&#xff0c;SLF4J(Simple Logging Facade for Java)在SpringBoot项目中扮演着关键角色。不同于直接调用Log4j或Logback等具体实现&#xff0c;SLF4J通过门面模式提供统一的日志API&#xff0c;这种设计带来…

作者头像 李华
网站建设 2026/10/14 3:03:55

ADO2.20 Class 封装实战:从 msado20.tlb 导入到可维护数据访问层

简介&#xff1a;ADO2.20 Class 是一套面向 Visual C 开发者的 ActiveX Data Objects 类库&#xff0c;由非中文开发者在 CodeProject 上发布&#xff0c;旨在简化 VC 程序对 SQL Server、Oracle、Access 等数据源的访问&#xff0c;让开发者无需深入底层 ADO 接口即可快速集成…

作者头像 李华
网站建设 2026/10/14 3:03:25

年会抽奖九宫格+转盘小程序:动画与随机逻辑避坑指南

简介&#xff1a;一份面向企业年会场景的抽奖小程序资源&#xff0c;包含九宫格抽取幸运者和转盘抽奖两个页面&#xff0c;无需数据库&#xff0c;所有数据以静态方式配置&#xff0c;可直接用于年会“抽人发红包”环节。规则设计完整&#xff1a;先用九宫格抽出一名免红包幸运…

作者头像 李华
网站建设 2026/10/14 3:03:22

一文掌握Kubernetes:从容器编排到集群实战

搞容器化半年之后&#xff0c;我发现自己天天敲docker run&#xff0c;但一说到"上生产"&#xff0c;马上就被问倒了&#xff1a;容器挂了怎么自动恢复&#xff1f;流量大了怎么扩容&#xff1f;多台机器上容器怎么调度&#xff1f;新版本怎么无损发布&#xff1f;这…

作者头像 李华
网站建设 2026/10/14 3:03:00

C# override全面解析:多态、虚方法与实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华