这是 drission 的版本更新说明。如果你还不知道它是什么:它是用 Rust 写的高性能反检测浏览器自动化库,内置字符验证码 OCR 与图片滑块缺口距离识别,API 对齐 DrissionPage。上一篇介绍文章写的是
0.1,而这半个月里它连跳两个大版本到了0.3.0——变化大到值得单独写一篇。

一句话总结这次更新:
默认后端从 Camoufox 换成了 Google Chrome(CDP),Camoufox 反检测内核改为「一行 feature 开启」;同时点选验证码、Session TLS/JA3 指纹伪装、每浏览器独立指纹这几块硬骨头都啃下来了,Windows 也从「能跑」变成「稳跑」。
版本演进一览(0.1 → 0.3.0)
先用一张表看清这半个月发生了什么:
| 版本 | 主题 | 关键变更 |
|---|---|---|
0.1.0 | 首个公开版 | Camoufox/Juggler 反检测驱动 · 字符 OCR · 极验滑块 · 吐环境 · 高并发池 |
0.1.1 | 能力扩张 | CDP 后端、Session/WebPage 双模、采集导出、代理池健康、顶象滑块 |
0.2.0 | 默认后端转向(破坏性) | 默认 = Chromium/CDP(Google Chrome)· Windows 稳定 + Chrome 路径智能探测 |
0.3.0 | 双协议对齐 + 网络层补环境 | CDP 全面对齐 Camoufox · 点选验证码 · Session TLS/JA3 指纹 · 每浏览器指纹 · AI 技能文档 |
下面挑最值得说的几件事展开。
重磅:默认后端换成 Google Chrome(CDP)
这是 0.2.0 的一处破坏性变更,也是整个升级的主线:
- 默认
default = ["cdp"]:cargo add drission装上即开箱驱动/接管 Google Chrome(及 Edge / Brave / Chromium / Electron),最精简、不含 Camoufox 重代码。 - Camoufox 改为 opt-in:原来的 Firefox 反检测内核及其全部高层能力(
Page/WebPage/SessionPage/Pool/ 吐环境 / 过盾 / 滑块…)收到--features camoufox之下(slider/impersonate会自动带入)。
为什么这么改?因为现实里大多数目标站点对 Chromium 系最友好,Cloudflare Turnstile 等关卡也更认 Chrome 形态;而需要 Firefox 内核级反检测时再一行打开即可,两边不互相拖累编译。
升级很简单——依赖里显式声明你要的后端就行:
[dependencies]
# 只用 Chrome / CDP(默认,最精简)
drission = "0.3"
# 要 Camoufox / Firefox 反检测内核及其全部高级能力时:
# drission = { version = "0.3", features = ["camoufox"] }
⚠️ 从
0.1(默认 camoufox)升上来的同学注意:如果你的代码用到Page/WebPage/BrowserPool/ 过盾 / 滑块 / 吐环境,这些现在归camoufoxfeature,记得把它加回features。
双后端,同一套代码,切 feature 即换内核
0.3.0 把 CDP 后端全面对齐了 Camoufox:在已对齐的导航/元素/输入之上,补齐了 iframe、Shadow DOM、动作链、控制台 / WebSocket 监听、截图录像、文件上传、对话框、登录态、cookie、翻页、吐环境、高并发池、修饰组合键、OCR……
意义在于:你的业务代码几乎不动,换个 feature 就换了浏览器内核。prelude 里的 Browser / Tab / Pool 是「规范别名」——默认构建它们指向 Chromium,开 --no-default-features --features camoufox 就指向 Camoufox。

use drission::prelude::*;
#[tokio::main]
async fn main() -> drission::Result<()> {
// 这段代码在「默认(CDP/Chrome)」与「--features camoufox」下都能编、都能跑
let browser = Browser::launch(BrowserOptions::new().headless(true)).await?;
let tab = browser.new_tab(Some("https://example.com")).await?;
println!("标题 = {:?}", tab.title().await?);
println!("h1 = {:?}", tab.ele("tag:h1").await?.text().await?);
browser.quit().await?;
Ok(())
}
cargo run --example cdp_demo # 默认 = Chrome/CDP
cargo run --example quickstart --no-default-features --features camoufox # 切 Camoufox
小坑提醒:默认
cdp与camoufox同时存在时,统一接口按「cdp 优先」解析,所以跑 Camoufox 系示例务必带--no-default-features,否则会跑成 CDP 后端或类型冲突。
亮点一:点选 / 文字点选验证码(路线图兑现)
上一篇文章的「路线图」里点名了「点选/文字点选验证码」——0.3.0 把它做出来了,对标 ddddocr 的 det=True。

它由两个纯 Rust 组件构成,推理依旧走 tract、不依赖原生 onnxruntime:
Det—— ddddocr 目标检测模型common_det.onnx(YOLOX):416 灰边 letterbox → 推理 → NMS →Vec<BBox>(原图坐标 + 置信度)。首次自动下载模型到缓存。ClickWord—— 点选求解器:solve(img, targets)一步完成「检测 → 逐框 OCR → 按提示顺序做全局最优指派」,返回依次点击的坐标。
use drission::ocr::ClickWord;
use drission::prelude::*;
#[tokio::main]
async fn main() -> drission::Result<()> {
let cw = ClickWord::new().await?; // 首次自动下载 det + ocr 模型
// cap: 干净点选图字节; targets: 按提示顺序要点的字,如 ["全","验","体"]
let cap: Vec<u8> = /* 从接口/截图拿到的图 */ vec![];
let targets = vec!["全".to_string(), "验".to_string(), "体".to_string()];
let hits = cw.solve(&cap, &targets)?;
for h in &hits {
println!("「{}」 置信 {:.2} 图内点 ({},{})", h.target, h.affinity, h.point.0, h.point.1);
}
Ok(())
}
仓库里的 yidun_click 示例把整条链路跑通了易盾「文字点选」:监听 c.dun.163.com/api/* 拿到干净底图与点击顺序(而不是截图——截图会把工具栏拍进去、缩放错位点不中),solve 出坐标后用 minimum-jerk 拟人轨迹 + 可信点击逐字点下去,最后读 api/check 响应当作「点击是否被接收」的铁证。
cargo run --example yidun_click --features cdp,ocr
实话实说边界:单字艺术体 OCR 非 100%(ddddocr 固有),且易盾另有行为风控——字点得准 ≠ 必过。本库负责把「识别 + 按序可信点击」这条工程链路做扎实,风控对抗是另一件持续的事。
亮点二:Session 套真实浏览器 TLS / JA3 / JA4 指纹
这是我个人最得意的一块,称它为网络层的「补环境」。
双模采集的经典姿势是:浏览器过盾拿到 cookie → 灌进纯 HTTP 的 Session → 用 Session 高速接力抓海量接口。但现代 WAF(Akamai / Cloudflare / DataDome)不止看 cookie,还看 TLS 握手指纹(JA3/JA4)+ HTTP2 指纹(Akamai)——Rust 默认 TLS 栈的指纹一眼就被识破,接力请求当场被拦。
0.3.0 新增 --features impersonate:给 Session 套上真实浏览器的握手指纹。底层是 wreq + wreq-util(reqwest 硬分叉 + BoringSSL,内置 100+ 浏览器模拟档)。

use drission::prelude::*;
#[tokio::main]
async fn main() -> drission::Result<()> {
// profile 一开,TLS/JA3/JA4 + HTTP2 指纹 + UA/默认头 全部变成 Chrome 形态
let mut s = SessionPage::new(SessionOptions::new().profile(BrowserProfile::Chrome))?;
s.get("https://tls.peet.ws/api/all").await?;
println!("{}", s.text()); // 看 ja3_hash / ja4 已是 Chrome 指纹
Ok(())
}
可选 BrowserProfile::{Chrome, Firefox, Safari, Edge},None 则是默认不伪装(零成本)。示例 session_tls 在同一进程里用 None 与 Chrome 各打一次 tls.peet.ws,实测 JA3 / JA4 / Akamai 指纹全部改变(t13d1011h2… → t13d1516h2…、UA Firefox → Chrome137):
cargo run --example session_tls --features impersonate
默认关、零成本:不开这个 feature 就不会引入 BoringSSL。开启需要
cmake+nasm;Windows 走 MSVC 或 mingw,x86_64-pc-windows-gnu交叉编译已实测产出真.exe。
亮点三:每浏览器一份「连贯指纹」
并发起 N 个浏览器时,如果它们指纹一模一样,等于自报家门。0.3.0 新增 CdpFingerprint / CdpFingerprintPool(对标 Camoufox 指纹池):给每个浏览器套一份自洽连贯的指纹——UA、平台、语言、时区、屏幕、硬件并发、内存、WebGL、canvas/audio 噪声整套对齐,而不是各字段乱拼。
use drission::cdp::{CdpFingerprintPool, ChromiumBrowser, ChromiumOptions};
#[tokio::main]
async fn main() -> drission::Result<()> {
let pool = CdpFingerprintPool::generate(5); // 5 份各异指纹
let base = ChromiumOptions::new().headless(true);
for fp in pool.profiles() {
let browser = ChromiumBrowser::launch(fp.apply_to_options(base.clone())).await?;
// …各浏览器的 canvas# / 屏幕 / 时区 / 硬件 各不相同…
browser.quit().await?;
}
Ok(())
}
两种模式:generate(n) 同 OS 变体(保真 UA/WebGL,对 Turnstile 友好);personas(n) 完整跨 OS 画像(连 UA/platform/WebGL 都伪装)。示例 cdp_fingerprint 会把每个浏览器的指纹 dump 成表,直观看出「各不相同」。
亮点四:CDP 高并发池、吐环境、组合键、下载,一并补齐
CDP 后端这次把工程化能力补成了完整体:
- 高并发池
ChromiumPool:多 worker × 多标签,每任务一个独立BrowserContext(cookie/缓存/storage 隔离)、带proxy时走 CDP 原生 per-context 代理、失败重试 + 健康自愈、map保序、map_resumable断点续抓(配Checkpoint)。
use drission::prelude::*;
let pool = ChromiumPool::launch(
ChromiumPoolOptions::new()
.size(2) // 2 个 Chrome 进程
.tabs_per_worker(2) // 每进程 2 标签 → 并发 4
.base_options(ChromiumOptions::new().headless(true)),
).await?;
let results = pool.map((0..100).collect::<Vec<_>>(), |i, tab| async move {
tab.get(&format!("https://example.com/p/{i}")).await?;
Ok::<String, drission::Error>(tab.title().await?)
}).await;
- 吐环境
tab.dump_env()移植到 CDP:把后端无关核心抽到新模块crate::envkit,两后端共用同一套「探针 /env.js/ 导出工程 / 同构双跑验证」逻辑。示例cdp_dump_env真机自验证「同构双跑 45/45 字段一致」。 - CDP 修饰组合键 / 热键:
tab.key_combo(&[Keys::CONTROL, "a"])/ele.shortcut(...),CDP 原生modifiers位掩码下发,页面读得到e.ctrlKey/metaKey为true;常见编辑键(Ctrl/Cmd+A/C/X/V/Z/Y)无头下也真正执行编辑动作。 - CDP 下载管理
tab.downloads():基于 CDP 原生Page.downloadWillBegin/downloadProgress事件按guid聚合(比文件系统轮询更准、自带 received/total 字节),多任务并发跟踪 + 实时进度 + 重命名。
亮点五:Windows 从「能跑」到「稳跑」
0.2.0 + 0.3.0 把 Windows 这条线补硬了:
- Chrome 路径智能探测(对标 DrissionPage
get_chrome_path):环境变量 → 用户级%LOCALAPPDATA%与系统级%PROGRAMFILES%→ 注册表App Paths\chrome.exe→PATH扫描,全程优先 Google Chrome,解决「免管理员用户级安装 / 非默认盘探测不到」。 - 进程树兜底(Job Object):两后端启动浏览器后把进程绑进
KILL_ON_JOB_CLOSE的 Job,quit/Drop时级联终止整棵进程树——根治了「主进程杀了、渲染/GPU 子进程变孤儿」的老问题。
亮点六:给 AI 编程助手的技能文档
现在很多人是「让 AI 基于某个库写代码」。0.3.0 新增了 docs/SKILL.md:一份面向 AI 编程助手的接口 / feature / 构建规则权威速查,覆盖从基础用法到点选验证码点击的复制即用代码,并把「Camoufox 系示例必须 --no-default-features --features camoufox」这类铁律写在显眼处。所有片段都按真实函数签名核验过,照着写一次编译通过。README 顶部也声明:AI 基于本库开发请先遵循该 skill。
升级指南(从 0.1 / 0.2 上来)
按你的需求挑 feature 即可:
| 你要的能力 | 依赖写法 |
|---|---|
| 只驱动 Chrome / CDP(默认) | drission = "0.3" |
| Camoufox / Firefox 反检测 + 高层能力 | features = ["camoufox"] |
| 字符 OCR / 点选验证码 | features = ["ocr"](可与 cdp 共用) |
| 图片滑块缺口距离 | features = ["slider"](自动带入 camoufox) |
| Session 浏览器 TLS / JA3 指纹 | features = ["impersonate"](自动带入 camoufox) |
跑示例时记住一条铁律:Camoufox / slider / impersonate 系示例要带 --no-default-features,CDP / ocr 系默认即可。完整命令在每个示例的头注释和 examples/README.md 里都写好了,复制即用(这次也把 ~45 个示例的过时命令逐个修正了)。
平台与版本
- 平台:macOS(arm64,主力)、Linux、Windows(命名管道传输 + Job Object 进程兜底);
impersonate的 Windows 交叉编译已实测产出.exe。 - 工具链:Rust ≥ 1.85(edition 2024)。
写在最后
0.3.0 这一版的主线,是把 drission 从「Camoufox 反检测专精」扩成「Chrome 默认开箱 + Camoufox 一行开启」的双后端形态,并补齐了点选验证码、TLS 指纹伪装这两块过去要东拼西凑的硬能力——目标始终没变:把「反检测浏览器 + 验证码识别 + 高并发采集」收进一个 Rust 库,保留 DrissionPage 那种「打开就会用」的手感。
- crates.io:
cargo add drission(按需features = ["camoufox", "ocr", "slider", "impersonate"]) - 文档:docs.rs/drission
- 仓库:github.com/MageGojo/drission-rs
- 完整变更:CHANGELOG.md
⚠️ 免责声明:本项目仅供学习与合法、非盈利用途。使用者须遵守目标站点的
robots协议与当地法律法规,禁止用于任何违法、侵害他人利益或采集受保护数据的行为。使用本库产生的一切后果由使用者自行承担。
如果这次更新帮到你,欢迎到 GitHub 点个 star;评论区也欢迎聊聊你在 Rust 爬虫 / 验证码对抗里踩过的坑。


658

被折叠的 条评论
为什么被折叠?



