This commit is contained in:
HuangHai
2026-01-13 15:02:32 +08:00
parent 8815cf603e
commit 4ddada009b
3 changed files with 77 additions and 74 deletions

View File

@@ -313,20 +313,17 @@ async def get_station_list(d, service, uploader, max_scrolls=MAX_SCROLLS):
loop.run_in_executor(None, uploader.upload_file, detail_object_key, detail_path)
# --- 抓取价格时段信息 ---
# 识别 "全部时段" 按钮
# 优先使用 VL 模型精准识别,避免几何特征误判导致退回微信
res = await ReadImageKit.find_all_time_button_coordinate(detail_path, device_info=device_info)
pos = (res.get("uia_center_x"), res.get("uia_center_y")) if res.get("uia_center_x") else None
entered_price_page = False
if pos and pos[0] is not None and pos[1] is not None:
ex, ey = pos
logger.info(f"找到 '全部时段' 按钮: ({ex}, {ey})")
# 【优化】使用模板匹配点击 "全部时段" 按钮,节省 VL Token 且更稳定
template_qbsd = os.path.join(os.path.dirname(__file__), "Template", "qbsd.jpg")
logger.info(f"尝试通过图片识别点击 '全部时段' 按钮: {template_qbsd}")
# 记录点击前的页面特征,用于验证是否成功进入三级页面
before_click_md5 = Kit.get_image_content_md5(detail_path)
d.click(ex, ey)
entered_price_page = False
try:
if d.image.click(template_qbsd, timeout=5.0):
logger.info("成功通过图片识别点击 '全部时段' 按钮")
await asyncio.sleep(1.5)
# 检查页面是否真的变化了
@@ -374,16 +371,14 @@ async def get_station_list(d, service, uploader, max_scrolls=MAX_SCROLLS):
should_back_to_list = True
else:
logger.warning(f"返回后状态未知 (ListMD5:{check_list_md5[:8]} vs {current_md5[:8]}, DetailMD5:{check_detail_md5[:8]} vs {before_click_md5[:8]})。")
logger.info("正在使用 VL 模型进一步确认当前页面状态...")
logger.info("使用图片识别进一步确认当前页面状态...")
# 使用 VL 模型检查当前页面是否存在 '全部时段' 按钮
# 如果存在,说明还在详情页,必须返回;如果不存在,说明可能已回到列表页
check_res = await ReadImageKit.find_all_time_button_coordinate(check_back_path, device_info=device_info)
if check_res and check_res.get("uia_center_x"):
logger.info("VL 确认当前仍处于详情页 (发现了'全部时段'按钮),执行返回。")
# 使用图片识别检查当前页面是否存在 '全部时段' 按钮
if d.image.match(template_qbsd):
logger.info("图片识别确认当前仍处于详情页 (发现了'全部时段'按钮),执行返回。")
should_back_to_list = True
else:
logger.info("VL 未发现'全部时段'按钮,判定已回到列表页(或非详情页),停止回退以防误退。")
logger.info("图片识别未发现'全部时段'按钮,判定已回到列表页(或非详情页),停止回退以防误退。")
should_back_to_list = False
# 使用完毕后再清理检查用的截图
@@ -395,7 +390,9 @@ async def get_station_list(d, service, uploader, max_scrolls=MAX_SCROLLS):
# 清理检查用的截图
if os.path.exists(after_click_path): os.remove(after_click_path)
else:
logger.info(f"场站 {station_name} 未发现 '全部时段' 按钮。")
logger.info(f"场站 {station_name} 通过图片识别未发现 '全部时段' 按钮。")
except Exception as e:
logger.error(f"通过图片识别点击 '全部时段' 按钮异常: {e}")
# 从二级页面返回 (仅当确实需要返回时)
if should_back_to_list:

View File

@@ -69,6 +69,12 @@
- 中文路径与空文件校验:`Kit.py` 统一图片读写与校验,避免并发读写导致崩溃。
- 异步任务清理:每页结束清理已完成任务,最终 `asyncio.gather` 等待残余任务,防止内存堆积。
### 3.7 模板匹配与设备一致性(关键建议)
- **识别原理**:使用 `d.image.click` 等基于 OpenCV 的图形学匹配方法时,本质上是像素级的特征对齐。
- **设备差异性**:不同手机的**屏幕分辨率**、**像素密度 (DPI)** 以及 **UI 缩放比例** 存在显著差异。同一张按钮截图(如 `qbsd.jpg`)在 A 设备上能匹配成功,但在 B 设备上可能因像素尺寸微调或渲染差异而识别失败。
- **一机一策**:在实际生产环境中,建议遵循“一机一议”原则。即针对不同的处理机(或同款但配置不同的手机),应分别采集对应的模板图片,确保匹配精度。
- **优化方案**:建议将模板文件按设备分辨率或型号分类存放(如 `Template/1080x2400/qbsd.jpg`),或者在无法匹配时使用视觉大模型(VL)作为兜底定位方案。
---
## 4. 数据持久化

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB