Files
aiData/Apps/XinDianTu/Opener.py
HuangHai 003ff3c342 'commit'
2026-01-12 13:48:14 +08:00

219 lines
8.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding=utf-8
import asyncio
import logging
import os
import time
import uuid
import uiautomator2 as u2
from Apps.XinDianTu.Kit import take_screenshot, detect_black_agree_button, detect_any_ad_close, \
detect_bottom_close_circle, is_background_dimmed
from Config.Config import TEMP_IMAGE_DIR
# pip install adbutils
# 配置日志输出,方便调试和监控
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("OpenXinDianTu")
async def check_and_close_ad(d):
"""
检测并关闭广告弹窗(优先使用计算机图形学方案,节省成本和时间)
"""
logger.info("开始检测广告弹窗...")
# 1. 拍摄截图
t1 = time.time()
image_uuid = str(uuid.uuid4())
# 使用相对路径: 基于当前脚本目录下的 Images 文件夹
base_dir = os.path.dirname(os.path.abspath(__file__))
save_dir = TEMP_IMAGE_DIR
screenshot_path = take_screenshot(d, image_uuid, save_dir=save_dir)
logger.info(f"Step [广告检测截图] 耗时: {time.time() - t1:.4f}s")
# 1.1 特征预检:检测背景蒙板
is_dimmed = is_background_dimmed(screenshot_path)
if is_dimmed:
logger.info("检测到背景变暗(蒙板),极大概率存在广告弹窗。")
# 2. 图形学检测方案 (Local CV)
t_cv = time.time()
# 方案 A: 检测黑色的"同意"按钮 (隐私协议)
# 这一步不需要模板,直接通过颜色和形状特征检测
agree_pos = detect_black_agree_button(screenshot_path, debug_dir=save_dir)
if agree_pos:
x, y = agree_pos
logger.info(f"通过图形学算法检测到隐私协议'同意'按钮: ({x}, {y})")
d.click(x, y)
logger.info(f"Step [图形学检测-同意按钮] 耗时: {time.time() - t_cv:.4f}s")
# 清理截图
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
return True
# 方案 B: 多模板匹配检测 "关闭(X)" 按钮 (支持多种广告样式)
template_dir = os.path.join(base_dir, "Templates")
if os.path.exists(template_dir):
logger.info(f"正在尝试多模板匹配关闭按钮: {template_dir}")
# 如果检测到蒙板,可以适当调低匹配阈值
match_threshold = 0.6 if is_dimmed else 0.7
close_pos = detect_ad_close_x_with_threshold(screenshot_path, template_dir, save_dir, match_threshold)
if close_pos:
x, y = close_pos
logger.info(f"通过多模板匹配检测到广告关闭按钮: ({x}, {y})")
d.click(x, y)
logger.info(f"Step [图形学检测-关闭按钮] 耗时: {time.time() - t_cv:.4f}s")
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
return True
# 方案 C: 底部圆形关闭按钮检测 (无模板,基于几何特征)
# 针对插屏广告底部中间的圆形关闭按钮
circle_pos = detect_bottom_close_circle(screenshot_path, debug_dir=save_dir)
if circle_pos:
x, y = circle_pos
logger.info(f"通过几何特征检测到底部圆形关闭按钮: ({x}, {y})")
d.click(x, y)
logger.info(f"Step [图形学检测-底部圆形按钮] 耗时: {time.time() - t_cv:.4f}s")
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
return True
logger.info(f"本地图形学检测完成,未发现已知广告。")
# 清理本地截图
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
return False
def detect_ad_close_x_with_threshold(screenshot_path, template_dir, debug_dir, threshold):
"""
带自定义阈值的多模板匹配
"""
for filename in os.listdir(template_dir):
if filename.startswith("ad_close") and filename.endswith(".jpg"):
template_path = os.path.join(template_dir, filename)
from Apps.XinDianTu.Kit import detect_ad_close_x
pos = detect_ad_close_x(screenshot_path, template_path, debug_dir=debug_dir, threshold=threshold)
if pos:
return pos
return None
async def open_mini_program():
"""
异步形式的进入微信小程序
"""
# 连接设备
d = u2.connect()
logger.info("执行进入小程序.")
# 启动微信 (强制停止后再启动,确保回到主页)
logger.info("启动微信...")
d.app_start("com.tencent.mm", stop=True)
await asyncio.sleep(5) # 给微信充足的启动时间
# 0. 确保在“微信”消息列表标签页
tab_chat = d(text="微信", resourceId="com.tencent.mm:id/f2s") # 常见底部标签 ID
if not tab_chat.exists:
tab_chat = d(text="微信")
if tab_chat.exists:
# 如果没选中(通常选中的文本颜色不同或有其他特征,这里直接点一下确保切换)
logger.info("点击底部‘微信’标签,确保在消息列表页.")
tab_chat.click()
await asyncio.sleep(1)
# 1. 点击搜索按钮(放大镜图标)
# 仅保留坐标点击逻辑
# window_size = d.window_size()
# w, h = window_size[0], window_size[1]
#
# # 精确相对坐标x=84%, y=8% (基于截图推算)
# click_x = int(w * 0.84)
# click_y = int(h * 0.08)
# logger.info(f"使用精确坐标点击搜索按钮: ({click_x}, {click_y})")
# d.click(click_x, click_y)
# 点击搜索按钮(放大镜图标)
logger.info("尝试查找并点击 '搜索按钮(放大镜图标)'...")
d.image.click("SearchButton.jpg")
logger.info("点击了搜索按钮(放大镜图标)")
# 点击后给予一定的加载时间
await asyncio.sleep(2)
# 2. 直接尝试输入内容 (既然已经看到了搜索界面,我们不再进行严格的特征校验)
logger.info("准备输入搜索内容: 新电途")
# 启用 u2 快速输入法 (使用更新的方法名)
# d.set_input_ime(True)
# 尝试点击搜索框位置以确保获取焦点 (通常在顶部居中偏左)
# search_bar_x, search_bar_y = int(w * 0.4), int(h * 0.08)
# d.click(search_bar_x, search_bar_y)
# await asyncio.sleep(1.5) # 稍微多等一会儿让输入法准备好
# 直接发送按键
try:
# 尝试先不使用 clear=True因为它在某些设备上会导致 ADB_KEYBOARD_CLEAR_TEXT 错误
# 如果需要清除文本,可以尝试全选+删除,或者假设搜索框是空的
logger.info("尝试输入文字: 新电途")
d.send_keys("新电途")
logger.info("文字输入指令已发送.")
except Exception as e:
logger.warning(f"直接 send_keys 失败: {e}")
try:
# 备选方案:尝试获取焦点元素并设置文本
logger.info("尝试使用 set_text 设置文本...")
d(focused=True).set_text("新电途")
logger.info("set_text 指令已发送.")
except Exception as e2:
logger.error(f"文字输入彻底失败: {e2}")
# 最后的尝试:切换回默认输入法(有时 FastInputIME 会卡住)
# d.set_fastinput_ime(False)
# d.send_keys("新电途")
await asyncio.sleep(3)
# # 兜底点击:点击搜索结果的第一项位置 (x=50%, y=18%)
# res_x, res_y = int(w * 0.5), int(h * 0.18)
# logger.info(f"尝试坐标点击第一项: ({res_x}, {res_y})")
# d.click(res_x, res_y)
# 点击符合新电途图标的小程序
logger.info("尝试查找并点击 '新电途小程序'...")
d.image.click("xdt.jpg")
logger.info("点击了新电途的小程序")
await asyncio.sleep(10)
# 进入小程序后,检查并处理广告
await check_and_close_ad(d)
return True
async def main():
success = await open_mini_program()
if success:
logger.info("任务执行成功.")
else:
logger.error("任务执行失败.")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("程序被用户中断.")
except Exception as e:
logger.exception(f"运行过程中出现异常: {e}")