9.4 KiB
9.4 KiB
新电途微信小程序爬虫流程说明文档
本文档详细记录了“新电途”微信小程序爬虫的工作流程、技术细节、避坑指南及维护策略,旨在帮助开发人员快速理解系统架构,应对 UI 变更及设备更换等场景。
1. 项目概述
本项目是一个基于 Python + uiautomator2 + 视觉大模型 (VL) + 计算机图形学 (CV) 的自动化爬虫系统。 其核心目标是模拟用户操作,遍历“新电途”小程序的场站列表,识别场站信息(名称、价格、空闲桩数),并进入详情页抓取地址和分时电价。
核心技术栈
- 控制端:
uiautomator2(Android 自动化控制) - 视觉识别 (VL): 阿里云 Qwen-VL / DeepSeek (负责复杂的文字和语义提取)
- 计算机图形学 (CV): OpenCV (负责快速、低成本的广告检测、按钮定位、图像切片)
- 数据存储: Doris (MySQL 协议) + Redis (去重缓存) + Huawei OBS (图片存储)
2. 核心流程图解
graph TD
A[启动程序 (Y5_Full)] --> B[Step 0: 初始化服务 & 数据库]
B --> C[Step 1: 打开小程序 (Y2)]
C --> D{检测广告 (CV)}
D -- 有广告 --> E[点击关闭 (CV模板/几何)]
D -- 无广告 --> F[Step 2: 列表页爬取 (Y3)]
E --> F
F --> G[截图 & 切片 (CV)]
G --> H[上传图片至 OBS]
H --> I[调用 VL 模型解析场站列表]
I --> J{是否存在有效场站?}
J -- 是 --> K[遍历场站]
K --> L{是否已处理? (Redis)}
L -- 否 --> M[点击进入详情页]
M --> N[截图详情页 & 解析地址]
N --> O[抓取分时电价 (可选)]
O --> P[返回列表页]
P --> K
L -- 是 --> K
J -- 否 --> Q[下拉翻页]
Q --> F
Q -- 结束 --> R[Step 3: 坐标回填 (Y4)]
R --> S{Cookie 有效?}
S -- 是 --> T[高德 API 查询 & 更新 DB]
S -- 否 --> U[弹窗手动登录 (T2)]
U --> T
3. 详细步骤与技术实现
步骤 0: 初始化 (Y5_Full.py)
- 动作: 程序启动时,首先初始化
XinDianTuService并连接数据库。 - 目的: 确保后续爬取过程中数据库连接立即可用,避免在写入数据时才初始化导致的延迟或错误。
- 注意: 数据库连接采用单例模式或长连接,程序结束时需显式关闭。
步骤 1: 启动小程序 (Y2_OpenXinDianTu.py)
- 动作:
- 强制停止微信并重新启动,确保回到微信主页。
- 点击底部“微信”标签。
- 点击右上角“搜索”按钮(基于百分比坐标)。
- 输入“新电途”并点击搜索结果进入小程序。
- 坑点:
- 搜索入口坐标: 搜索按钮的位置在不同分辨率手机上略有差异,目前使用
w * 0.84,h * 0.08。如果更换手机,需检查此坐标。 - 输入法干扰:
uiautomator2的输入法有时会失效,代码中做了send_keys(clear=True)和直接输入的双重兜底。
- 搜索入口坐标: 搜索按钮的位置在不同分辨率手机上略有差异,目前使用
步骤 2: 列表页爬取 (Y3_StationList.py)
这是最核心的循环步骤(如需广告检测会自动调用 CV 模块):
- 截图:
d.screenshot()。 - 图像切片 (CV): 调用
Kit.crop_cards_from_image。- 利用行扫描算法,根据像素亮度和方差,识别出场站卡片之间的灰色分割线,将大图切割成一个个小卡片 (
_vl.jpg实际上是带绿框的整图,配合 JSON 元数据)。 - 优势: 极大降低了 VL 模型的理解难度,模型只需识别框内内容,不用自己找位置。
- 利用行扫描算法,根据像素亮度和方差,识别出场站卡片之间的灰色分割线,将大图切割成一个个小卡片 (
- VL 解析: 将图片上传 OBS,调用 VL 模型(Qwen/DeepSeek)。
- Prompt: 要求模型提取“场站名称”、“价格”、“枪数”、“距离”等。
- 坐标映射与安全检查:
- 模型返回的坐标会结合
device_info(设备真实宽高) 进行校验。 - Config.py:
SAFE_EXCLUDE_RATIO=0.20(顶部20%不点),BOTTOM_SAFE_EXCLUDE_RATIO=0.1(底部10%不点)。这解决了第一屏场站无法点击的问题。
- 模型返回的坐标会结合
步骤 3: 坐标回填 (Y4_Coord.py)
- 动作: 扫描数据库中
address不为空但coord_x/y为空的记录,调用高德地图 API 补全经纬度。 - 智能修复:
- 任务开始前会自动探测 Cookie 有效性。
- 如果 Cookie 失效,自动调用
T2_GetAmapCookie弹出浏览器窗口让用户手动登录。 - 登录完成后,程序自动保存新 Cookie 并继续执行回填任务,无需重启。
4. 技术选型指南:何时用 CV?何时用 VL?
| 场景 | 推荐技术 | 理由 |
|---|---|---|
| 广告关闭按钮 | CV (OpenCV) | 图标固定、形状简单(圆/叉)、要求毫秒级响应、零成本。 |
| 隐私协议按钮 | CV (OpenCV) | 颜色特征明显(黑色块)、位置固定。 |
| 场站卡片切分 | CV (行扫描) | 列表页结构规律,分割线特征稳定,CV 切分极其精准且快。 |
| 读取场站名称 | VL (大模型) | 字体多样、可能有干扰、OCR 传统方案容易错乱,VL 语义理解能力强。 |
| 读取价格/枪数 | VL (大模型) | 格式复杂("快 闲4/4"),VL 能直接提取结构化 JSON。 |
| 寻找"全部时段" | CV (几何特征) | 按钮只有文字没有边框,但左右空白特征明显,用边缘检测更可靠。 |
总结:
- 结构固定、特征简单、追求速度 -> 用 CV。
- 语义复杂、内容多变、容错率高 -> 用 VL。
5. 关键参数配置 (Config/Config.py)
| 参数名 | 当前值 | 说明 | 调整场景 |
|---|---|---|---|
SAFE_EXCLUDE_RATIO |
0.20 | 顶部安全排除比例。在此比例内的坐标不点击。 | 如果发现第一屏顶部的场站无法点击,调小此值。 |
BOTTOM_SAFE_EXCLUDE_RATIO |
0.1 | 底部安全排除比例。避开“扫码充电”等按钮。 | 如果频繁误触底部按钮,调大此值。 |
SCROLL_DISTANCE_RATIO |
0.3 | 翻页滑动幅度的比例。 | 如果翻页太快漏数据,调小;翻页太慢,调大。 |
MAX_CRAWL_DISTANCE |
50 | 最大爬取距离 (km)。 | 根据业务需求调整爬取范围。 |
VL_MODEL_NAME |
qwen3-vl-flash |
使用的视觉模型版本。 | 如果识别准确率下降,可尝试升级模型。 |
6. 避坑指南与设备更换
Q1: 更换手机需要注意什么?
- 分辨率差异:
- 代码大部分使用了相对坐标 (百分比),理论上兼容不同分辨率。
- 重点检查:
Y2_OpenXinDianTu.py中的搜索按钮点击坐标 (0.84, 0.08)。新手机可能刘海屏高度不同,导致 Y 轴偏移。
- 截图尺寸 vs 屏幕尺寸:
- 某些手机截图分辨率与
d.info获取的屏幕分辨率不一致(如 Retina 缩放)。 - 解决方案:
Y3_StationList.py中已包含自动检测逻辑:if img_w != w: device_info['width'] = img_w。一般无需手动修改。
- 某些手机截图分辨率与
Q2: 小程序 UI 大改版怎么办?
- 列表样式变更:
- 如果列表不再有明显的灰色分割线,
Kit.py的切片逻辑 (get_card_segments) 会失效。 - 应对: 修改
Kit.py,改用 VL 模型直接进行全图目标检测 (Object Detection),或者调整 CV 分割线的颜色阈值。
- 如果列表不再有明显的灰色分割线,
- 广告样式变更:
- 如果出现新广告,截图保存到
Tools/Templates,命名为ad_close_new.jpg即可,代码会自动加载。
- 如果出现新广告,截图保存到
Q3: 为什么有场站但没点进去?
- 被安全区拦截: 检查日志
safe exclude关键字。如果是误拦截,调整SAFE_EXCLUDE_RATIO。 - VL 识别失败: 检查
Images/目录下的_vl.jpg,看绿框是否框住了场站。如果没有,说明 CV 切片参数 (Kit.py) 需要调整(如row_mean阈值)。
7. 调试与单元测试
虽然本项目没有使用标准的 unittest 框架,但每个核心模块都设计了独立运行入口 (if __name__ == "__main__":),方便单步调试。
单元调试清单
| 功能模块 | 对应文件 | 调试方法 | 作用 |
|---|---|---|---|
| 广告检测 (CV) | Util/Kit.py |
无法直接运行,需编写临时脚本调用 detect_ad_close_x。建议在 Tools/T3_CropCards.py 中添加测试代码。 |
测试新广告模板是否生效。 |
| 切片逻辑 (CV) | Tools/T3_CropCards.py |
运行该脚本,会自动读取 Samples 目录下的图片进行切片测试。 |
调试列表分割线识别参数。 |
| 进入小程序 | Tools/Y2_OpenXinDianTu.py |
直接运行该文件。 | 测试微信启动和搜索流程。 |
| 列表爬取主循环 | Tools/Y3_StationList.py |
直接运行该文件 (需连接手机)。 | 独立测试爬取流程,不依赖外部调度。 |
| 全流程 | Tools/Y5_Full.py |
直接运行该文件。 | 生产环境模拟(含坐标回填)。 |
建议的开发习惯
- 遇到新 Bug: 先看日志 (
Tools/Logs/), 确定是哪一步卡住。 - 保留现场:
KEEP_SCREENSHOTS = True(在Y3_StationList.py),开启后会保留所有截图,方便事后分析。 - 单步验证: 如果是广告检测问题,把截图拿出来,写个几行的 Python 脚本单独调用
Kit.detect_ad_close_x进行验证,不要每次都跑全流程。