 | |  |  |
京东每日签到领京豆脚本
- /*
- * ============================================================
- * AIWROK 京东每日签到领京豆脚本 - 无障碍AUTO模式
- * ============================================================
- * 功能: 自动打开京东APP,进入签到页面完成每日签到领京豆
- * 流程: 启动京东 → 进入"我的" → 点击签到入口 → 完成签到 →
- * 领取奖励 → 关闭弹窗 → 统计结果
- *
- * 技术特点:
- * 1. 纯无障碍节点解析,不依赖固定坐标
- * 2. 三级安全点击策略(节点直点→父节点→坐标兜底)
- * 3. 多路径签到入口查找(签到卡片→领京豆→签到按钮)
- * 4. 自动关闭广告弹窗和奖励弹窗
- * 5. 签到状态检测(已签到/未签到/签到成功)
- * 6. 支持定时循环执行(每日自动签到)
- * 7. 连续错误自动恢复与APP重启
- *
- * 兼容性: Rhino ES5 引擎 / AIWROK 安卓自动化平台
- * ============================================================
- */
- print.log("===== 京东每日签到领京豆(无障碍AUTO模式)=====");
- print.time();
- // ============================================================
- // 一、配置参数
- // ============================================================
- var config = {
- APP包名: "com.jingdong.app.mall", // 京东商城包名
- 页面加载等待秒: 5, // 页面切换等待秒数
- 操作间隔毫秒: 1000, // 操作间隔毫秒
- 最大重试次数: 3, // 单步操作最大重试次数
- 最大连续错误: 5, // 连续错误上限
- 调试模式: 'test', // 调试模式:'debug'=只输出页面节点摘要不签到, 'test'=执行完整签到流程, 'false'=正常模式
- 循环签到: false, // 是否循环签到(定时模式)
- 循环间隔分钟: 30, // 循环间隔分钟数
- // 签到入口关键词:京东签到入口在"我的"页面"领88豆"按钮
- // 实际可点击节点desc="领88豆京豆最高",text="领88豆"(不可点击,需父节点遍历)
- // 数字每天变化,用textIncludes匹配"豆"或desc匹配"领"+"豆"
- 首页签到入口: ["领京豆", "签到", "签到领豆", "领金币", "双签", "每日签到"],
- 我的页签到入口: ["每日签到", "领京豆", "签到", "签到领豆", "做任务领京豆", "签到中心", "领金币", "领88豆"]
- };
- // ============================================================
- // 二、初始化
- // ============================================================
- print.log("\n【初始化】设置无障碍详细模式...");
- auto.setDetailedModel();
- var 屏幕宽 = screen.getScreenWidth();
- var 屏幕高 = screen.getScreenHeight();
- print.log("屏幕尺寸:" + 屏幕宽 + " x " + 屏幕高);
- // ============================================================
- // 三、通用工具函数
- // ============================================================
- /**
- * 查找文字节点(同时搜索text和desc属性)
- * @param {Array} 关键词列表 - 关键词数组,依次尝试精确匹配和包含匹配
- * @return {Object} 找到的节点对象或null
- */
- function 查找文字节点(关键词列表) {
- try {
- var 节点集合 = auto.nodeSearch(2000);
- if (节点集合 == '' || 节点集合 == null) {
- return null;
- }
- for (var i = 0; i < 关键词列表.length; i++) {
- var 关键词 = 关键词列表[i];
- // 精确文本匹配
- var 文本过滤 = 节点集合.text(关键词);
- if (文本过滤 != '' && 文本过滤 != null && 文本过滤.count() > 0) {
- var 节点 = 文本过滤.getNode(0);
- if (节点 != '' && 节点 != null) {
- return 节点;
- }
- }
- // 包含文本匹配
- var 包含过滤 = 节点集合.textIncludes(关键词);
- if (包含过滤 != '' && 包含过滤 != null && 包含过滤.count() > 0) {
- var 节点2 = 包含过滤.getNode(0);
- if (节点2 != '' && 节点2 != null) {
- return 节点2;
- }
- }
- }
- // desc属性兜底搜索(京东签到按钮的可点击节点desc含"领88豆京豆最高"但text为空)
- for (var j = 0; j < 关键词列表.length; j++) {
- var 关键词2 = 关键词列表[j];
- var 节点 = 查找描述节点([关键词2]);
- if (节点) {
- return 节点;
- }
- }
- } catch (e) {
- print.log(" ⚠ 查找文字节点出错:" + e.message);
- }
- return null;
- }
- /**
- * 查找描述节点(通过desc属性搜索)
- * 遍历所有可点击节点,检查desc是否包含关键词
- * @param {Array} 关键词列表 - 关键词数组
- * @return {Object} 找到的节点对象或null
- */
- function 查找描述节点(关键词列表) {
- try {
- var 节点集合 = auto.nodeSearch(2000);
- if (节点集合 == '' || 节点集合 == null) {
- return null;
- }
- // 遍历所有节点检查desc
- var 总数 = 节点集合.count();
- for (var i = 0; i < 总数; i++) {
- var 节点 = 节点集合.getNode(i);
- if (节点 == '' || 节点 == null) {
- continue;
- }
- try {
- var desc = "" + 节点.getDesc();
- if (!desc || desc == "null" || desc.length == 0) {
- continue;
- }
- for (var j = 0; j < 关键词列表.length; j++) {
- var 关键词 = 关键词列表[j];
- if (desc.indexOf(关键词) >= 0) {
- return 节点;
- }
- }
- } catch (e) {
- }
- }
- } catch (e) {
- print.log(" ⚠ 查找描述节点出错:" + e.message);
- }
- return null;
- }
- /**
- * 查找desc中同时包含多个关键词的节点
- * 例如: 查找描述节点含多词(["领", "豆"]) 会匹配 desc="领88豆京豆最高"
- * @param {Array} 关键词列表 - 需要同时包含的关键词数组
- * @return {Object} 找到的节点对象或null
- */
- function 查找描述节点含多词(关键词列表) {
- try {
- var 节点集合 = auto.nodeSearch(2000);
- if (节点集合 == '' || 节点集合 == null) {
- return null;
- }
- var 总数 = 节点集合.count();
- for (var i = 0; i < 总数; i++) {
- var 节点 = 节点集合.getNode(i);
- if (节点 == '' || 节点 == null) {
- continue;
- }
- try {
- var desc = "" + 节点.getDesc();
- if (!desc || desc == "null" || desc.length == 0) {
- continue;
- }
- // 检查是否同时包含所有关键词
- var 全部匹配 = true;
- for (var j = 0; j < 关键词列表.length; j++) {
- if (desc.indexOf(关键词列表[j]) < 0) {
- 全部匹配 = false;
- break;
- }
- }
- if (全部匹配) {
- print.log(" [desc组合匹配] desc=[" + desc + "]");
- return 节点;
- }
- } catch (e) {
- }
- }
- } catch (e) {
- print.log(" ⚠ 查找描述节点含多词出错:" + e.message);
- }
- return null;
- }
- /**
- * 检查文字是否存在
- * @param {Array} 关键词列表 - 关键词数组
- * @return {boolean} 存在返回true
- */
- function 检查文字存在(关键词列表) {
- var 规则 = 关键词列表.join("||");
- return auto.findText(规则);
- }
- /**
- * 安全点击节点 - 三级降级策略
- * 策略: 1)节点可点击→直接点击 2)父/祖父节点可点击→点击父级 3)兜底→坐标点击
- * @param {Object} 节点 - 要点击的节点对象
- * @return {boolean} 点击成功返回true
- */
- function 安全点击节点(节点) {
- if (!节点 || 节点 == '' || 节点 == null) {
- return false;
- }
- // 第一级:节点本身可点击
- try {
- if (节点.isClickable && 节点.isClickable()) {
- 节点.click();
- return true;
- }
- } catch (e) {
- }
- // 第二级:向上查找可点击的父节点或祖父节点
- try {
- var 父节点 = 节点.getParent();
- if (父节点 != '' && 父节点 != null) {
- if (父节点.isClickable && 父节点.isClickable()) {
- 父节点.click();
- return true;
- }
- var 祖父节点 = 父节点.getParent();
- if (祖父节点 != '' && 祖父节点 != null) {
- if (祖父节点.isClickable && 祖父节点.isClickable()) {
- 祖父节点.click();
- return true;
- }
- }
- }
- } catch (e2) {
- }
- // 第三级:兜底方案,使用坐标点击
- try {
- var 中心 = 节点.getCenter();
- var x = 中心.x();
- var y = 中心.y();
- auto.clickPoint(x, y);
- return true;
- } catch (e3) {
- print.log(" ⚠ 安全点击全部失败:" + e3.message);
- return false;
- }
- }
- /**
- * 关闭弹窗 - 自动识别并关闭各种弹窗、广告、奖励提示
- * @return {boolean} 成功关闭返回true
- */
- function 关闭弹窗() {
- var 弹窗关键词 = [
- "我知道了", "知道了", "关闭", "暂不开启", "以后再说",
- "取消", "暂不更新", "下次再说", "拒绝", "不允许", "跳过",
- "稍后", "确定", "不了谢谢", "残忍拒绝", "收下", "好的"
- ];
- var 检测结果 = auto.findText(弹窗关键词.join("||"));
- if (!检测结果) {
- return false;
- }
- for (var i = 0; i < 弹窗关键词.length; i++) {
- var 关键词 = 弹窗关键词[i];
- var 节点 = 查找文字节点([关键词]);
- if (节点) {
- try {
- if (安全点击节点(节点)) {
- print.log(" ✓ 关闭弹窗:点击【" + 关键词 + "】");
- sleep.millisecond(毫秒 = config.操作间隔毫秒);
- return true;
- }
- } catch (e) {
- }
- }
- }
- // 尝试点击右上角关闭按钮(X图标)
- try {
- var 节点集合 = auto.nodeSearch(1000);
- if (节点集合 != '' && 节点集合 != null) {
- var 可点击 = 节点集合.clickable(true);
- if (可点击 != '' && 可点击 != null) {
- for (var j = 0; j < 可点击.count(); j++) {
- var n = 可点击.getNode(j);
- if (n) {
- var desc = "" + n.getDesc();
- if (desc.indexOf("关闭") >= 0 || desc.indexOf("close") >= 0 ||
- desc.indexOf("Close") >= 0) {
- n.click();
- print.log(" ✓ 点击关闭按钮(描述匹配)");
- sleep.millisecond(毫秒 = config.操作间隔毫秒);
- return true;
- }
- }
- }
- }
- }
- } catch (e) {
- }
- return false;
- }
- /**
- * 调试输出 - 输出当前页面节点摘要
- */
- function 输出页面摘要() {
- if (!config.调试模式) {
- return;
- }
- try {
- var 节点集合 = auto.nodeSearch(1000);
- if (节点集合 == '' || 节点集合 == null) {
- print.log(" [调试] 无节点");
- return;
- }
- var 总数 = 节点集合.count();
- print.log(" [调试] 页面节点总数:" + 总数);
- var 文本视图 = 节点集合.className("android.widget.TextView");
- if (文本视图 != '' && 文本视图 != null) {
- var 文本数 = Math.min(15, 文本视图.count());
- print.log(" [调试] 前" + 文本数 + "个文本节点:");
- for (var i = 0; i < 文本数; i++) {
- var 节点 = 文本视图.getNode(i);
- if (节点) {
- var 文本 = "";
- try { 文本 = "" + 节点.getText(); } catch (e) {}
- var 描述 = "";
- try { 描述 = "" + 节点.getDesc(); } catch (e) {}
- print.log(" " + (i + 1) + ". text=" + 文本 + " desc=" + 描述);
- }
- }
- }
- } catch (e) {
- print.log(" [调试] 输出页面摘要出错:" + e.message);
- }
- }
- /**
- * 等待页面加载并检测特征文字
- * @param {Array} 特征文字列表 - 页面特征文字
- * @param {number} 超时秒 - 超时秒数
- * @return {boolean} 检测到特征返回true
- */
- function 等待页面(特征文字列表, 超时秒) {
- var 超时毫秒 = 超时秒 * 1000;
- var 开始时间 = Date.now();
- while (Date.now() - 开始时间 < 超时毫秒) {
- if (检查文字存在(特征文字列表)) {
- return true;
- }
- sleep.millisecond(毫秒 = 500);
- }
- if (config.调试模式) {
- print.log(" [调试] 等待页面超时,未检测到:" + 特征文字列表.join(", "));
- 输出页面摘要();
- }
- return false;
- }
- // ============================================================
- // 四、核心功能函数
- // ============================================================
- /**
- * 启动京东APP
- * @return {boolean} 启动成功返回true
- */
- function 启动京东() {
- print.log("\n【启动】正在启动京东...");
- for (var i = 0; i < config.最大重试次数; i++) {
- try {
- app.openApp(config.APP包名);
- sleep.second(秒 = config.页面加载等待秒);
- 关闭弹窗();
- // 验证京东是否正常启动(首页特征文字)
- if (检查文字存在(["首页", "分类", "发现", "购物车", "我的"])) {
- print.log("✓ 京东启动成功");
- return true;
- }
- // 兜底验证:检查是否有搜索框
- if (auto.findText("搜索")) {
- print.log("✓ 京东启动成功(搜索框检测)");
- return true;
- }
- } catch (e) {
- print.log("⚠ 启动失败(第" + (i + 1) + "次):" + e.message);
- sleep.second(秒 = 3);
- }
- }
- print.log("✗ 京东启动失败");
- return false;
- }
- /**
- * 进入「我的」页面
- * @return {boolean} 成功进入返回true
- */
- function 进入我的页面() {
- print.log("\n【导航】进入「我的」页面...");
- // 方法1:通过文字查找「我的」标签
- var 我的节点 = 查找文字节点(["我的"]);
- if (我的节点) {
- if (安全点击节点(我的节点)) {
- print.log(" ✓ 已点击【我的】");
- sleep.second(秒 = 2);
- 关闭弹窗();
- // 验证是否进入我的页面
- if (等待页面(["我的订单", "我的钱包", "账号管理", "京豆", "会员"], 3)) {
- print.log("✓ 已进入「我的」页面");
- return true;
- }
- }
- }
- // 方法2:底部导航栏坐标兜底("我的"通常在底部最右侧)
- print.log(" ⚠ 文字查找失败,尝试坐标点击");
- auto.clickPercent(0.9, 0.97);
- sleep.second(秒 = 2);
- 关闭弹窗();
- if (等待页面(["我的订单", "我的钱包", "京豆", "会员"], 3)) {
- print.log("✓ 已进入「我的」页面(坐标点击)");
- return true;
- }
- print.log("✗ 无法进入「我的」页面");
- 输出页面摘要();
- return false;
- }
- /**
- * 输出页面完整节点摘要(调试用)
- * 无论调试模式是否开启都强制输出,用于排查节点问题
- */
- function 输出完整页面摘要(标签) {
- try {
- var 节点集合 = auto.nodeSearch(2000);
- if (节点集合 == '' || 节点集合 == null) {
- print.log(" 【页面摘要-" + 标签 + "】无节点");
- return;
- }
- var 总数 = 节点集合.count();
- print.log(" 【页面摘要-" + 标签 + "】节点总数:" + 总数);
- // 输出所有文本节点
- var 文本视图 = 节点集合.className("android.widget.TextView");
- if (文本视图 != '' && 文本视图 != null) {
- var 文本数 = 文本视图.count();
- print.log(" 【页面摘要-" + 标签 + "】文本节点数:" + 文本数);
- var 输出数 = Math.min(30, 文本数);
- for (var i = 0; i < 输出数; i++) {
- var 节点 = 文本视图.getNode(i);
- if (节点) {
- var 文本 = "";
- try { 文本 = "" + 节点.getText(); } catch (e) {}
- var 描述 = "";
- try { 描述 = "" + 节点.getDesc(); } catch (e) {}
- var 可点击 = "";
- try { 可点击 = 节点.isClickable() ? "可点击" : "不可点击"; } catch (e) {}
- print.log(" " + (i + 1) + ". text=[" + 文本 + "] desc=[" + 描述 + "] " + 可点击);
- }
- }
- }
- // 输出所有可点击节点
- var 可点击节点 = 节点集合.clickable(true);
- if (可点击节点 != '' && 可点击节点 != null) {
- var 可点击数 = 可点击节点.count();
- print.log(" 【页面摘要-" + 标签 + "】可点击节点数:" + 可点击数);
- var 输出数2 = Math.min(20, 可点击数);
- for (var j = 0; j < 输出数2; j++) {
- var cn = 可点击节点.getNode(j);
- if (cn) {
- var c文本 = "";
- try { c文本 = "" + cn.getText(); } catch (e) {}
- var c描述 = "";
- try { c描述 = "" + cn.getDesc(); } catch (e) {}
- var cID = "";
- try { cID = "" + cn.getID(); } catch (e) {}
- print.log(" 点击" + (j + 1) + ". text=[" + c文本 + "] desc=[" + c描述 + "] id=[" + cID + "]");
- }
- }
- }
- } catch (e) {
- print.log(" 【页面摘要】输出出错:" + e.message);
- }
- }
- /**
- * 在首页查找签到入口
- * 京东签到入口通常在首页顶部"领京豆"图标
- * @return {boolean} 成功进入签到页面返回true
- */
- function 首页查找签到() {
- print.log("\n【签到】在首页查找签到入口...");
- 关闭弹窗();
- sleep.millisecond(毫秒 = 500);
- // 调试模式下输出首页节点摘要
- if (config.调试模式 == 'debug') {
- print.log("\n >>> 首页节点摘要 <<<");
- 输出完整页面摘要("首页");
- }
- for (var i = 0; i < config.首页签到入口.length; i++) {
- var 关键词 = config.首页签到入口[i];
- var 节点 = 查找文字节点([关键词]);
- if (节点) {
- print.log(" ✓ 首页找到签到入口:【" + 关键词 + "】");
- if (安全点击节点(节点)) {
- sleep.second(秒 = config.页面加载等待秒);
- 关闭弹窗();
- // 验证是否进入签到页面
- if (检查文字存在(["签到", "立即签到", "签到成功", "已签到", "连签", "京豆", "领取"])) {
- print.log("✓ 已进入签到页面(首页入口)");
- return true;
- }
- sleep.second(秒 = 2);
- if (检查文字存在(["签到", "立即签到", "已签到", "连签"])) {
- print.log("✓ 已进入签到页面(延迟检测)");
- return true;
- }
- // 可能点击后进入了其他页面,返回首页重试
- print.log(" ⚠ 点击后未进入签到页面,返回重试");
- auto.back();
- sleep.second(秒 = 2);
- }
- }
- }
- // 首页顶部可能有签到图标但没有文字,尝试下滑一点找
- print.log(" 首页顶部未找到,下滑查找...");
- auto.swipPercent_v2(0.5, 0.3, 0.5, 0.6, 300, 100);
- sleep.second(秒 = 1);
- for (var j = 0; j < config.首页签到入口.length; j++) {
- var 关键词2 = config.首页签到入口[j];
- var 节点2 = 查找文字节点([关键词2]);
- if (节点2) {
- print.log(" ✓ 下滑后找到签到入口:【" + 关键词2 + "】");
- if (安全点击节点(节点2)) {
- sleep.second(秒 = config.页面加载等待秒);
- 关闭弹窗();
- if (检查文字存在(["签到", "立即签到", "已签到", "连签", "京豆"])) {
- print.log("✓ 已进入签到页面(下滑后)");
- return true;
- }
- }
- }
- }
- return false;
- }
- /**
- * 在「我的」页面查找签到入口
- * @return {boolean} 成功进入签到页面返回true
- */
- function 我的页面查找签到() {
- print.log("\n【签到】在「我的」页面查找签到入口...");
- if (config.调试模式 == 'debug') {
- print.log("\n >>> 我的页面节点摘要 <<<");
- 输出完整页面摘要("我的页面");
- }
- for (var 尝试次数 = 0; 尝试次数 < config.最大重试次数; 尝试次数++) {
- print.log(" 第" + (尝试次数 + 1) + "次在「我的」页面查找...");
- 关闭弹窗();
- sleep.millisecond(毫秒 = 500);
- // 方法1:遍历关键词列表查找(text + desc)
- for (var i = 0; i < config.我的页签到入口.length; i++) {
- var 关键词 = config.我的页签到入口[i];
- var 节点 = 查找文字节点([关键词]);
- if (节点) {
- print.log(" ✓ 「我的」页面找到签到入口:【" + 关键词 + "】");
- if (安全点击节点(节点)) {
- sleep.second(秒 = config.页面加载等待秒);
- 关闭弹窗();
- if (检查文字存在(["签到", "立即签到", "签到成功", "已签到", "连签", "京豆"])) {
- print.log("✓ 已进入签到页面(我的页入口)");
- return true;
- }
- sleep.second(秒 = 2);
- if (检查文字存在(["签到", "立即签到", "已签到", "连签"])) {
- print.log("✓ 已进入签到页面(延迟检测)");
- return true;
- }
- }
- }
- }
- // 方法2:desc组合搜索"领"+"豆"(解决"领88豆"数字每天变化的问题)
- // 京东签到按钮desc格式如"领88豆京豆最高",数字会变但"领"和"豆"不变
- if (尝试次数 == 0) {
- print.log(" 关键词未匹配,尝试desc组合搜索「领」+「豆」...");
- var 豆节点 = 查找描述节点含多词(["领", "豆"]);
- if (豆节点) {
- print.log(" ✓ desc组合搜索找到签到按钮");
- if (安全点击节点(豆节点)) {
- sleep.second(秒 = config.页面加载等待秒);
- 关闭弹窗();
- if (检查文字存在(["签到", "立即签到", "签到成功", "已签到", "连签", "京豆"])) {
- print.log("✓ 已进入签到页面(desc组合搜索)");
- return true;
- }
- }
- }
- }
- // 下滑查找
- if (尝试次数 < config.最大重试次数 - 1) {
- print.log(" 未找到签到入口,下滑查找...");
- auto.swipPercent_v2(0.5, 0.7, 0.5, 0.3, 400, 100);
- sleep.second(秒 = 1);
- }
- }
- return false;
- }
- /**
- * 查找并点击签到入口(主入口函数)
- * 查找顺序: 首页 → 我的页面 → 搜索兜底
- * @return {boolean} 成功进入签到页面返回true
- */
- function 进入签到页面() {
- print.log("\n【签到】开始查找签到入口...");
- auto.refresh();
- // 路径1:在首页直接查找签到入口(京东签到入口主要在首页顶部"领京豆")
- print.log("\n >> 路径1:首页查找");
- if (首页查找签到()) {
- return true;
- }
- // 路径2:进入「我的」页面查找
- print.log("\n >> 路径2:进入「我的」页面查找");
- if (进入我的页面()) {
- if (我的页面查找签到()) {
- return true;
- }
- // 没找到,返回首页
- auto.back();
- sleep.second(秒 = 2);
- }
- // 路径3:通过搜索进入签到页面
- print.log("\n >> 路径3:搜索进入签到");
- 回到首页();
- var 搜索节点 = 查找文字节点(["搜索", "搜索商品"]);
- if (搜索节点) {
- 安全点击节点(搜索节点);
- sleep.second(秒 = 2);
- try {
- input.sendString("京东签到领京豆");
- } catch (e) {
- print.log(" ⚠ 输入失败:" + e.message);
- }
- sleep.second(秒 = 2);
- // 点击搜索按钮
- auto.clickPercent(0.95, 0.05);
- sleep.second(秒 = 3);
- if (检查文字存在(["签到", "领京豆", "签到中心"])) {
- var 签到入口 = 查找文字节点(["签到", "领京豆", "签到中心"]);
- if (签到入口) {
- 安全点击节点(签到入口);
- sleep.second(秒 = config.页面加载等待秒);
- if (检查文字存在(["签到", "立即签到", "已签到"])) {
- print.log("✓ 通过搜索进入签到页面");
- return true;
- }
- }
- }
- }
- print.log("✗ 所有路径均无法找到签到入口");
- print.log("\n >>> 最终页面节点摘要 <<<");
- 输出完整页面摘要("最终页面");
- return false;
- }
- /**
- * 执行签到操作
- * 在签到页面中查找"签到"按钮并点击
- * @return {number} 0=签到成功, 1=今日已签到, 2=签到失败
- */
- function 执行签到() {
- print.log("\n【签到】执行签到操作...");
- 关闭弹窗();
- sleep.millisecond(毫秒 = 500);
- // 检查是否已经签到过
- if (检查文字存在(["已签到", "明天再来", "今日已签到", "已连续签到"])) {
- // 需要区分「已签到」按钮和「已签到」状态文字
- // 如果页面有「已签到」但没有「立即签到」/「签到」按钮,说明今天已签过
- if (!检查文字存在(["立即签到", "签到"]) && 检查文字存在(["已签到", "今日已签到"])) {
- print.log(" ℹ 今日已签到,无需重复操作");
- return 1;
- }
- }
- // 查找并点击"签到"按钮
- var 签到按钮关键词 = ["立即签到", "签到", "点击签到", "签到领取"];
- var 签到按钮 = 查找文字节点(签到按钮关键词);
- if (签到按钮) {
- print.log(" ✓ 找到签到按钮");
- if (安全点击节点(签到按钮)) {
- print.log(" ✓ 已点击签到按钮");
- sleep.second(秒 = 2);
- // 关闭签到后弹出的奖励弹窗
- 关闭弹窗();
- sleep.millisecond(毫秒 = 500);
- // 验证签到是否成功
- if (检查文字存在(["签到成功", "签到+", "获得", "领取成功", "已签到"])) {
- print.log(" 🎉 签到成功!");
- return 0;
- }
- // 再等待一下检测
- sleep.second(秒 = 2);
- 关闭弹窗();
- if (检查文字存在(["签到成功", "已签到", "明天见", "连签"])) {
- print.log(" 🎉 签到成功!(延迟检测)");
- return 0;
- }
- // 即使没有明确成功提示,如果没有"立即签到"按钮了也算成功
- if (!检查文字存在(["立即签到"])) {
- print.log(" 🎉 签到成功(按钮消失验证)");
- return 0;
- }
- }
- } else {
- print.log(" ⚠ 未找到签到按钮");
- 输出页面摘要();
- }
- // 二次尝试:下滑查找签到按钮
- print.log(" 下滑查找签到按钮...");
- auto.swipPercent_v2(0.5, 0.6, 0.5, 0.3, 300, 100);
- sleep.second(秒 = 1);
- 关闭弹窗();
- var 签到按钮2 = 查找文字节点(签到按钮关键词);
- if (签到按钮2) {
- print.log(" ✓ 下滑后找到签到按钮");
- if (安全点击节点(签到按钮2)) {
- sleep.second(秒 = 2);
- 关闭弹窗();
- if (检查文字存在(["签到成功", "已签到", "连签"])) {
- print.log(" 🎉 签到成功!(二次尝试)");
- return 0;
- }
- }
- }
- print.log(" ✗ 签到失败");
- return 2;
- }
- /**
- * 领取签到奖励
- * 签到后可能有额外奖励需要手动领取
- * @return {boolean} 领取成功返回true
- */
- function 领取奖励() {
- print.log("\n【奖励】检查并领取额外奖励...");
- sleep.second(秒 = 1);
- var 领取关键词 = ["领取", "立即领取", "收下", "领豆", "去领取", "点击领取"];
- var 领取节点 = 查找文字节点(领取关键词);
- if (领取节点) {
- print.log(" ✓ 找到奖励领取入口");
- if (安全点击节点(领取节点)) {
- sleep.second(秒 = 2);
- 关闭弹窗();
- print.log(" 🎁 已领取奖励");
- return true;
- }
- }
- print.log(" ℹ 暂无额外奖励可领取");
- return false;
- }
- /**
- * 回到京东首页
- * @return {boolean} 成功返回首页返回true
- */
- function 回到首页() {
- print.log("\n【返回】回到京东首页...");
- for (var i = 0; i < 3; i++) {
- auto.back();
- sleep.second(秒 = 1);
- if (检查文字存在(["首页", "分类", "购物车"])) {
- print.log("✓ 已回到首页");
- return true;
- }
- }
- // 兜底:回到桌面重新打开
- print.log(" 返回失败,重新打开京东...");
- auto.home();
- sleep.second(秒 = 2);
- if (启动京东()) {
- return true;
- }
- return false;
- }
- /**
- * 重启京东APP
- * @return {boolean} 重启成功返回true
- */
- function 重启京东() {
- print.log("✗ 需要重启京东...");
- try {
- app.resetApp(config.APP包名);
- sleep.second(秒 = 8);
- 关闭弹窗();
- print.log("✓ 京东重启成功");
- return true;
- } catch (e) {
- print.log("✗ 重启失败:" + e.message);
- return false;
- }
- }
- // ============================================================
- // 五、主流程
- // ============================================================
- print.log("\n【主流程】开始京东每日签到领京豆...\n");
- var 签到成功次数 = 0;
- var 签到跳过次数 = 0;
- var 签到失败次数 = 0;
- for (var 当前轮次 = 1; ; 当前轮次++) {
- print.log("\n========== 第 " + 当前轮次 + " 轮签到 ==========");
- var 连续错误 = 0;
- // ===== 步骤1:启动京东 =====
- print.log("\n【步骤1】启动京东APP...");
- if (!启动京东()) {
- print.log("✗ 启动失败,等待10秒后重试");
- sleep.second(秒 = 10);
- 签到失败次数++;
- continue;
- }
- sleep.second(秒 = 2);
- // ===== 调试模式:只输出页面摘要不签到 =====
- if (config.调试模式 == 'debug') {
- print.log("\n【调试模式】当前为debug模式,只输出页面节点摘要,不执行签到");
- print.log(" >>> 京东首页节点摘要 <<<");
- 输出完整页面摘要("京东首页");
- // 同时进入"我的"页面输出摘要
- print.log("\n >>> 进入「我的」页面输出摘要 <<<");
- if (进入我的页面()) {
- 输出完整页面摘要("我的页面");
- }
- print.log("\n【调试模式】请查看上方节点摘要,确认签到入口文字后:");
- print.log(" 1. 将关键词加入 config.首页签到入口 或 config.我的页签到入口");
- print.log(" 2. 将 config.调试模式 改为 'test' 验证完整签到流程");
- print.log(" 3. 验证通过后改为 'false' 进入正常模式");
- print.log("\n 完成时间:");
- print.time();
- break;
- }
- // ===== 步骤2:进入签到页面(首页→我的→搜索三路径) =====
- print.log("\n【步骤2】进入签到页面...");
- if (!进入签到页面()) {
- print.log("⚠ 进入签到页面失败");
- 连续错误++;
- if (连续错误 >= config.最大连续错误) {
- print.log("✗ 连续失败,重启京东...");
- 重启京东();
- 连续错误 = 0;
- continue;
- }
- continue;
- }
- // ===== 步骤3:执行签到 =====
- print.log("\n【步骤3】执行签到...");
- var 签到结果 = 执行签到();
- if (签到结果 == 0) {
- // 签到成功
- 签到成功次数++;
- print.log("✓ 签到成功!累计成功:" + 签到成功次数 + " 次");
- // 步骤4:领取额外奖励
- print.log("\n【步骤4】领取额外奖励...");
- 领取奖励();
- } else if (签到结果 == 1) {
- // 今日已签到
- 签到跳过次数++;
- print.log("ℹ 今日已签到过,跳过");
- } else {
- // 签到失败
- 签到失败次数++;
- print.log("✗ 签到失败");
- 输出页面摘要();
- }
- // ===== 步骤5:回到首页 =====
- print.log("\n【步骤5】回到首页...");
- 回到首页();
- // ===== 统计输出 =====
- print.log("\n【签到统计】");
- print.log("==========================================");
- print.log(" 签到成功:" + 签到成功次数 + " 次");
- print.log(" 已签跳过:" + 签到跳过次数 + " 次");
- print.log(" 签到失败:" + 签到失败次数 + " 次");
- print.log("==========================================");
- // 判断是否需要循环
- if (!config.循环签到) {
- print.log("\n✓ 单次签到模式,任务完成!");
- print.log(" 完成时间:");
- print.time();
- break;
- }
- // 循环模式:等待下一次签到
- var 等待秒 = config.循环间隔分钟 * 60;
- print.log("\n等待 " + config.循环间隔分钟 + " 分钟后进行下一次签到...");
- print.log(" 下次签到时间:约 " + new Date(Date.now() + 等待秒 * 1000).toLocaleString());
- for (var 倒计时 = 等待秒; 倒计时 > 0; 倒计时 -= 60) {
- var 显示分钟 = Math.floor(倒计时 / 60);
- print.log(" 剩余等待时间:约 " + 显示分钟 + " 分钟");
- sleep.second(秒 = Math.min(60, 倒计时));
- }
- }
- print.log("\n===== 京东每日签到领京豆完成 =====");
复制代码
| |  | |  |
|