浏览器自动化框架完全问答:从原理到自研实践

发生于一次交流会发现行业内都基于WebDriver BiDi协议做自动化控制了,于是想对于微软的Edge浏览器做一个自己的框架;(预期是做这个的人少,自用被自动化检测的概率低)基于这个目的,对浏览器自动化框架相关的知识做了一个了解和梳理;

问:浏览器自动化框架的本质是什么?

答: 本质上,浏览器自动化框架是对浏览器内核 (如 Chromium、Gecko、WebKit)的远程控制 。内核就像提供底层能力的"基类",它暴露了调试协议(如 WebDriver、CDP、WebDriver BiDi)。自动化框架通过 WebSocket 或 HTTP 等通道实例化一个远程会话 ,然后调用内核支持的各种方法(导航、执行脚本、模拟输入、拦截网络等)。这些调用本质上是在操作内核内部的对象状态(DOM 树、JavaScript 堆、事件循环等)。框架代码并不是直接调用内核的 C++ 方法,而是将用户的高层操作(如 page.goto(url))翻译成符合协议的 JSON 命令,通过网络发送给内核,内核执行后返回结果。因此,逻辑上可以视为"远程调用内核对象的方法"。


问:目前主流的浏览器自动化协议和框架有哪些?

答: 市面上存在三大类协议及对应的成熟框架:

1. 传统 WebDriver 协议(HTTP 同步)

  • 协议特点:基于 HTTP 请求-响应,单向控制,浏览器无法主动上报事件。

  • 代表框架

    • Selenium:跨语言、跨浏览器,生态最庞大。

    • WebdriverIO(Node.js):封装优雅,支持多种服务端。

  • 适用场景:大规模跨浏览器测试、CI/CD 集成。

2. Chrome DevTools Protocol(CDP)

  • 协议特点:基于 WebSocket 双向通信,由 Chrome 发明,功能极其强大(网络、性能、调试等),但非 W3C 标准。

  • 代表框架

    • Puppeteer(Node.js,Google 官方):CDP 鼻祖,性能极致。

    • Pydoll(Python):异步直连 CDP,内置拟人化行为。

    • DrissionPage(Python):国产框架,语法简洁,无 WebDriver 依赖。

    • nodriver(Python):专为绕过风控设计。

  • 适用场景:爬虫、UI 自动化、需要深度控制浏览器的场景。

3. WebDriver BiDi 协议(W3C 新一代标准)

  • 协议特点:基于 WebSocket + JSON‑RPC 2.0,双向通信,融合了 WebDriver 的标准化与 CDP 的实时事件能力。

  • 代表框架

    • Playwright (微软官方):支持所有主流浏览器,API 现代,内置等待、网络拦截、移动端模拟。https://playwright.nodejs.cn/

    • Selenium 4+:实验性支持 BiDi。

    • WebdriverIO:同时支持 WebDriver、CDP 和 BiDi。

  • 适用场景:未来浏览器自动化的统一方向,兼顾标准化与高性能。

另外还有一些非典型但特色鲜明的框架,如:


问:有哪些核心名词需要理解?

答:

名词 解释
浏览器内核 负责解析 HTML/CSS、执行 JavaScript、渲染页面的底层引擎,如 Chromium(Chrome/Edge)、Gecko(Firefox)、WebKit(Safari)。
调试协议 内核暴露的远程控制接口,允许外部程序发送命令、接收事件。常见的有 CDP、WebDriver BiDi。
WebSocket 全双工通信协议,浏览器自动化中用于实现双向实时消息交换。
JSON‑RPC 2.0 一种轻量级远程调用协议,WebDriver BiDi 采用其消息格式(id、method、params、result、error)。
远程对象引用 执行 script.evaluate 返回的 DOM 元素或 JavaScript 对象的句柄(如 handle 或 sharedId),后续操作通过引用指向该对象。
动作链 一系列连续的输入事件(鼠标移动、点击、键盘按键),可模拟复杂的人机交互。
网络拦截 在请求发送前或响应返回后修改其内容,实现 Mock 数据、修改请求头、模拟失败等。
用户上下文 浏览器中隔离的会话环境,不同上下文拥有独立的 Cookie、Storage、缓存,用于多账号并行操作。

问:浏览器自动化的技术线路有哪些?如何选择?

答: 主要有三条线路,可根据需求选择:

线路 协议 优点 缺点 推荐场景
官方 WebDriver 线路 WebDriver(HTTP) 标准化、跨浏览器、资料丰富 单向阻塞、无法监听事件 传统 Web 自动化测试
CDP 线路 CDP(WebSocket) 速度快、功能强、隐匿性好 非标准、主要面向 Chromium 爬虫、高风控对抗、性能分析
WebDriver BiDi 线路 WebDriver BiDi 标准化 + 双向实时、未来主流 部分模块仍在完善 新项目、希望统一技术栈

选择建议

  • 如果追求稳定成熟、团队熟悉 → Selenium(WebDriver)

  • 如果追求极致性能、绕过风控 → Puppeteer(Node)或 Pydoll / DrissionPage(Python)

  • 如果希望拥抱未来、兼顾标准化 → Playwright(首选)


问:一个完整的自动化框架由哪些组件构成?

答: 无论采用何种协议,框架通常包含以下核心组件:

  1. 浏览器启动器(Launcher)
    1. 负责以特定参数启动浏览器进程(如指定用户数据目录、开启调试端口、设置代理)。
  2. 连接管理器(Session)
    1. 建立与浏览器的 WebSocket/HTTP 连接,管理会话 ID。
  3. 协议编码器/解码器
    1. 将用户 API 调用转换为符合协议的 JSON 消息,并解析返回的响应和事件。
  4. 命令调度器
    1. 发送命令、等待响应、处理超时和重试。
  5. 事件分发器
    1. 订阅感兴趣的事件(网络、日志、页面生命周期),并分发给注册的回调函数。
  6. 页面/元素抽象层(Page & Element)
    1. 封装 gotoclickevaluate 等常用操作,隐藏协议细节。
  7. 等待机制
    1. 智能等待元素出现、导航完成、网络空闲等,替代硬编码 sleep
  8. 资源管理
    1. 及时释放远程对象引用,关闭浏览器进程,避免内存泄漏。

问:如何设计一个基于 WebDriver BiDi 的自研框架?(上层控制与底层依赖)

答: 以下是一套完整的设计方案,涵盖底层依赖、协议实现和上层 API。

底层依赖

  • 语言:Python ≥ 3.8(异步优先,也可选 Node.js/Java/Rust)

  • 核心库

    • websockets:建立 WebSocket 连接

    • aiohttp 或 requests:获取浏览器的 WebSocket URL(通过 HTTP 端点)

    • asyncio:管理异步命令与事件循环

  • 浏览器:Edge / Chrome ≥ 96,或 Firefox ≥ 120

核心实现步骤

1. 启动浏览器并获取 WebSocket URL

以 Edge 为例:

bash 复制代码
msedge.exe --remote-debugging-port=9222 --user-data-dir=./profile

然后通过 HTTP 获取 webSocketDebuggerUrl:

python 复制代码
import requests
resp = requests.get("http://localhost:9222/json/version")
ws_url = resp.json()["webSocketDebuggerUrl"]
2. 实现 BiDi 会话类
python 复制代码
import asyncio, json, websockets

class BiDiSession:
    def __init__(self, ws_url):
        self.ws_url = ws_url
        self._id = 0
        self._pending = {}
        self._handlers = {}

    async def start(self):
        self.websocket = await websockets.connect(self.ws_url)
        asyncio.create_task(self._recv_loop())

    async def _recv_loop(self):
        async for msg in self.websocket:
            data = json.loads(msg)
            if "id" in data:          # 响应
                future = self._pending.pop(data["id"])
                future.set_result(data.get("result"))
            elif "method" in data:    # 事件
                for cb in self._handlers.get(data["method"], []):
                    await cb(data["params"])

    async def send(self, method, params):
        self._id += 1
        msg = {"id": self._id, "method": method, "params": params}
        future = asyncio.Future()
        self._pending[self._id] = future
        await self.websocket.send(json.dumps(msg))
        return await future

    def on(self, event, callback):
        self._handlers.setdefault(event, []).append(callback)
3. 封装 Page 类(上层控制)
python 复制代码
class Page:
    def __init__(self, session, context_id):
        self.session = session
        self.context_id = context_id

    async def goto(self, url):
        await self.session.send("browsingContext.navigate", {
            "context": self.context_id,
            "url": url
        })

    async def evaluate(self, js):
        res = await self.session.send("script.evaluate", {
            "expression": js,
            "target": {"context": self.context_id},
            "awaitPromise": True
        })
        return res["result"]["value"]

    async def click(self, selector):
        # 先获取元素引用
        ref = await self.evaluate(f"document.querySelector('{selector}')")
        if not ref:
            raise Exception("Element not found")
        # 调用原生 click
        await self.session.send("script.callFunction", {
            "functionDeclaration": "(elem) => elem.click()",
            "target": {"context": self.context_id},
            "arguments": [{"handle": ref["handle"]}],
            "awaitPromise": True
        })
4. 支持网络拦截(高风控场景)
python 复制代码
# 订阅网络事件
await session.send("session.subscribe", {
    "events": ["network.beforeRequestSent"]
})
# 添加拦截规则
await session.send("network.addIntercept", {
    "phases": ["beforeRequestSent"],
    "urlPatterns": [{"type": "pattern", "pattern": "https://api.example.com/*"}]
})
# 在事件回调中修改请求或返回 Mock 数据
session.on("network.beforeRequestSent", lambda params: mock_response(params))
复制代码

上层 API 设计目标

  • 自然语义 :page.goto(url), element.click(), page.on("network.response", callback)

  • 异步优先:充分利用 WebSocket 双向通信,避免阻塞

  • 自动等待 :内置 wait_for_selector、wait_for_navigation 等

  • 链式动作 :actions.move_to(element).click().perform()


问:自研框架与现有成熟框架的生态对比如何?

答:

维度 自研框架(基于 WebDriver BiDi) Playwright Selenium
标准化程度 高(W3C 标准) 高(BiDi + CDP) 高(传统 WebDriver)
开发工作量 大(需实现协议细节) 零(直接使用)
可定制性 完全可控 中等(黑盒) 中等
社区支持 强大(微软维护) 极强大
学习价值 极高(深入理解原理)
生产就绪 需大量测试

结论

  • 如果目标是学习浏览器自动化底层原理、打造完全自主的轻量框架,自研 WebDriver BiDi 是非常值得的投入。

  • 如果目标是快速解决业务问题(如爬虫、测试),直接使用 Playwright 或 Pydoll 是更高效的选择。


问:实践建议 ------ 从零开始实现一个最小化 BiDi 框架需要多少代码?

答: 一个能实现"启动 Edge、打开百度、输入关键词、点击搜索"的最小框架大约 200 行 Python 代码。核心步骤:

  1. 启动 Edge 调试端口(可用 subprocess)

  2. 获取 WebSocket URL

  3. 实现 BiDiSession 类(约 80 行)

  4. 实现 Page 类(goto, evaluate, query_selector, click,约 60 行)

  5. 实现 Element 类(约 30 行)

  6. 编写示例脚本(约 30 行)

完成后,你就拥有了一个可扩展的基础,可以逐步增加网络拦截、动作链、多标签管理等功能。


附:WebDriver BiDi 协议前世今生

1. 背景困境(2015‑2020)

  • WebDriver(经典):W3C 标准,跨浏览器,但单向 HTTP,无法接收事件。

  • CDP(Chrome DevTools Protocol):功能强大、双向实时,但仅限 Chromium,非标准。

2. 立项启动(2020)

  • **WebDriver BiDi:**2020年,W3C 浏览器测试与工具工作组正式立项,

  • 目标:WebDriver 的标准化 + CDP 的双向实时能力。

3. 厂商跟进与框架集成(2021‑2024)

  • Firefox 陆续实现核心 BiDi 模块,Chrome/Edge 通过 chromium-bidi 翻译层支持 BiDi。

  • Selenium 4 和 Puppeteer 提供实验性支持,Playwright 原生支持 BiDi(微软主导)。

  • 至此,主流浏览器与自动化框架初步完成 BiDi 集成,为后续标准化奠定基础。

4. 标准化与生态成熟(2024‑2026)

  • 2024年11月,W3C 发布 WebDriver BiDi 首个公开工作草案。

  • 2025年,Firefox 宣布逐步弃用 CDP 转向 BiDi,Puppeteer 23+ 稳定支持 Firefox + BiDi。

  • 2026年,Firefox 141 正式移除 CDP,BiDi 成为事实上的新一代标准。

  • 目前 Chrome、Edge、Firefox 全支持,Selenium、Puppeteer、Playwright、Cypress 等主流框架均已集成,未来将继续完善设备模拟、响应体获取等模块,有望统一浏览器自动化生态。

相关推荐
qq_452396232 小时前
第二篇:《主流UI自动化工具横向对比:Selenium、Cypress、Playwright、Puppeteer》
selenium·ui·自动化
seabirdssss2 小时前
从 Windows GUI 自动化到 Android 自动化:一套双端巡检脚本的重构过程
android·windows·自动化
15&30游山_玩水69☆156♀253 小时前
高性能自动化核心配件选型:西门子 S7-1500 CPU 与博世力士乐 IndraDrive M 伺服驱动器详解
运维·自动化
John_ToDebug3 小时前
Chromium 源码剖析:base::NoDestructor——更安全的静态单例解决方案
开发语言·c++·chrome
BY组态3 小时前
《工业4.0时代的智能组态解决方案:打造高效自动化控制系统》
运维·信息可视化·自动化
石榴树下的七彩鱼3 小时前
电商订单 OCR 识别实战:如何自动提取订单信息并实现发货自动化(附 Python / Java 示例)
人工智能·python·自动化·ocr·电商·电商自动化·api 接入
七夜zippoe3 小时前
OpenClaw 浏览器自动化实战
运维·chrome·自动化·浏览器·playwright·openclaw
薛定谔的猫36915 小时前
探索 MCP 协议:构建跨平台的 Agent 自动化生态
ai·自动化·agent·技术趋势·mcp
qq_4523962318 小时前
【工程实战】第十篇:性能监控集成 —— 自动化脚本的“副产品”:不仅仅是功能测试
python·功能测试·自动化