Spitolas — 基于浏览器的网络爬虫¶
Spitolas 是一个状态机驱动的网络爬虫,它驱动真实的 Chromium 浏览器,通过类似用户的操作(点击、表单填写、iframe 遍历)来发现应用状态。所有产生的 HTTP 流量在 CDP 层面被捕获,并输入到 vigolium 的扫描管道中。
工作原理¶
RunSpider(config, recordSaver)
│
▼
┌─────────────────────────────────────────────────┐
│ 浏览器池(通过 rod 控制 Chromium) │
│ ├── CDP 网络捕获(所有标签页/iframe) │
│ └── 自动对话框处理(alert/confirm/prompt) │
└────────────────────┬────────────────────────────┘
│ 导航到目标 URL
▼
┌─────────────────────────────────────────────────┐
│ 捕获初始状态(DOM 快照 + SHA256 ID) │
└────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 爬取循环 │
│ 1. 选取下一个状态(候选 + 优先级) │
│ 2. 重置浏览器 → 导航到初始状态 │
│ 3. 重放到达目标状态的最短路径 │
│ 4. 触发未触发的动作(点击/悬停/提交) │
│ 5. 捕获新 DOM → 比较 → 添加状态/边 │
│ 6. 重复直到满足终止条件 │
└────────────────────┬────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 网络写入器 │
│ CDP 事件 → httpmsg.HttpRequestResponse │
│ → RecordSaver(数据库)→ 扫描管道 │
└─────────────────────────────────────────────────┘
核心概念¶
状态与状态图¶
状态是由 SHA256(strippedDOM)[:16] 标识的 DOM 快照。状态图是一个有向图,其中节点是状态,边是引起状态转换的动作。状态间的导航使用 Dijkstra 最短路径算法(备用方案为 Yen 的 K 最短路径)。
近似重复检测使用归一化 Levenshtein 距离(阈值:10%)。对于大型 DOM(超过 10K 字符),采用基于采样的距离以提高性能。
动作与候选元素¶
候选可点击元素通过 CSS 选择器发现(a、button、[onclick]、[role=button]、input[type=submit]、框架特定绑定如 [ng-click]、[v-on:click] 等)。每个候选在被触发后成为 Eventable(图边),将源状态与目标状态通过事件类型(点击、悬停、回车)连接起来。
片段(视觉页面分割)¶
页面被分解为片段——由 XPath、边界框、子树大小和内容哈希标识的 DOM 区域。两种模式:
- Landmark(默认):基于 DOM 的快速提取
- VIPS:基于视觉的页面分割,使用多轮递减阈值
片段比较使用 APTED 树编辑距离算法。片段管理器跟踪重复/等效片段上的探索状态,并使用候选影响力评分来决定下一步探索哪些状态。
表单处理¶
表单处理器检测并填写表单,使用智能值生成:
- 字段名称感知的值(电子邮件、密码、电话、URL 等)
- 约束感知生成(遵循
pattern、min/max、minlength/maxlength) - 当一次性填写所有输入失败时,使用成对回退
- 支持文件上传,具有类型感知的文件选择
探索策略¶
| 策略 | 描述 |
|---|---|
| 默认(BFS/DFS) | 基于片段优先级的确定性遍历 |
adaptive |
Exp3.1 多臂老虎机——通过重要性加权概率采样平衡利用(已知良好动作)与探索(未尝试动作)。奖励基于新状态发现。 |
浏览器管理¶
- 内嵌二进制文件:附带 Chromium(macOS/Windows/Linux)和 ungoogled-Chromium(Linux)。首次运行时解压,按版本缓存。
- 无头模式:加载扩展时使用
headless=new(支持 Chrome 扩展,不同于旧版无头模式)。 - 扩展:通过
--load-extension加载(例如,爬取时使用 uBlock Origin Lite 进行广告拦截)。 - 为爬取禁用安全标志:
--disable-web-security、--ignore-certificate-errors、--allow-running-insecure-content。 - 池:多个浏览器实例,采用轮询选择。
网络捕获¶
流量在浏览器层面(而非页面层面)通过 CDP 事件捕获,覆盖所有标签页、弹出窗口和 iframe:
NetworkRequestWillBeSent→ 记录请求NetworkResponseReceived→ 记录响应头NetworkLoadingFinished→ 获取响应体
基于哈希的去重防止重复记录。清理循环移除过期的待处理请求(超过 15 秒)。捕获的流量转换为 httpmsg.HttpRequestResponse,并通过 RecordSaver 接口保存,来源标记为 "spidering"。
终止条件¶
当满足以下任一条件时,爬取停止:
- 发现的最大状态数
- 最大持续时间已过
- 达到最大爬取深度
- 连续失败次数达到上限
- 没有更多候选动作可探索
- 上下文取消
入口点¶
result, err := spitolas.RunSpider(ctx, spitolas.SpiderConfig{
TargetURL: "https://example.com",
MaxStates: 100,
MaxDuration: 10 * time.Minute,
MaxDepth: 5,
BrowserCount: 1,
CrawlStrategy: "adaptive", // 或 "" 表示默认
}, recordSaver)
返回 SpiderResult,包含:发现的状态数、执行/失败的动作数、提交的表单数、持续时间和保存的记录数。