|
|
@@ -0,0 +1,212 @@
|
|
|
+# tbsg — 饿了么闪购店铺采集
|
|
|
+
|
|
|
+OCR + AI 驱动的 Android 端到端自动化,从搜索到二维码解析全流程。
|
|
|
+
|
|
|
+## 目录结构
|
|
|
+
|
|
|
+```
|
|
|
+tbsg/
|
|
|
+├── main.py # 主入口(920行):步骤编排 + 验证码处理 + 二维码解析
|
|
|
+├── ai_helper.py # DeepSeek AI:页面分类 / 店铺解析 / 坐标定位
|
|
|
+│
|
|
|
+├── steps/
|
|
|
+│ ├── executor.py # SafeExecutor:uiautomator2 安全执行器(点击/滑动/输入/重连)
|
|
|
+│ └── ocr.py # OCR 类:RapidOCR 封装(裁剪/压缩/置信度过滤)
|
|
|
+│
|
|
|
+├── detect_slider_button.py # 滑块按钮检测:HSV 橙色识别 + 轮廓筛选
|
|
|
+├── detect_captcha_edge.py # 验证码缺口边缘检测:橙色覆盖层最左 X 坐标
|
|
|
+│
|
|
|
+├── yzm/
|
|
|
+│ └── tmp_captcha_test2.py # 滑块验证码破解:TouchPipe 压感 + 轨迹模拟 + jfbym API
|
|
|
+│
|
|
|
+└── files/
|
|
|
+ ├── captcha1.png # 验证码模板(用于模板匹配检测)
|
|
|
+ ├── line.png # 滑块辅助图
|
|
|
+ └── share.png # 分享按钮辅助图
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 运行
|
|
|
+
|
|
|
+```bash
|
|
|
+cd tbsg
|
|
|
+python main.py # 全流程,默认搜索"矿泉水"
|
|
|
+python main.py step1 # 仅步骤1:打开 App
|
|
|
+python main.py step2 金活正红花油 # 仅步骤2:搜索指定关键词
|
|
|
+python main.py step3 # 仅步骤3:遍历店铺列表
|
|
|
+python main.py --device DEVICE_ID # 指定设备
|
|
|
+```
|
|
|
+
|
|
|
+**默认设备:** `T4VK4LM7AAUOV8AY`(多设备时交互选择)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 全流程(cmd="all")
|
|
|
+
|
|
|
+### 步骤 1:打开 App
|
|
|
+
|
|
|
+```
|
|
|
+1. app_stop("me.ele") → 关闭饿了么
|
|
|
+2. app_start("me.ele") → 重新启动
|
|
|
+3. sleep(5s) → 等加载
|
|
|
+4. OCR 识别底部 12% 区域 → 检测"我的"确认进入成功
|
|
|
+```
|
|
|
+
|
|
|
+**核心代码:** `step1_open_app(ex)` — 第106行
|
|
|
+
|
|
|
+### 步骤 2:搜索商品
|
|
|
+
|
|
|
+```
|
|
|
+阶段0 — 进入买药频道
|
|
|
+ 1. OCR 全屏识别 → 找"看病买药"按钮 → 点击 → sleep(3s)
|
|
|
+
|
|
|
+阶段1 — 点击搜索栏
|
|
|
+ 2. OCR 顶部 30% 区域 → 找"搜索" → 偏移 -120px 点击输入框 → sleep(3s)
|
|
|
+
|
|
|
+阶段2 — 输入关键词
|
|
|
+ 3. OCR 确认进入搜索页(搜索文字位置是否移动)
|
|
|
+ 4. 偏移 -180px 点击输入框 → 聚焦
|
|
|
+ 5. set_input_ime(True) → send_keys(keyword) → 点击"搜索"
|
|
|
+ 6. OCR 验证:检测"筛选"/"快递"确认搜索结果页
|
|
|
+
|
|
|
+阶段3 — 切换到快递配送
|
|
|
+ 7. 若检测到"快递"→ 点击切换(确保全国范围搜索)
|
|
|
+```
|
|
|
+
|
|
|
+**核心代码:** `step2_search(ex, keyword)` — 第135行
|
|
|
+
|
|
|
+### 步骤 3:遍历店铺列表
|
|
|
+
|
|
|
+```
|
|
|
+while True:
|
|
|
+ 1. 截图 → OCR → AI 解析店铺列表(店名/商品/价格/坐标)
|
|
|
+ 2. 过滤:店名含中文或字母 + 有价格 = 有效店铺
|
|
|
+
|
|
|
+ 3. 逐个点击店铺:
|
|
|
+ a. 去重检查(店名+价格 key)
|
|
|
+ b. 点击进入店铺
|
|
|
+ c. 调用 step4_parse_qr() 获取二维码链接
|
|
|
+ d. 返回搜索页(最多3次 back)
|
|
|
+
|
|
|
+ 4. 一个批次处理完 → 滑动到倒数第二张卡片位置
|
|
|
+ 5. 连续3批无新店铺 → 结束
|
|
|
+
|
|
|
+输出:
|
|
|
+ 最终结果表(店铺名 / 商品 / 价格 / 链接)
|
|
|
+```
|
|
|
+
|
|
|
+**核心代码:** `step3_swipe_and_enter(ex, keyword)` — 第782行
|
|
|
+
|
|
|
+**滑动方式:** ADB `input swipe` 分3段手指滑动(模拟真人),非 uiautomator2 swipe
|
|
|
+
|
|
|
+### 步骤 4:进入店铺 → 解析二维码
|
|
|
+
|
|
|
+```
|
|
|
+1. 等待加载(sleep 6s)
|
|
|
+ └─ 异常处理:验证码检测(模板匹配 + OCR关键词)→ 自动破解
|
|
|
+ └─ 安全验证弹窗 → 反复 back 退出
|
|
|
+
|
|
|
+2. 确认在店铺页:OCR 检测"刚刚搜过" + "评价"
|
|
|
+
|
|
|
+3. AI 定位商品标题坐标:
|
|
|
+ a. 截图 → OCR → 返回所有文字块坐标
|
|
|
+ b. DeepSeek AI 匹配商品标题 → 返回点击坐标
|
|
|
+ c. 最多重试3次(每次重新OCR+AI)
|
|
|
+
|
|
|
+4. 点击商品标题 → 进入详情页
|
|
|
+ └─ 验证:检测"加入购物车"/"立即购买"关键字
|
|
|
+ └─ 验证码拦截 → 自动处理
|
|
|
+
|
|
|
+5. 找右上角"分享"按钮 → 点击 → 二维码弹窗 → 截图
|
|
|
+
|
|
|
+6. pyzbar 解析二维码 → 返回 URL
|
|
|
+```
|
|
|
+
|
|
|
+**核心代码:** `step4_parse_qr(ex, product_title, shop_name)` — 第342行
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 验证码处理
|
|
|
+
|
|
|
+### 检测方式(双重)
|
|
|
+
|
|
|
+1. **模板匹配** — `captcha1.png` 5种算法(灰度/边缘/直方图/高斯/二值化),阈值 0.30
|
|
|
+2. **OCR 关键词** — "拖动滑块"/"请按住滑块"/"安全验证"
|
|
|
+
|
|
|
+### 破解方式(`yzm/tmp_captcha_test2.py`)
|
|
|
+
|
|
|
+| 步骤 | 说明 |
|
|
|
+|------|------|
|
|
|
+| 1. 截图 | 截取验证码弹窗 |
|
|
|
+| 2. 滑块定位 | `detect_slider_button()` — HSV 橙色检测 |
|
|
|
+| 3. 缺口定位 | `detect_captcha_edge()` — 橙色覆盖层左边缘 |
|
|
|
+| 4. 计算距离 | 缺口左边缘 - 滑块中心 X |
|
|
|
+| 5. 轨迹生成 | 加速→匀速→减速 + 随机扰动 |
|
|
|
+| 6. 执行滑动 | TouchPipe(ATX 9008端口压感通道) |
|
|
|
+| 7. jfbym API | 云码平台兜底(`http://api.jfbym.com`) |
|
|
|
+
|
|
|
+**最多重试 5 次**,失败后等待人工处理。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 核心模块详解
|
|
|
+
|
|
|
+### SafeExecutor(`steps/executor.py`)
|
|
|
+
|
|
|
+封装 uiautomator2,提供安全操作:
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `tap(x, y)` | 坐标点击 |
|
|
|
+| `swipe(distance)` | 分多段模拟真人滑动(X轴±30px 随机偏移) |
|
|
|
+| `input_text(xpath, text)` | 清空再输入(模拟打字间隔) |
|
|
|
+| `safe_click(xpath)` | 点击 + 验证码检测 + 自动处理 |
|
|
|
+| `No_slider()` | 验证码检测 + `_solve_slider()` 自动破解 |
|
|
|
+| `is_connected()` | 连接检测 + 自动重启 atx-agent |
|
|
|
+| `_recover_service()` | stop → start atx-agent → reconnect |
|
|
|
+
|
|
|
+### OCR(`steps/ocr.py`)
|
|
|
+
|
|
|
+基于 RapidOCR(`rapidocr_onnxruntime`),无需 GPU。
|
|
|
+
|
|
|
+| 参数 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `rect` | 裁剪区域 `[left, top, right, bottom]` |
|
|
|
+| `confidence` | 置信度阈值(默认 0.1) |
|
|
|
+| `pattern` | 正则过滤 |
|
|
|
+| `detail` | `'all'`/`'text'`/`'first'` |
|
|
|
+
|
|
|
+- 大图自动压缩到 960px 防止 OOM
|
|
|
+- 矩形坐标自动映射回原始尺寸
|
|
|
+
|
|
|
+### AIParser(`ai_helper.py`)
|
|
|
+
|
|
|
+调用 DeepSeek API,三个核心功能:
|
|
|
+
|
|
|
+| 方法 | 输入 | 输出 |
|
|
|
+|------|------|------|
|
|
|
+| `parse_shops()` | OCR 原始结果 | 店铺列表(店名/商品/价格/坐标) |
|
|
|
+| `check_page()` | OCR 文字列表 | 页面类型(`normal`/`risk`/`qrcode`) |
|
|
|
+| `_call()` | system_prompt + user_prompt | AI 响应 JSON |
|
|
|
+
|
|
|
+**API 地址:** `https://ai-api.dfwy.tech/v1/messages`
|
|
|
+**模型:** `deepseek-v4-flash-nothinking`
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 依赖
|
|
|
+
|
|
|
+```bash
|
|
|
+pip install uiautomator2 opencv-python rapidocr-onnxruntime Pillow numpy requests pyzbar
|
|
|
+```
|
|
|
+
|
|
|
+- Android 真机连接 ADB
|
|
|
+- atx-agent 已安装于设备
|
|
|
+- DeepSeek API Key(环境变量 `DEEPSEEK_API_KEY` 或 `config.json`)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 注意事项
|
|
|
+
|
|
|
+- `yzm/tmp_captcha_test2.py` 含云码平台 Token
|