# 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