/g, '\n');hljs.highlightElement(block);});}); 发现这玩意儿是用h5,因此普通控件js没什么用了,于是考虑ocr识别以及配合root权限点击。 我比较推荐安装com.daowuya.ppocrv3以及termux,以及在termux中安装python运行环境 然后从mt管理器中调用。 上面说到的几个APP以及具体使用方法可以ai去搜一下 下面我提供一下用于抖音极速版的刷金币脚本模板 #!/usr/bin/python3 import os import sys import time import requests import json import subprocess import logging import re import random # ====================================== # 金币点击脚本 - 应用检测修复版 v2.3 # 新增白名单机制支持多个包名 # ====================================== # 配置参数 KEYWORD_PRIORITY = [ "继续观看", "评价并收下金币", "领取奖励", # 最高优先级 "领取成功", # 第二优先级 "看广告赚金币" # 第三优先级 ] # 返回键触发关键词 BACK_KEYWORDS = [ "第1章", "加桌", "你要咨询", "确定关闭对话", "购物车", "应用权限" "问题", "客服", "再聊聊", "可详细", "正在为", "继续浏览", "减少提醒" "介绍", "政策", "页面由", "同意", "免费上门", "开发者", "好评率", "您的电话" ] # 白名单包名列表(支持多个应用) PACKAGE_WHITELIST = [ "com.ss.android.ugc.aweme", # 抖音极速版 "com.ss.android.ugc.aweme.lite", # 抖音普通版 "com.zhiliaoapp.musically", # TikTok国际版 "com.ss.android.ugc.aweme.lat", # 抖音海外版 "com.daowuya.ppocrv3" ] MAX_RETRY = 5 RETRY_DELAY = 2 SCREENSHOT_PATH = "/sdcard/screen.png" DEBUG_MODE = True # OCR服务配置 OCR_SERVER = "http://127.0.0.1:1919/detect" CONF_VALUE = 0.3 SCALE = 1 # 设置日志 logging.basicConfig( level=logging.DEBUG if DEBUG_MODE else logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("/sdcard/gold_clicker.log"), logging.StreamHandler(sys.stdout) ] ) logger = logging.getLogger("GoldClicker") def check_root_permission(): """检查是否拥有root权限""" try: result = subprocess.run( ["su", "-c", "echo root_check"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) return "root_check" in result.stdout.strip() except Exception as e: logger.error(f"Root权限检查失败: {e}") return False def get_current_package(): """获取当前前台应用包名(改进版)""" # 方法1: 使用dumpsys window windows try: result = subprocess.run( ["su", "-c", "dumpsys window windows"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) if result.returncode == 0: # 查找mCurrentFocus行 for line in result.stdout.splitlines(): if "mCurrentFocus" in line: # 多种可能的格式 match = re.search(r'u0 (\S+?)/', line) if match: return match.group(1) match = re.search(r'(\S+?)/\S+\s+\S+\s+mCurrentFocus', line) if match: return match.group(1) except Exception as e: logger.error(f"方法1失败: {e}") # 方法2: 使用dumpsys activity activities try: result = subprocess.run( ["su", "-c", "dumpsys activity activities"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) if result.returncode == 0: # 查找resumedActivity行 for line in result.stdout.splitlines(): if "resumedActivity" in line: match = re.search(r'(\S+?)/\S+', line) if match: return match.group(1) except Exception as e: logger.error(f"方法2失败: {e}") # 方法3: 使用dumpsys window displays try: result = subprocess.run( ["su", "-c", "dumpsys window displays"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) if result.returncode == 0: # 查找focusedApp行 for line in result.stdout.splitlines(): if "mFocusedApp" in line: match = re.search(r'ActivityRecord\{\w+ \w+ (\S+?)/', line) if match: return match.group(1) except Exception as e: logger.error(f"方法3失败: {e}") # 方法4: 使用dumpsys window policy try: result = subprocess.run( ["su", "-c", "dumpsys window policy"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) if result.returncode == 0: # 查找topFullscreenOpaqueWindow行 for line in result.stdout.splitlines(): if "topFullscreenOpaqueWindow" in line: match = re.search(r'Window\{\w+ \w+ (\S+?)/', line) if match: return match.group(1) except Exception as e: logger.error(f"方法4失败: {e}") logger.warning("无法获取当前应用包名") return None def is_target_application(): """检查当前是否为白名单应用""" current_package = get_current_package() logger.debug(f"当前应用包名: {current_package}") # 检查包名是否在白名单中 for allowed_package in PACKAGE_WHITELIST: # 完整匹配或前缀匹配 if current_package == allowed_package: return True # 处理可能变体 (例如: com.ss.android.ugc.aweme.lite.debug) if current_package and current_package.startswith(f"{allowed_package}."): return True return False def capture_screenshot(): """使用root权限截图""" try: # 删除旧截图 if os.path.exists(SCREENSHOT_PATH): os.remove(SCREENSHOT_PATH) # 执行截图命令 result = subprocess.run( ["su", "-c", f"screencap -p {SCREENSHOT_PATH}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) if result.returncode != 0: logger.error(f"截图失败: {result.stderr.decode('utf-8')}") return False # 检查截图文件是否存在 if not os.path.exists(SCREENSHOT_PATH) or os.path.getsize(SCREENSHOT_PATH) == 0: logger.error("截图文件未创建或为空") return False logger.info("截图成功") return True except Exception as e: logger.error(f"截图异常: {e}") return False def get_screen_dimensions(): """获取屏幕分辨率""" try: result = subprocess.run( ["su", "-c", "wm size"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) if result.returncode == 0: match = re.search(r'(\d+)x(\d+)', result.stdout) if match: return int(match.group(1)), int(match.group(2)) # 备选方法 result = subprocess.run( ["su", "-c", "dumpsys window displays | grep init="], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) if result.returncode == 0: match = re.search(r'init=(\d+)x(\d+)', result.stdout) if match: return int(match.group(1)), int(match.group(2)) logger.warning("无法获取屏幕分辨率,使用默认值 1080x1920") return 1080, 1920 except Exception as e: logger.error(f"获取分辨率失败: {e}") return 1080, 1920 def perform_click(x, y): """执行点击操作""" try: result = subprocess.run( ["su", "-c", f"input tap {x} {y}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) if result.returncode == 0: logger.info(f"点击成功: ({x}, {y})") return True logger.error(f"点击失败: {result.stderr.decode('utf-8')}") return False except Exception as e: logger.error(f"点击异常: {e}") return False def perform_back(): """模拟按下返回键""" try: result = subprocess.run( ["su", "-c", "input keyevent KEYCODE_BACK"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) if result.returncode == 0: logger.info("模拟返回键成功") return True logger.error(f"模拟返回键失败: {result.stderr.decode('utf-8')}") return False except Exception as e: logger.error(f"模拟返回键异常: {e}") return False def ocr_detect(): """使用OCR服务进行识别""" try: # 构造请求数据 payload = { "ocr_image": SCREENSHOT_PATH, "confValue": CONF_VALUE, "range": [], "scale": SCALE } headers = { "Content-Type": "application/json;charset=utf-8" } # 发送请求 response = requests.post( OCR_SERVER, json=payload, headers=headers, timeout=10 ) logger.debug(f"OCR响应状态码: {response.status_code}") logger.debug(f"OCR响应内容: {response.text[:200]}") if response.status_code != 200: logger.error(f"OCR请求失败: HTTP {response.status_code}") return None # 解析响应 try: return response.json() except json.JSONDecodeError: # 尝试提取JSON部分 start_idx = response.text.find('[') end_idx = response.text.rfind(']') + 1 if start_idx != -1 and end_idx != -1: json_str = response.text[start_idx:end_idx] return json.loads(json_str) logger.error("OCR响应解析失败") return None except requests.exceptions.RequestException as e: logger.error(f"OCR请求异常: {e}") return None except Exception as e: logger.error(f"OCR处理异常: {e}") return None def find_target_position(ocr_data): """根据关键词优先级查找目标位置""" if not ocr_data or not isinstance(ocr_data, list): logger.warning("OCR返回数据无效") return None # 按优先级搜索关键词 for keyword in KEYWORD_PRIORITY: best_position = None best_confidence = 0 for item in ocr_data: if not isinstance(item, dict) or "text" not in item or "center" not in item: continue text = item["text"].strip() confidence = item.get("confidence", 0) # 检查是否包含当前关键词 if keyword in text: logger.debug(f"找到关键词 '{keyword}' 在文本: '{text}'") # 选择置信度最高的位置 if confidence > best_confidence: best_confidence = confidence best_position = item["center"] # 如果找到当前关键词的目标位置 if best_position: logger.info(f"选择关键词 '{keyword}' 的目标位置") return best_position[0], best_position[1] return None def find_back_keyword(ocr_data): """查找返回关键词""" if not ocr_data or not isinstance(ocr_data, list): return False # 搜索所有返回关键词 back_detected = False for item in ocr_data: if not isinstance(item, dict) or "text" not in item: continue text = item["text"].strip() # 检查是否包含返回关键词 for keyword in BACK_KEYWORDS: if keyword in text: logger.info(f"检测到返回关键词: '{keyword}'") back_detected = True break return back_detected def try_preset_positions(screen_width, screen_height): """尝试预设位置点击""" logger.info("尝试预设位置点击") # 预设位置 positions = [ (0.5, 0.8), # 屏幕底部中心 (0.3, 0.75), # 左下区域 (0.7, 0.75), # 右下区域 (0.4, 0.85), # 底部偏左 (0.6, 0.85) # 底部偏右 ] # 随机打乱位置顺序 random.shuffle(positions) # 尝试所有预设位置 for i, (rel_x, rel_y) in enumerate(positions): x = int(screen_width * rel_x) y = int(screen_height * rel_y) logger.info(f"尝试位置 #{i+1}: ({x}, {y})") if perform_click(x, y): return True # 点击后等待 time.sleep(0.5) return False def main_loop(): """主循环函数""" logger.info("====== 金币点击循环启动 ======") # 获取屏幕尺寸 screen_width, screen_height = get_screen_dimensions() logger.info(f"屏幕分辨率: {screen_width}x{screen_height}") # 循环计数器 cycle_count = 0 success_count = 0 back_count = 0 # 主循环 while True: cycle_count += 1 logger.info(f"===== 循环 #{cycle_count} =====") # 检查当前应用是否在白名单中 if not is_target_application(): current_package = get_current_package() logger.warning(f"当前不在白名单应用内,检测到的包名: {current_package}") logger.info("白名单应用列表:") for package in PACKAGE_WHITELIST: logger.info(f" - {package}") logger.warning("脚本停止执行") break # 尝试次数计数器 attempt_success = False for attempt in range(1, MAX_RETRY + 1): logger.info(f"尝试 #{attempt}/{MAX_RETRY}") try: # 截图 if not capture_screenshot(): logger.warning("截图失败,跳过本次尝试") continue # OCR识别 logger.info("发送OCR请求...") ocr_data = ocr_detect() if not ocr_data: logger.warning("OCR识别失败,跳过本次尝试") continue # 检查返回关键词 if find_back_keyword(ocr_data): logger.info("检测到返回关键词,模拟返回键操作") if perform_back(): back_count += 1 attempt_success = True break else: logger.warning("模拟返回键失败") # 继续尝试常规操作 # 查找目标位置 logger.info("解析OCR结果...") position = find_target_position(ocr_data) if position: logger.info(f"找到目标位置: ({position[0]}, {position[1]})") if perform_click(position[0], position[1]): success_count += 1 attempt_success = True break else: logger.info("未找到目标文本") # 尝试预设位置 logger.info("尝试预设位置...") if try_preset_positions(screen_width, screen_height): success_count += 1 attempt_success = True break except Exception as e: logger.error(f"尝试 #{attempt} 发生异常: {e}") # 重试前等待 if attempt < MAX_RETRY: logger.info(f"等待 {RETRY_DELAY} 秒后重试...") time.sleep(RETRY_DELAY) # 清理截图 if os.path.exists(SCREENSHOT_PATH): os.remove(SCREENSHOT_PATH) # 循环间隔 if attempt_success: logger.info("等待5秒后进行下一轮检测...") time.sleep(5) else: logger.info("未找到目标,等待10秒后重试...") time.sleep(10) logger.info(f"====== 循环结束 ======") logger.info(f"总循环次数: {cycle_count}") logger.info(f"成功点击次数: {success_count}") logger.info(f"返回键触发次数: {back_count}") logger.info("====== 脚本结束 ======") def main(): logger.info("====== 金币点击脚本启动 ======") # 打印白名单应用列表 logger.info("白名单应用列表:") for package in PACKAGE_WHITELIST: logger.info(f" - {package}") # 检查root权限 if not check_root_permission(): logger.error("未检测到ROOT权限,脚本退出") return logger.info("ROOT权限检测通过") # 手动确认应用状态 current_package = get_current_package() logger.info(f"当前应用包名: {current_package}") # 检查当前应用是否在白名单中 in_whitelist = False for allowed_package in PACKAGE_WHITELIST: if current_package == allowed_package or (current_package and current_package.startswith(f"{allowed_package}.")): in_whitelist = True break if not in_whitelist: logger.warning(f"当前应用不在白名单中 ({current_package})") logger.info("请在白名单应用界面重新启动脚本") return # 进入主循环 main_loop() if __name__ == "__main__": main() 以下内容无法直接添加到帖子中,因为妖火有post拦截 自行手搓。
