214 lines
9.0 KiB
Markdown
214 lines
9.0 KiB
Markdown
# 架构说明(v1.1.0)
|
||
|
||
本文档梳理项目中的主要模块、职责划分以及核心流程,帮助维护者快速了解整体结构。当前版本包含短信验证码登录、Cookie 持久化以及 AI 驱动的滑块验证码自动破解功能。
|
||
|
||
## 模块概览
|
||
|
||
```
|
||
├── README.md // 使用说明与运行指引
|
||
├── ARCHITECTURE.md // 架构概览与流程说明(本文档)
|
||
├── IMPLEMENTATION.md // 关键实现细节记录
|
||
├── QUICKSTART.md // 快速开始指南
|
||
├── CHANGELOG.md // 版本更新日志
|
||
├── release.md // 发布说明
|
||
├── login.md // 早期需求与操作步骤
|
||
├── package.json // 项目配置(v1.1.0)
|
||
├── src/
|
||
│ ├── login.ts // 豆瓣登录脚本入口(集成滑块验证)
|
||
│ └── slider/ // 滑块验证模块(v1.1.0 新增)
|
||
│ ├── index.ts // 模块导出
|
||
│ ├── types.ts // 类型定义
|
||
│ ├── detector.ts // 主滑块检测器
|
||
│ ├── detector-self-learning.ts // 第二滑块检测
|
||
│ ├── slider-controller.ts // 滑块控制器
|
||
│ ├── cli.ts // CLI 批量工具
|
||
│ ├── validator.ts // 结果验证工具
|
||
│ ├── detection/
|
||
│ │ └── candidate-search.ts // 多策略检测
|
||
│ └── utils/
|
||
│ ├── geometry.ts // 几何计算
|
||
│ └── image.ts // 图像处理
|
||
├── noflag/ // 原始验证码截图输出目录
|
||
├── output/ // 标注结果输出目录
|
||
└── typescript-spec.md // 团队 TypeScript 编码规范
|
||
```
|
||
|
||
## 登录流程分层(v1.1.0)
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ main() │
|
||
│ - 启动 Chromium │
|
||
│ - 复用或创建上下文 │
|
||
│ - 调用 loginWithSms() │
|
||
│ - 保存 Cookies │
|
||
└─────────────────────────────────────────┘
|
||
│
|
||
┌──────────────────▼────────────────────┐
|
||
│ loginWithSms() │
|
||
│ - 输入手机号 │
|
||
│ - 触发短信验证码 │
|
||
│ - [v1.1.0] 自动处理滑块验证 │
|
||
│ - 等待并提交短信验证码 │
|
||
│ - 校验是否登录成功 │
|
||
└───────────────────────────────────────┘
|
||
│
|
||
┌────────────┴──────────────┐
|
||
│ │
|
||
┌─────▼──────────────┐ ┌─────────▼──────────────┐
|
||
│ SliderController │ │ isLoggedIn() │
|
||
│ - 等待滑块出现 │ │ - 检查 Cookie(dbcl2) │
|
||
│ - 截图到 noflag/ │ │ - 确认登录表单状态 │
|
||
│ - 调用 detector │ └────────────────────────┘
|
||
│ - 计算距离 │
|
||
│ - 拖动滑块 │
|
||
│ - 验证成功标识 │
|
||
│ - 失败重试(10次) │
|
||
└────────────────────┘
|
||
│
|
||
┌────────▼───────────────┐
|
||
│ SliderDetector │
|
||
│ - 图像缩放(800px) │
|
||
│ - 多策略检测 │
|
||
│ - 候选框评分 │
|
||
│ - 绘制标注到 output/ │
|
||
└────────────────────────┘
|
||
│
|
||
┌────────▼───────────────┐
|
||
│ CandidateSearch │
|
||
│ - 暗区域检测 │
|
||
│ - Canny 边缘检测 │
|
||
│ - 颜色量化 │
|
||
│ - LAB 色彩空间 │
|
||
│ - IoU 去重 │
|
||
└────────────────────────┘
|
||
```
|
||
|
||
**关键模块职责**:
|
||
|
||
- `prepareContext()`:负责加载已有 Cookie、创建新上下文以及兜底跳转登录页
|
||
- `loginWithSms()`:串联短信登录流程,涵盖用户输入与滑块自动化
|
||
- `SliderController`:Playwright 集成,控制滑块验证的完整流程
|
||
- `SliderDetector`:图像处理和滑块位置检测的核心算法
|
||
- `CandidateSearch`:多种图像识别策略的并行执行
|
||
- `isLoggedIn()`:封装判定逻辑,避免各处重复编写 Cookie/页面检查
|
||
|
||
## 依赖与交互
|
||
|
||
- **Playwright**:启动浏览器、操作页面元素、持久化 `storageState`、控制滑块拖动
|
||
- **Sharp**:图像处理(缩放、边缘检测、颜色量化、模板匹配)
|
||
- **Node.js**:文件读写、路径与环境变量处理
|
||
- **readline**:在控制台等待用户输入短信验证码
|
||
- **环境变量**:
|
||
- `DOUBAN_PHONE`:登录手机号(必填)
|
||
- `DOUBAN_AUTO_SLIDER`:启用自动滑块验证(可选,值为 1 时启用)
|
||
- **`~/douban-cookie.json`**:保存登录态的 storageState 文件,下次运行直接复用
|
||
- **`noflag/`**:原始验证码截图存储目录
|
||
- **`output/`**:标注结果(红框)存储目录
|
||
|
||
## 数据流(v1.1.0)
|
||
|
||
1. **初始化阶段**
|
||
- 读取 `DOUBAN_PHONE`,未配置则终止
|
||
- 检查 `DOUBAN_AUTO_SLIDER` 环境变量
|
||
- 若存在本地 Cookie 文件,加载后访问登录页以确认是否仍然有效
|
||
|
||
2. **登录流程**
|
||
- 无有效登录态时执行短信登录:
|
||
- Playwright 填写手机号并请求验证码
|
||
- **[v1.1.0]** 自动检测并处理滑块验证码:
|
||
1. 等待验证码 iframe 加载
|
||
2. 截图验证码区域到 `noflag/` 目录
|
||
3. 使用 Sharp 将图像缩放到 800px 宽度
|
||
4. 并行运行四种检测策略
|
||
5. 计算距离:`(缺口X - 滑块X) / scaleX`
|
||
6. 绘制红框标注保存到 `output/` 目录
|
||
7. 拖动滑块到计算位置
|
||
8. 检测成功标识(`.tc-success`)
|
||
9. 失败则刷新重试(最多 10 次)
|
||
- 控制台输入短信验证码并提交
|
||
|
||
3. **状态持久化**
|
||
- 登录成功后调用 `context.storageState()` 写入 `~/douban-cookie.json`
|
||
- 浏览器关闭,后续脚本可直接复用该文件
|
||
|
||
4. **图像数据流**
|
||
```
|
||
原始验证码(340x191)
|
||
│
|
||
▼ 截图
|
||
noflag/captcha-timestamp.png
|
||
│
|
||
▼ 缩放到 800px
|
||
内存中的处理图像(800x449)
|
||
│
|
||
▼ 多策略检测
|
||
候选框数组 [{x,y,w,h,score}]
|
||
│
|
||
▼ 评分排序 + IoU去重
|
||
最佳滑块位置 [b1, b2]
|
||
│
|
||
▼ 绘制红框
|
||
output/captcha-timestamp-detected.png
|
||
│
|
||
▼ 计算距离
|
||
移动距离 = (b2.x - b1.x) / scaleX
|
||
```
|
||
|
||
## 日志与错误处理
|
||
|
||
- 关键步骤均在控制台打印提示,便于追踪流程
|
||
- **[v1.1.0]** 滑块检测过程的详细日志:
|
||
- 图像缩放信息(原始尺寸 → 检测尺寸)
|
||
- 检测到的滑块数量和位置
|
||
- 每个滑块的评分和尺寸
|
||
- 距离计算公式和结果
|
||
- 成功/失败状态和重试次数
|
||
- 验证码相关操作采用提示 + `prompt` 方式等待人工输入
|
||
- 登录失败或异常会设置 `process.exitCode` 并输出详细错误信息
|
||
- 视觉调试:`output/` 目录中的红框标注图便于人工验证检测准确性
|
||
|
||
## v1.1.0 核心创新
|
||
|
||
### 简化的距离计算算法
|
||
|
||
**核心原理**:"两只小鸟嘴尖距离"
|
||
|
||
```typescript
|
||
// 双滑块模式(推荐)
|
||
const distance = (box2.x - box1.x) / scaleX;
|
||
|
||
// 单滑块模式(兜底)
|
||
const distance = box.x / scaleX;
|
||
```
|
||
|
||
**为什么这样简单?**
|
||
1. 检测在 800px 宽度图像上进行(scaleX ≈ 2.35)
|
||
2. 两个滑块的左边界水平距离就是移动距离(缩放坐标系)
|
||
3. 除以 scaleX 转换回实际显示坐标系(340px)
|
||
4. 避免复杂的 iframe 偏移、页面坐标转换等计算
|
||
|
||
**v1.0.0 vs v1.1.0**:
|
||
- v1.0.0:需要人工完成滑块验证
|
||
- v1.1.0:自动检测、计算、拖动,成功率约 50%
|
||
|
||
### 多策略并行检测
|
||
|
||
并行运行四种算法,提高鲁棒性:
|
||
|
||
1. **暗区域检测**:基于亮度阈值查找暗色滑块
|
||
2. **Canny 边缘检测**:查找边缘密集区域
|
||
3. **颜色量化**:K-means 聚类找独特色块
|
||
4. **LAB 色彩空间**:在感知均匀的色彩空间中检测
|
||
|
||
候选框通过 IoU 去重,避免重复检测同一个滑块。
|
||
|
||
### 自学习模板匹配
|
||
|
||
使用第一个检测到的滑块作为模板,在图像中查找第二个滑块:
|
||
|
||
1. 提取第一个滑块的边缘特征
|
||
2. 在剩余区域进行模板匹配
|
||
3. 验证 y 坐标一致性(偏差 < 25px)
|
||
4. 确保两个滑块在合理的水平距离范围内
|