'commit'
This commit is contained in:
@@ -313,89 +313,86 @@ 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
|
||||
# 【优化】使用模板匹配点击 "全部时段" 按钮,节省 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)
|
||||
|
||||
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})")
|
||||
|
||||
# 记录点击前的页面特征,用于验证是否成功进入三级页面
|
||||
before_click_md5 = Kit.get_image_content_md5(detail_path)
|
||||
|
||||
d.click(ex, ey)
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
# 检查页面是否真的变化了
|
||||
after_click_path = take_screenshot(d, f"check_{detail_uuid}", save_dir=TEMP_IMAGE_DIR)
|
||||
after_click_md5 = Kit.get_image_content_md5(after_click_path)
|
||||
|
||||
if before_click_md5 != after_click_md5:
|
||||
entered_price_page = True
|
||||
price_screenshots = []
|
||||
for p_idx in range(1, 4):
|
||||
p_uuid = f"{hashlib.md5(station_name.encode('utf-8')).hexdigest()}_p_{p_idx}"
|
||||
p_path = take_screenshot(d, p_uuid, save_dir=TEMP_IMAGE_DIR)
|
||||
price_screenshots.append(p_path)
|
||||
if p_idx < 3:
|
||||
d.swipe_ext("up", scale=0.7)
|
||||
await asyncio.sleep(1.0)
|
||||
try:
|
||||
if d.image.click(template_qbsd, timeout=5.0):
|
||||
logger.info("成功通过图片识别点击 '全部时段' 按钮")
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
# 【异步优化】后台处理价格
|
||||
logger.info(f"已启动后台分析价格页: {station_name}")
|
||||
task_price = asyncio.create_task(analyze_prices_background(service, station_name, price_screenshots, device_info=device_info))
|
||||
background_tasks.append(task_price)
|
||||
|
||||
# 从三级页面返回二级页面
|
||||
d.press("back")
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
# 检查返回后的页面状态,防止多重返回导致退出到搜索页
|
||||
check_back_path = take_screenshot(d, f"check_back_{detail_uuid}", save_dir=TEMP_IMAGE_DIR)
|
||||
# 检查页面是否真的变化了
|
||||
after_click_path = take_screenshot(d, f"check_{detail_uuid}", save_dir=TEMP_IMAGE_DIR)
|
||||
after_click_md5 = Kit.get_image_content_md5(after_click_path)
|
||||
|
||||
# 1. 与列表页对比 (使用列表页的排除比例)
|
||||
check_list_md5 = Kit.get_image_content_md5(
|
||||
check_back_path,
|
||||
top_ratio=SAFE_EXCLUDE_RATIO,
|
||||
bottom_ratio=BOTTOM_SAFE_EXCLUDE_RATIO
|
||||
)
|
||||
|
||||
# 2. 与详情页对比 (使用默认排除比例,与 before_click_md5 一致)
|
||||
check_detail_md5 = Kit.get_image_content_md5(check_back_path)
|
||||
|
||||
if check_list_md5 == current_md5:
|
||||
logger.info("检测到已直接返回列表页,跳过后续返回操作。")
|
||||
should_back_to_list = False
|
||||
elif check_detail_md5 == before_click_md5:
|
||||
logger.info("检测到返回详情页,需执行第二次返回。")
|
||||
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 模型进一步确认当前页面状态...")
|
||||
if before_click_md5 != after_click_md5:
|
||||
entered_price_page = True
|
||||
price_screenshots = []
|
||||
for p_idx in range(1, 4):
|
||||
p_uuid = f"{hashlib.md5(station_name.encode('utf-8')).hexdigest()}_p_{p_idx}"
|
||||
p_path = take_screenshot(d, p_uuid, save_dir=TEMP_IMAGE_DIR)
|
||||
price_screenshots.append(p_path)
|
||||
if p_idx < 3:
|
||||
d.swipe_ext("up", scale=0.7)
|
||||
await asyncio.sleep(1.0)
|
||||
|
||||
# 使用 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 确认当前仍处于详情页 (发现了'全部时段'按钮),执行返回。")
|
||||
# 【异步优化】后台处理价格
|
||||
logger.info(f"已启动后台分析价格页: {station_name}")
|
||||
task_price = asyncio.create_task(analyze_prices_background(service, station_name, price_screenshots, device_info=device_info))
|
||||
background_tasks.append(task_price)
|
||||
|
||||
# 从三级页面返回二级页面
|
||||
d.press("back")
|
||||
await asyncio.sleep(0.5)
|
||||
|
||||
# 检查返回后的页面状态,防止多重返回导致退出到搜索页
|
||||
check_back_path = take_screenshot(d, f"check_back_{detail_uuid}", save_dir=TEMP_IMAGE_DIR)
|
||||
|
||||
# 1. 与列表页对比 (使用列表页的排除比例)
|
||||
check_list_md5 = Kit.get_image_content_md5(
|
||||
check_back_path,
|
||||
top_ratio=SAFE_EXCLUDE_RATIO,
|
||||
bottom_ratio=BOTTOM_SAFE_EXCLUDE_RATIO
|
||||
)
|
||||
|
||||
# 2. 与详情页对比 (使用默认排除比例,与 before_click_md5 一致)
|
||||
check_detail_md5 = Kit.get_image_content_md5(check_back_path)
|
||||
|
||||
if check_list_md5 == current_md5:
|
||||
logger.info("检测到已直接返回列表页,跳过后续返回操作。")
|
||||
should_back_to_list = False
|
||||
elif check_detail_md5 == before_click_md5:
|
||||
logger.info("检测到返回详情页,需执行第二次返回。")
|
||||
should_back_to_list = True
|
||||
else:
|
||||
logger.info("VL 未发现'全部时段'按钮,判定已回到列表页(或非详情页),停止回退以防误退。")
|
||||
should_back_to_list = False
|
||||
|
||||
# 使用完毕后再清理检查用的截图
|
||||
if os.path.exists(check_back_path): os.remove(check_back_path)
|
||||
logger.warning(f"返回后状态未知 (ListMD5:{check_list_md5[:8]} vs {current_md5[:8]}, DetailMD5:{check_detail_md5[:8]} vs {before_click_md5[:8]})。")
|
||||
logger.info("使用图片识别进一步确认当前页面状态...")
|
||||
|
||||
# 使用图片识别检查当前页面是否存在 '全部时段' 按钮
|
||||
if d.image.match(template_qbsd):
|
||||
logger.info("图片识别确认当前仍处于详情页 (发现了'全部时段'按钮),执行返回。")
|
||||
should_back_to_list = True
|
||||
else:
|
||||
logger.info("图片识别未发现'全部时段'按钮,判定已回到列表页(或非详情页),停止回退以防误退。")
|
||||
should_back_to_list = False
|
||||
|
||||
# 使用完毕后再清理检查用的截图
|
||||
if os.path.exists(check_back_path): os.remove(check_back_path)
|
||||
|
||||
else:
|
||||
logger.warning(f"点击 '{station_name}' 的 '全部时段' 按钮后页面无明显变化,跳过三级页面处理。")
|
||||
|
||||
# 清理检查用的截图
|
||||
if os.path.exists(after_click_path): os.remove(after_click_path)
|
||||
else:
|
||||
logger.warning(f"点击 '{station_name}' 的 '全部时段' 按钮后页面无明显变化,跳过三级页面处理。")
|
||||
|
||||
# 清理检查用的截图
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user