Skip to content

Latest commit

 

History

History
183 lines (153 loc) · 8.79 KB

File metadata and controls

183 lines (153 loc) · 8.79 KB

04 · 浏览器运行时

本篇定义"自动启停浏览器 + 会话/Profile 管理 + 可插拔传输驱动"的运行时。 对应传统 RPA 的 Robot 运行时,但把"浏览器如何被驱动"抽象成可热切换的传输契约。

1. 三层资源模型:Profile → Session → Page

flowchart TD
    subgraph IDENTITY["身份层 · Identity Profile(长期,可信累积)"]
        P1["profile=mac-m4-chrome-stable<br/>seed=identity-A<br/>cookies/localStorage 持久化<br/>一致性指纹 + 行为参数"]
    end
    subgraph SESSION["会话层 · Session(一次运行的浏览器实例)"]
        S1["绑定一个 Identity + 一个传输档位(T0–T3)<br/>+ 可选代理出口<br/>= 一个 Chrome 进程"]
    end
    subgraph PAGE["页面层 · Page / Tab"]
        PG1["标签页,AX-tree ref 定位<br/>行为合成在此作用"]
    end
    P1 --> S1 --> PG1
Loading
  • 一身份一进程:一个逻辑身份 = 一个持久化 Profile = 一个 Chrome 进程(借鉴 mochi "多 session = 多进程",避免跨身份指纹串味)。
  • 会话绑定档位与出口:档位(T1/T2/T3)与代理出口在会话创建时确定,运行中可因被拦而升档(触发换会话)。
  • Page 用 AX-tree ref:Agent/解释器都用稳定整型 ref,不手写选择器。

2. 浏览器生命周期状态机(自动启停 + 崩溃恢复)

stateDiagram-v2
    [*] --> Idle
    Idle --> Launching: 收到会话请求
    Launching --> Warming: 进程起+注入指纹/脚本(top-of-frame)
    Warming --> Ready: 一致性自检通过
    Warming --> LaunchFailed: 启动/自检失败
    Ready --> Busy: 执行动作
    Busy --> Ready: 动作完成
    Busy --> Recovering: 崩溃/断连/无响应
    Recovering --> Ready: 从持久化状态重建(cookies/URL/进度)
    Recovering --> Failed: 重试超限
    Ready --> Draining: 空闲超时/被回收
    Draining --> Parked: 保存状态→进程可复用/挂起
    Parked --> Ready: 命中复用
    Parked --> Idle: 达 TTL→关闭进程
    LaunchFailed --> Idle
    Failed --> Idle
Loading

设计要点:

  • 自动启动:会话请求触发按需启动;启动即注入一致性指纹脚本(addScriptToEvaluateOnNewDocumentFetch.fulfillRequest 注入,top-of-frame,避免源属性泄漏)。
  • 一致性自检:启动后跑一次内部探针(类 mochi Probe-Manifest),核对指纹面自洽、无 navigator.webdriver、无 HeadlessChrome 痕迹;不过则不投入使用。
  • 自动停止 / 回收:空闲超时 → Draining → 保存状态 → Parked(可复用或挂起)→ 达 TTL 关闭。避免"用完不关"的资源泄漏,也避免"每次全新会话"的可疑感。
  • 崩溃恢复:Recovering 从持久化的 cookies/当前 URL/回放进度检查点重建会话并续跑(对应 SC5)。
  • 检查点(checkpoint):回放解释器在关键节点落进度检查点,崩溃后可从最近检查点续跑而非从头。

3. 会话池与 Profile 池

flowchart LR
    REQ["会话请求(身份?/档位?/域)"] --> SCHED["池调度器"]
    SCHED -->|命中空闲同身份| REUSE["复用 Parked 会话(暖启动)"]
    SCHED -->|需新身份/并发| NEW["新建会话(冷启动)"]
    subgraph POOLS["资源池"]
        IDLEPOOL["Parked 会话池(LRU + TTL)"]
        PROFILES["Identity Profile 库(Vault 管理)"]
        PROXIES["代理/出口池(T3, 住宅优先)"]
    end
    REUSE --> IDLEPOOL
    NEW --> PROFILES
    NEW --> PROXIES
    SCHED --> LIMITS["并发/速率护栏(按域)"]
Loading
  • 暖启动复用:优先复用同身份 Parked 会话,降低启动开销、也让身份"连续在线"更像真人。
  • 并发与速率护栏:按域限制并发会话数与请求速率(责任使用 + 降低风控触发)。
  • 身份轮换(T3):高频长跑时从 Profile 库轮换身份+住宅出口,防止单身份声誉累积(与 03 §7 呼应)。
  • 本地优先:默认不启用代理(本机住宅 IP 最一致);仅在策略要求或声誉风险时启用 T3 代理池。

4. 传输驱动契约(BrowserNode)——架构不变量 I-1

上层(回放解释器 / Actor)只依赖统一契约,不感知底层是 patchright 还是裸 CDP。驱动作为受控子进程经 gRPC over UDS 挂到控制面。

classDiagram
    class BrowserNode {
        <<gRPC 接口>>
        +Capabilities() Caps
        +LaunchSession(IdentitySpec, Tier, ProxySpec) SessionHandle
        +Navigate(session, url, waitPolicy)
        +Snapshot(session) AXTree+Screenshot
        +Resolve(session, LocatorBundle) ElementRef
        +HumanClick(session, ref, behaviorParams)
        +HumanType(session, ref, textOrSecretRef, behaviorParams)
        +HumanScroll(session, target, behaviorParams)
        +Extract(session, schema) StructuredData
        +Fetch(session, request) Response
        +Assert(session, Assertion) bool
        +SaveState(session) StatePath
        +CloseSession(session)
        +SelfCheck(session) CoherenceReport
    }
    class DriverHTTP_T0
    class DriverPW_T1
    class DriverCDP_T2
    class DriverCDPPlus_T3
    BrowserNode <|.. DriverHTTP_T0
    BrowserNode <|.. DriverPW_T1
    BrowserNode <|.. DriverCDP_T2
    BrowserNode <|.. DriverCDPPlus_T3
Loading

契约设计原则:

  • 只暴露拟人原语:没有裸 click/type,只有 HumanClick/HumanType/HumanScroll(行为合成内建,借鉴 mochi 无 page.click 的做法)——从 API 层面杜绝"机器人式瞬移点击"。
  • Capabilities() 声明能力:如 T0 不支持 JS 执行/复杂交互;解释器据此决定可否降档。
  • 机密以 secretRef 传递:驱动向 Vault 解引用,明文不过 gRPC 边界(I-5)。
  • Fetch 走浏览器自身:需要旁路请求已知 XHR 时也经 Chromium 发出,保持 JA4/H2 一致(03 §4)。
  • SelfCheck 返回一致性报告:供池在 Warming 阶段判定是否投用。

4.1 各驱动实现要点

驱动 运行时 关键实现 许可
driver-http (T0) 任意 curl_cffi / bogdanfinn tls-client:Chrome 形状 TLS+H2;无浏览器进程 MIT/BSD
driver-pw (T1) Node 或 Python Patchright,channel=chrome 驱动真实 Chrome;humanization 层 Apache-2.0
driver-cdp (T2) Python(参考 nodriver)/ 未来 Bun(mochi) / 自研 Go --remote-debugging-pipe 裸 CDP、无 Runtime.enable、无 TCP 端口;一致性注入 + OS 级输入 nodriver=AGPL-3.0;mochi=MIT
driver-cdp+ (T3) 同 T2 T2 + 代理编排 + 可选 patched 二进制(camoufox/Cloak)+ CAPTCHA 升级钩子 视组件

为什么核心 Go、驱动可异种语言:Go 做控制面(守护、并发、单二进制)最省心;而"过第③层"的最强实现现在在 Python(nodriver)/Bun(mochi)。用 gRPC 子进程隔离,既拿到最强隐身,又不牺牲核心的工程性(I-1 的价值)。语言选择完全藏在 BrowserNode 契约之后,可随生态演进替换。


5. 会话创建的完整时序(含一致性自检与选档)

sequenceDiagram
    autonumber
    participant INTP as 回放解释器/Actor
    participant POOL as 池调度器
    participant VAULT as Vault
    participant DRV as Transport Driver
    participant CH as 系统 Chrome

    INTP->>POOL: 申请会话(域, 身份?, 期望档?)
    POOL->>POOL: 选档(记忆/探针) + 选身份Profile
    POOL->>VAULT: 取身份画像 + 代理出口(如T3)
    VAULT-->>POOL: (profile,seed) + proxy
    POOL->>DRV: LaunchSession(identity, tier, proxy)
    DRV->>CH: 起进程(pipe 模式/channel=chrome, headful)
    DRV->>CH: 注入一致性指纹脚本(top-of-frame)
    DRV->>DRV: SelfCheck 一致性 + 地理校验
    alt 自检通过
        DRV-->>POOL: SessionHandle(Ready)
        POOL-->>INTP: 会话就绪
    else 自检失败/地理矛盾
        DRV-->>POOL: 拒绝(GeoMismatch/CoherenceFail)
        POOL->>POOL: 换身份/换出口 重试
    end
Loading

6. 与其它文档衔接

  • 档位定义、指纹一致性、行为合成细节 → 03
  • 会话/身份/代理由谁治理、Vault 存储模型 → 05
  • 解释器如何调用这些原语跑技能 → 02
  • 驱动契约如何映射到 Agent 可见的 MCP 原语 → 06

验收检查表(本篇)

  • 浏览器自动启动/停止/回收,空闲不泄漏、非全新会话(SC5)。
  • 崩溃可从检查点/持久化状态恢复续跑(SC5)。
  • Profile→Session→Page 三层模型,一身份一进程。
  • BrowserNode 统一契约,只暴露拟人原语,档位可热切换(I-1/I-2)。
  • 会话启动含一致性自检 + 地理校验,不带矛盾上场(I-3)。
  • 机密以 secretRef 传递,明文不过驱动边界(I-5)。