4.5 KiB
4.5 KiB
艾特吉易充数据抓取流程说明文档
本文件详细记录了艾特吉易充(微信小程序)数据抓取爬虫的设计架构、抓取流程及关键技术实现。
1. 项目概述
本爬虫旨在自动化抓取“艾特吉易充”小程序中的充电场站信息,包括场站名称、地址、充电枪状态、实时价格以及 24 小时分时价格表。
2. 核心抓取流程
爬虫采用“列表 -> 详情 -> 价格 -> 返回 -> 列表”的闭环循环逻辑。
2.1 第一级:场站列表页
- 操作: 自动滚动列表,每屏截取一张大图。
- 识别方法:
- 图形学切片: 使用 OpenCV 识别图片中的白色卡片区域(几何卡片),确定点击位置。
- VL 模型分析: 使用
Qwen-VL模型识别本页所有场站的名称、基础价格和归一化坐标。 - 坐标匹配: 将几何卡片的像素坐标与 VL 模型的归一化坐标进行交叉比对,确定每个卡片对应的场站名称。
- 关键点: 通过几何卡片确保点击的准确性,通过 VL 模型确保数据的语义准确性。
2.2 第二级:场站详情页
- 进入: 点击列表页卡片。
- 操作: 截取详情页全图。
- 识别方法:
- 异步识别: 截图后立即启动
asyncio.create_task在后台调用 VL 模型提取地址和基础信息。 - 模板匹配: 使用 OpenCV 查找“分时价格”图标(
timePrice.jpg)的坐标。
- 异步识别: 截图后立即启动
- 关键点: UI 流程不等待 VL 模型返回,直接寻找入口进入下一级。
2.3 第三级:价格详情页
- 进入: 点击详情页中的分时价格入口。
- 操作: 截取价格列表,若列表过长则执行滑动截图,利用 MD5 校验判断是否滑动到底部。
- 识别方法:
- 异步识别: 截图完成后,UI 立即执行
d.press("back")返回列表页,所有截图交给后台任务处理。 - 数据规整: 后台任务调用 VL 模型识别各时段价格,并使用
ReadImageKit.expand_schedule_to_24h将不规则时段规整为 24 小时整点数据。
- 异步识别: 截图完成后,UI 立即执行
3. 关键技术点
3.1 异步并发设计 (Decoupling)
- 实现方式: 使用
AsyncOpenAI客户端和asyncio.create_task。 - 为什么要异步?:
- 提高吞吐量: VL 模型响应通常需要 3-8 秒。如果同步等待,爬取一个场站可能需要 20 秒以上。异步化后,手机 UI 可以在后台分析的同时继续操作。
- 用户体验: UI 操作(点击、滑动、返回)是连续的,不会因为网络请求波动而卡顿。
- 任务追踪: 在
Crawler.py中维护background_tasks列表,在每页结束时清理已完成任务,并在整个爬取结束时使用asyncio.gather等待残余任务。
3.2 场站去重策略
- 按名称去重: 仅依据列表显示的场站名称进行去重,不再使用前缀或模糊匹配。
- 处理规则:
- 名称先经
clean_station_name去掉尾部省略号与空格,例如AAABBB...→AAABBB; - 首次遇到该名称时处理并写入 Redis 键
crawled:aite:{name}; - 后续再遇到同名(包括省略号截断的同名)直接跳过,不再点击进入详情页。
- 名称先经
- 设计原因: 逻辑直白、符合业务预期,降低模糊匹配带来的误判风险。
- 一致性说明: 新电途项目采用同样的按名称去重策略以保持跨项目行为一致。
3.3 坐标系转换
- VL 坐标: 0-1000 的归一化坐标。
- UI 坐标: 屏幕像素坐标(如 1080x2400)。
- 转换公式:
px = val * screen_size / 1000。用于将 VL 识别的场站位置映射到屏幕实际可点击位置。
3.4 鲁棒性设计
- JSON 提取器:
ReadImageKit._extract_json采用递归和raw_decode策略,能够从 VL 模型输出的杂乱文本中精准提取 JSON 内容,容忍模型输出的说明文字。 - 图片读写:
Kit.py封装了支持中文路径的图片读写方法(np.fromfile/cv2.imencode),并增加了空文件校验,防止因并发读写导致的cv2崩溃。
4. 给研发人员的建议
- 调试模式: 开启
logging.INFO级别可以观察到 VL 模型的完整响应。 - 环境依赖: 确保
uiautomator2已正确连接 Android 设备。 - API 消耗: 异步调用会增加 API 并发压力,请确保使用的 API Key 具有足够的 QPS 限额。
- 内存管理: 后台任务会持有图片路径,处理完成后务必调用
os.remove清理临时图片。
文档更新日期:2026-01-12