七猫阅读赚钱自动刷框架
七猫阅读赚钱自动刷框架// =============================================================================
//通用阅读赚钱自动刷框架(七猫/番茄/快音等通用版)
//平台: AIWROK Android (ES5 严格语法)
//原理: 翻页阅读 + 看广告领奖励 + 防检测随机化
//特点: 每个App只需配置包名和翻页方向,框架自动处理其余逻辑
//
//支持App:
// 1. 七猫小说 com.kmxs.reader 翻页方向: horizontal(左右)
// 2. 番茄免费小说com.dragon.read 翻页方向: horizontal(左右)
// 3. 快音 com.kuaiyin.x 翻页方向: vertical(上下)
// 4. 抖音极速版 com.ss.android.ugc.aweme.lite 翻页方向: vertical(上下)
// 5. 自定义App (在APP表里添加即可)
//
//防检测策略:
// - 随机翻页间隔 (8~18秒,每个页面不同)
// - 随机停留时长 (在页面上多停一会再翻)
// - 随机滑动轨迹 (起点/终点都有微小偏移)
// - 随机滑动速度 (300~700ms之间)
// - 偶尔做"回翻"动作 (模拟真人回头看一下)
// - 偶尔做"点赞"动作 (模拟真人互动)
// - 每30分钟休息一次 (模拟真人离开)
// =============================================================================
print.log("╔══════════════════════════════════════════════╗");
print.log("║通用阅读赚钱自动刷框架 v1.0 ║");
print.log("║七猫/番茄/快音等通用 | 防检测随机化 ║");
print.log("╚══════════════════════════════════════════════╝");
print.time();
// =============================================================================
//第一部分:配置(只需改这里就能适配新App)
// =============================================================================
var CONFIG = {
// ====== 选择目标App (1~4) ======
目标App编号: 1,
// ====== 运行时长 ======
总运行分钟: 60, // 总共跑多久(分钟)
每隔N分钟休息: 30, // 每跑N分钟休息一次
休息秒数: 30, // 每次休息多少秒
// ====== 翻页参数(随机范围) ======
最小停留秒: 8, // 每页最少停留秒数
最大停留秒: 18, // 每页最多停留秒数
滑动时长最小毫秒: 300, // 滑动速度下限
滑动时长最大毫秒: 700, // 滑动速度上限
// ====== 防检测概率 ======
回翻概率: 0.08, // 8%概率做一次回翻动作
点赞概率: 0.05, // 5%概率做一次双击点赞
休息概率: 0.03, // 3%概率额外多停一会
// ====== 看广告领奖励 ======
看广告间隔分钟: 5, // 每N分钟去看一次广告领奖励
广告等待秒: 30, // 看广告等待秒数
// ====== 弹窗关键词 ======
弹窗关键词: [
"我知道了", "知道了", "暂不开启", "以后再说", "取消",
"暂不更新", "下次再说", "拒绝", "不允许", "跳过", "关闭",
"暂不领取", "稍后再说", "不再提示", "暂不签到", "继续阅读",
"暂不参加", "不了谢谢", "以后再领", "下次再领"
],
// ====== 阅读页特征文字(多个满足一个即认为在阅读页) ======
阅读页特征: ["目录", "上一章", "下一章", "书签", "设置", "夜间", "亮度", "字体"],
// ====== 模式 ======
优先使用Agent模式: true,
调试模式: true,
// ====== App表(添加新App只需在这里加一行) ======
App表: [
{
编号: 1,
名称: "七猫小说",
包名: "com.kmxs.reader",
翻页方向: "horizontal", // horizontal=左右翻页(小说), vertical=上下滑动(视频)
翻页起点X: 0.80, // 水平翻页: 从右侧往左滑 (起点X) 七猫阅读区0~1.0
翻页起点Y: 0.45, // 翻页起点Y 避开顶部菜单和底部进度条
翻页终点X: 0.20, // 水平翻页: 终点X
翻页终点Y: 0.45, // 翻页终点Y
福利页坐标: , // 底部"福利"Tab (实测XML: centerPercent=)
广告按钮文字: "看视频领金币", // 看广告按钮上的文字
启动后等待秒: 8,
阅读页检测文字: "目录", // 在阅读页能看到的文字(判断是否在阅读界面)
需要找书: true, // 七猫书架可能为空,需要去书城找书
书城Tab坐标: , // 底部"书城"Tab (实测XML: centerPercent=)
书架Tab坐标: , // 底部"书架"Tab (实测XML: centerPercent=)
点击中央呼出菜单: false // 七猫阅读页菜单是常驻的,不需要点中央呼出/隐藏
},
{
编号: 2,
名称: "番茄免费小说",
包名: "com.dragon.read",
翻页方向: "horizontal",
翻页起点X: 0.75,
翻页起点Y: 0.50,
翻页终点X: 0.25,
翻页终点Y: 0.50,
福利页坐标: ,
广告按钮文字: "看视频领金币",
启动后等待秒: 8,
阅读页检测文字: "目录",
需要找书: true,
书城Tab坐标: ,
书架Tab坐标: ,
点击中央呼出菜单: false
},
{
编号: 3,
名称: "快音",
包名: "com.kuaiyin.x",
翻页方向: "vertical", // 上下滑动(短视频类)
翻页起点X: 0.35, // 左侧滑动避开全屏按钮
翻页起点Y: 0.78,
翻页终点X: 0.35,
翻页终点Y: 0.22,
福利页坐标: ,
广告按钮文字: "看视频领金币",
启动后等待秒: 8,
阅读页检测文字: null, // 短视频类不需要检测阅读页
需要找书: false,
书城Tab坐标: null,
书架Tab坐标: null,
点击中央呼出菜单: false
},
{
编号: 4,
名称: "抖音极速版",
包名: "com.ss.android.ugc.aweme.lite",
翻页方向: "vertical",
翻页起点X: 0.35,
翻页起点Y: 0.78,
翻页终点X: 0.35,
翻页终点Y: 0.22,
福利页坐标: , // 右侧红包挂件
广告按钮文字: "看视频赚金币",
启动后等待秒: 8,
阅读页检测文字: null,
需要找书: false,
书城Tab坐标: null,
书架Tab坐标: null,
点击中央呼出菜单: false
}
]
};
// =============================================================================
//第二部分:引擎(Agent / 无碍 双模式自动切换)
// =============================================================================
var Engine = {
mode: "",
屏幕宽: 1080,
屏幕高: 2400,
init: function() {
print.log("\n【引擎初始化】检测模式...");
if (CONFIG.优先使用Agent模式) {
try { if (agent.isOpen()) { this.mode = "agent"; print.log("✓ Agent代理模式"); } } catch(e) {}
}
if (this.mode === "") {
try { if (typeof auto !== 'undefined') { this.mode = "auto"; print.log("✓ 无碍(Accessibility)模式"); } } catch(e) {}
}
if (this.mode === "") {
print.log("✗ 两个模式都不可用!请开启 Agent 或无障碍后再跑");
return false;
}
try {
if (this.mode === "agent") {
var raw = "" + agent.shell("wm size");
var m = raw.match(/(\d+)x(\d+)/);
this.屏幕宽 = m ? parseInt(m) : 1080;
this.屏幕高 = m ? parseInt(m) : 2400;
} else {
this.屏幕宽 = screen.getScreenWidth();
this.屏幕高 = screen.getScreenHeight();
}
} catch(e) {
this.屏幕宽 = 1080;
this.屏幕高 = 2400;
}
print.log("✓ 屏幕尺寸:" + this.屏幕宽 + " × " + this.屏幕高);
return true;
},
// 随机整数 [min, max)
randInt: function(min, max) {
return Math.floor(min + Math.random() * (max - min));
},
// 随机浮点 [0, 1)
randFloat: function() {
return Math.random();
},
// 随机偏移(在基准值上加微小随机量)
jitter: function(base, range) {
return base + (Math.random() - 0.5) * range;
},
// 翻页滑动(核心防检测:随机轨迹 + 随机速度 + 随机偏移)
nextPage: function(app) {
var x1, y1, x2, y2;
var dur = this.randInt(CONFIG.滑动时长最小毫秒, CONFIG.滑动时长最大毫秒);
if (app.翻页方向 === "horizontal") {
// 水平翻页:从右往左滑(下一页)
x1 = this.jitter(app.翻页起点X, 0.04);
y1 = this.jitter(app.翻页起点Y, 0.08);
x2 = this.jitter(app.翻页终点X, 0.04);
y2 = this.jitter(app.翻页终点Y, 0.08);
} else {
// 垂直翻页:从下往上滑(下一个视频)
x1 = this.jitter(app.翻页起点X, 0.06);
y1 = this.jitter(app.翻页起点Y, 0.04);
x2 = this.jitter(app.翻页终点X, 0.06);
y2 = this.jitter(app.翻页终点Y, 0.04);
}
// 确保坐标在合法范围
x1 = Math.max(0.02, Math.min(0.98, x1));
y1 = Math.max(0.02, Math.min(0.98, y1));
x2 = Math.max(0.02, Math.min(0.98, x2));
y2 = Math.max(0.02, Math.min(0.98, y2));
if (CONFIG.调试模式) {
print.log("→ 翻页 [" + app.翻页方向 + "] (" +
x1.toFixed(2) + "," + y1.toFixed(2) + ") → (" +
x2.toFixed(2) + "," + y2.toFixed(2) + ") " + dur + "ms");
}
try {
auto.swipPercent_v2(x1, y1, x2, y2, dur, 0);
} catch(e) {
// 兜底:用 agent.shell input swipe
try {
var px1 = Math.floor(this.屏幕宽 * x1);
var py1 = Math.floor(this.屏幕高 * y1);
var px2 = Math.floor(this.屏幕宽 * x2);
var py2 = Math.floor(this.屏幕高 * y2);
agent.shell("input swipe " + px1 + " " + py1 + " " + px2 + " " + py2 + " " + dur);
} catch(e2) {
print.log("⚠ 翻页失败: " + e2.message);
}
}
sleep.millisecond(this.randInt(300, 600));
// 小说类App翻页后可能弹出广告/弹窗,关闭它
if (app.点击中央呼出菜单) {
// 不再点中央隐藏菜单——七猫阅读页菜单是常驻的(上一章/下一章/目录在底部)
// 只关闭可能弹出的广告弹窗
this.closePopup();
}
},
// 回翻(模拟真人回头看一下上一页)
backPage: function(app) {
print.log("↩ 回翻一页(模拟真人回头)");
var x1, y1, x2, y2;
if (app.翻页方向 === "horizontal") {
// 水平回翻:从左往右滑(上一页)
x1 = this.jitter(app.翻页终点X, 0.04);
y1 = this.jitter(app.翻页起点Y, 0.08);
x2 = this.jitter(app.翻页起点X, 0.04);
y2 = this.jitter(app.翻页终点Y, 0.08);
} else {
// 垂直回翻:从上往下滑(上一个视频)
x1 = this.jitter(app.翻页终点X, 0.06);
y1 = this.jitter(app.翻页终点Y, 0.04);
x2 = this.jitter(app.翻页起点X, 0.06);
y2 = this.jitter(app.翻页起点Y, 0.04);
}
try {
auto.swipPercent_v2(x1, y1, x2, y2, this.randInt(400, 800), 0);
} catch(e) {
try {
var px1 = Math.floor(this.屏幕宽 * x1);
var py1 = Math.floor(this.屏幕高 * y1);
var px2 = Math.floor(this.屏幕宽 * x2);
var py2 = Math.floor(this.屏幕高 * y2);
agent.shell("input swipe " + px1 + " " + py1 + " " + px2 + " " + py2 + " 600");
} catch(e2) {}
}
sleep.millisecond(this.randInt(500, 1000));
},
// 双击点赞(模拟真人双击屏幕点赞)
doubleTap: function() {
print.log("❤ 双击点赞");
var x = this.jitter(0.5, 0.1);
var y = this.jitter(0.4, 0.1);
try {
auto.clickPercent(x, y);
sleep.millisecond(80);
auto.clickPercent(x, y);
} catch(e) {
try {
var px = Math.floor(this.屏幕宽 * x);
var py = Math.floor(this.屏幕高 * y);
agent.shell("input tap " + px + " " + py);
sleep.millisecond(80);
agent.shell("input tap " + px + " " + py);
} catch(e2) {}
}
sleep.millisecond(this.randInt(300, 600));
},
// 点击百分比坐标
clickPercent: function(px, py) {
try {
auto.clickPercent(px, py);
} catch(e) {
try {
agent.shell("input tap " + Math.floor(this.屏幕宽 * px) + " " + Math.floor(this.屏幕高 * py));
} catch(e2) {}
}
sleep.millisecond(this.randInt(600, 1000));
},
// 返回键
back: function() {
try {
if (this.mode === "agent") agent.shell("input keyevent 4");
else auto.back();
} catch(e) {}
sleep.second(1);
},
// Home键
home: function() {
try {
if (this.mode === "agent") agent.shell("input keyevent 3");
else auto.home();
} catch(e) {}
sleep.second(2);
},
// 启动 App
openApp: function(pkg, name) {
print.log("→ 启动:" + name + "(" + pkg + ")");
try {
app.resetApp(pkg);
print.log("✓ 启动APP:" + pkg);
return true;
} catch(e) {
print.log("⚠ app.resetApp 失败:" + e.message + ",尝试 monkey 兜底");
try {
agent.shell("monkey -p " + pkg + " -c android.intent.category.LAUNCHER 1");
return true;
} catch(e2) {
print.log("✗ 启动完全失败:" + e2.message);
return false;
}
}
},
// 关闭弹窗(全用 nodeSearch,不依赖 findText)
closePopup: function() {
var words = CONFIG.弹窗关键词;
try {
var nodes = auto.nodeSearch(1000);
if (!nodes) return false;
// 第一轮:精确匹配关键词
for (var i = 0; i < words.length; i++) {
try {
var filtered = nodes.text(words);
if (filtered && filtered.count() > 0) {
var node = filtered.getNode(0);
if (node && this.clickNode(node, words, "弹窗")) {
return true;
}
}
} catch(e2) {}
}
// 第二轮:模糊匹配关键词
for (var j = 0; j < words.length; j++) {
try {
var inc = nodes.textIncludes(words);
if (inc && inc.count() > 0) {
var node2 = inc.getNode(0);
if (node2 && this.clickNode(node2, words, "模糊弹窗")) {
return true;
}
}
} catch(e3) {}
}
// 第三轮:关闭悬浮广告/红包(通过节点ID,带包名前缀)
var pkg = "";
try { pkg = app.getTopPackName() || ""; } catch(e5) {}
var closeIds = [
(pkg ? pkg + ":id/" : "") + "close_red_packet",
(pkg ? pkg + ":id/" : "") + "close",
(pkg ? pkg + ":id/" : "") + "iv_close",
(pkg ? pkg + ":id/" : "") + "btn_close",
(pkg ? pkg + ":id/" : "") + "img_close",
"close_red_packet", "close", "iv_close", "btn_close", "img_close"
];
for (var k = 0; k < closeIds.length; k++) {
try {
var idNode = nodes.id(closeIds);
if (idNode && idNode.count() > 0) {
var node3 = idNode.getNode(0);
if (node3 && this.clickNode(node3, closeIds, "浮窗ID")) {
return true;
}
}
} catch(e4) {}
}
} catch(e) {
if (CONFIG.调试模式) print.log("- 弹窗检测异常: " + e.message);
}
return false;
},
// 查找并点击文字(精确→模糊→desc匹配,每个都先node.click再坐标fallback)
findAndClickText: function(keyword) {
try {
var nodes = auto.nodeSearch(2000);
if (!nodes) return false;
// 1. 精确匹配 text
try {
var filtered = nodes.text(keyword);
if (filtered && filtered.count() > 0) {
var node = filtered.getNode(0);
if (node && this.clickNode(node, keyword)) return true;
}
} catch(e1) {}
// 2. 模糊匹配 textIncludes
try {
var inc = nodes.textIncludes(keyword);
if (inc && inc.count() > 0) {
var node2 = inc.getNode(0);
if (node2 && this.clickNode(node2, keyword)) return true;
}
} catch(e2) {}
// 3. desc 精确匹配
try {
var descNode = nodes.desc(keyword);
if (descNode && descNode.count() > 0) {
var node3 = descNode.getNode(0);
if (node3 && this.clickNode(node3, keyword, "desc")) return true;
}
} catch(e3) {}
// 4. descIncludes 模糊匹配
try {
var descInc = nodes.descIncludes(keyword);
if (descInc && descInc.count() > 0) {
var node4 = descInc.getNode(0);
if (node4 && this.clickNode(node4, keyword, "desc模糊")) return true;
}
} catch(e4) {}
} catch(e) {
if (CONFIG.调试模式) print.log("- findAndClickText 异常: " + e.message);
}
return false;
},
// 点击节点(先尝试node.click(),失败则用坐标点击)
// AIWROK节点对象的 text/centerPercent/center 都是属性不是方法,用node.xxx不是node.xxx()
clickNode: function(node, label, matchType) {
matchType = matchType || "text";
try {
// 先尝试 node.click()
node.click();
print.log("✓ 点击" + matchType + "【" + label + "】(node.click)");
sleep.second(1);
return true;
} catch(e) {
// node.click() 失败,用坐标点击
try {
// 获取节点的 centerPercent 属性(注意:是属性不是方法)
var cp = null;
try { cp = node.centerPercent; } catch(e3) {}
if (cp) {
// centerPercent 格式 ""
var m = ("" + cp).match(/([\d.]+),([\d.]+)/);
if (m) {
var px = parseFloat(m);
var py = parseFloat(m);
this.clickPercent(px, py);
print.log("✓ 坐标点击" + matchType + "【" + label + "】(" + px + "," + py + ")");
return true;
}
}
// 兜底:用 center 属性
var ct = null;
try { ct = node.center; } catch(e4) {}
if (ct) {
var m2 = ("" + ct).match(/([\d.]+),([\d.]+)/);
if (m2) {
var cx = parseInt(m2);
var cy = parseInt(m2);
var px2 = cx / this.屏幕宽;
var py2 = cy / this.屏幕高;
this.clickPercent(px2, py2);
print.log("✓ 坐标点击" + matchType + "【" + label + "】(" + px2 + "," + py2 + ")");
return true;
}
}
// 兜底2:用 boundsPercent 属性
var bp = null;
try { bp = node.boundsPercent; } catch(e5) {}
if (bp) {
// boundsPercent 格式 "" 取中心
var m3 = ("" + bp).match(/\[([\d.]+),([\d.]+)\]\[([\d.]+),([\d.]+)\]/);
if (m3) {
var px3 = (parseFloat(m3) + parseFloat(m3)) / 2;
var py3 = (parseFloat(m3) + parseFloat(m3)) / 2;
this.clickPercent(px3, py3);
print.log("✓ 坐标点击" + matchType + "【" + label + "】(" + px3 + "," + py3 + ")");
return true;
}
}
} catch(e2) {
if (CONFIG.调试模式) print.log("- clickNode坐标fallback也失败: " + e2.message);
}
}
return false;
},
// 判断当前是否在阅读页/视频页
// 优先用阅读页特有的ID检测(最准确),文字特征只作为辅助
isOnReadingPage: function(app) {
if (!app.阅读页检测文字) return true; // 不需要检测的直接返回true
try {
var nodes = auto.nodeSearch(1500);
if (!nodes) return true; // nodeSearch失败时不阻断流程
// 1. 优先检测阅读页特有的ID(最准确,不会误判)
try {
var pkg = app.包名;
var ids = [
pkg + ":id/read_progress_layout",
pkg + ":id/book_directory",
pkg + ":id/btn_progress_left",
pkg + ":id/btn_progress_right",
pkg + ":id/read_blank_area",
pkg + ":id/read_page_container",
pkg + ":id/read_view",
pkg + ":id/tv_read_progress"
];
for (var j = 0; j < ids.length; j++) {
var idNode = nodes.id(ids);
if (idNode && idNode.count() > 0) return true;
}
} catch(e3) {}
// 2. 再用文字特征辅助判断(注意:要同时满足多个特征才算,避免误判)
var matchCount = 0;
var features = CONFIG.阅读页特征;
for (var i = 0; i < features.length; i++) {
try {
var matched = nodes.text(features);
if (matched && matched.count() > 0) {
matchCount++;
// 至少匹配2个阅读页特征文字才认定(减少误判)
if (matchCount >= 2) return true;
}
} catch(e) {}
}
// 3. 检测主检测文字 + 至少1个其他特征
try {
var main = nodes.text(app.阅读页检测文字);
if (main && main.count() > 0 && matchCount >= 1) return true;
} catch(e2) {}
return false;
} catch(e) {
return true; // 检测失败时假设在阅读页(不中断流程)
}
},
// 等待一段时间,期间周期性关闭弹窗
smartSleep: function(totalSec, intervalSec) {
var remain = totalSec;
while (remain > 0) {
var step = Math.min(intervalSec, remain);
sleep.second(step);
remain -= step;
this.closePopup();
}
}
};
// =============================================================================
//第三部分:阅读赚钱核心模块
// =============================================================================
var ReadingBot = {
app: null,
totalReads: 0, // 总翻页次数
totalAds: 0, // 看广告次数
totalPopups: 0, // 关弹窗次数
totalBackReads: 0, // 回翻次数
totalLikes: 0, // 点赞次数
totalRests: 0, // 休息次数
startTime: 0,
lastAdTime: 0, // 上次看广告的时间戳
run: function(app) {
this.app = app;
this.startTime = Date.now();
this.lastAdTime = this.startTime;
var maxMs = CONFIG.总运行分钟 * 60 * 1000;
print.log("\n╔══════════ 开始阅读赚钱 ══════════╗");
print.log("· App:" + app.名称 + "(" + app.包名 + ")");
print.log("· 翻页方向:" + app.翻页方向);
print.log("· 总时长:" + CONFIG.总运行分钟 + " 分钟");
print.log("· 停留:" + CONFIG.最小停留秒 + "~" + CONFIG.最大停留秒 + " 秒");
print.log("· 看广告间隔:" + CONFIG.看广告间隔分钟 + " 分钟");
print.log("╚══════════════════════════════════╝");
// 1. 启动App
print.log("\n[步骤1] 启动App...");
if (!Engine.openApp(app.包名, app.名称)) {
print.log("✗ 启动失败,退出");
return;
}
sleep.second(app.启动后等待秒 || 8);
Engine.closePopup();
// 2. 确保在阅读页/视频页
print.log("[步骤2] 确认阅读页面...");
if (app.需要找书 && !Engine.isOnReadingPage(app)) {
// 书架可能为空或不在阅读页,需要找一本书
print.log("→ 不在阅读页,需要找一本书进入阅读...");
this.findBookAndRead(app);
} else if (!Engine.isOnReadingPage(app)) {
// 不需要找书的App(如短视频),点中央进入
print.log("⚠ 不在阅读页,尝试点击屏幕中央进入...");
Engine.clickPercent(0.5, 0.5);
sleep.second(2);
Engine.closePopup();
}
if (Engine.isOnReadingPage(app)) {
print.log("✓ 已进入阅读页面");
} else {
print.log("⚠ 未确认在阅读页,但仍继续尝试翻页...");
}
// 3. 主循环
print.log("\n[步骤3] 开始自动翻页阅读...\n");
while ((Date.now() - this.startTime) < maxMs) {
var elapsedMin = ((Date.now() - this.startTime) / 60000).toFixed(1);
var remainMin = (CONFIG.总运行分钟 - elapsedMin).toFixed(1);
// === A. 检查是否该休息了 ===
if (CONFIG.每隔N分钟休息 > 0 &&
(Date.now() - this.startTime) > CONFIG.每隔N分钟 * 60 * 1000 * (this.totalRests + 1)) {
this.totalRests++;
var restSec = Engine.randInt(CONFIG.休息秒数, CONFIG.休息秒数 + 20);
print.log("\n[" + elapsedMin + "m] ☕ 第" + this.totalRests + "次休息 " + restSec + "秒");
Engine.smartSleep(restSec, 10);
print.log("✓ 休息完毕,继续阅读");
continue;
}
// === B. 检查是否该看广告了 ===
var sinceAd = Date.now() - this.lastAdTime;
if (sinceAd >= CONFIG.看广告间隔分钟 * 60 * 1000) {
this.watchAd();
this.lastAdTime = Date.now();
// 看完广告后确保回到阅读页
this.ensureReadingPage();
continue;
}
// === C. 随机停留看当前页 ===
var staySec = Engine.randInt(CONFIG.最小停留秒, CONFIG.最大停留秒);
// 小概率额外多停一会(模拟真人被内容吸引)
if (Engine.randFloat() < CONFIG.休息概率) {
staySec += Engine.randInt(10, 30);
if (CONFIG.调试模式) print.log("📖 这段内容不错,多看 " + (staySec - CONFIG.最小停留秒) + " 秒");
}
if (CONFIG.调试模式) {
print.log("[" + elapsedMin + "m] 第" + (this.totalReads + 1) + "页 停留" + staySec + "s (剩" + remainMin + "m)");
} else if ((this.totalReads % 10) === 0) {
print.log("[" + elapsedMin + "m] 已翻" + this.totalReads + "页 广告" + this.totalAds + "次 弹窗" + this.totalPopups + "次");
}
// 停留期间每5秒关一次弹窗
Engine.smartSleep(staySec, 5);
// === D. 随机防检测动作 ===
var dice = Engine.randFloat();
if (dice < CONFIG.回翻概率) {
// 小概率回翻一页
this.totalBackReads++;
Engine.backPage(this.app);
sleep.second(Engine.randInt(3, 6));
// 再翻回来
Engine.nextPage(this.app);
this.totalReads++;
} else if (dice < CONFIG.回翻概率 + CONFIG.点赞概率) {
// 小概率双击点赞
this.totalLikes++;
Engine.doubleTap();
} else {
// 正常翻页
Engine.nextPage(this.app);
this.totalReads++;
}
// 每20页关一次弹窗
if ((this.totalReads % 20) === 0) {
if (Engine.closePopup()) this.totalPopups++;
}
// 每50页确保在阅读页
if ((this.totalReads % 50) === 0) {
if (!Engine.isOnReadingPage(this.app)) {
print.log("⚠ 偏离阅读页,尝试恢复...");
Engine.back();
sleep.second(2);
if (!Engine.isOnReadingPage(this.app)) {
Engine.clickPercent(0.5, 0.5);
sleep.second(2);
}
Engine.closePopup();
}
}
}
// 4. 结束统计
var totalMin = ((Date.now() - this.startTime) / 60000).toFixed(1);
print.log("\n╔══════════ 阅读结束 ══════════╗");
print.log("║总翻页:" + this.totalReads + " 次");
print.log("║回翻次数:" + this.totalBackReads + " 次");
print.log("║点赞次数:" + this.totalLikes + " 次");
print.log("║看广告:" + this.totalAds + " 次");
print.log("║关弹窗:" + this.totalPopups + " 次");
print.log("║休息次数:" + this.totalRests + " 次");
print.log("║总时长:" + totalMin + " 分钟");
print.log("╚══════════════════════════════════╝");
Engine.home();
},
// 找一本书进入阅读页面(七猫/番茄等小说类App用)
// 基于实测XML节点结构编写,支持重试和多策略fallback
findBookAndRead: function(app) {
var maxRetry = 4; // 最多尝试4本书
var readBtns = ["开始阅读", "免费阅读", "立即阅读", "继续阅读", "免费读", "开始免费读"];
var addBtns = ["加入书架", "添加到书架", "收藏"];
for (var retry = 0; retry < maxRetry; retry++) {
print.log("\n[找书] === 第" + (retry + 1) + "/" + maxRetry + "轮 ===");
try {
// 0. 已在阅读页则直接返回
if (Engine.isOnReadingPage(app)) {
print.log("[找书] ✓ 已在阅读页,无需找书");
return true;
}
// 1. 确保在书城页(点书城Tab)
if (retry === 0 && app.书城Tab坐标) {
print.log("[找书] 1. 点击书城Tab...");
Engine.clickPercent(app.书城Tab坐标, app.书城Tab坐标);
sleep.second(3);
Engine.closePopup();
}
// 2. 点击一本书:优先用节点ID,兜底用坐标
var bookClicked = false;
var bookTitle = "";
// 策略A: 用 tv_book_title 节点点击(通过坐标fallback确保点击成功)
try {
var nodes = auto.nodeSearch(2000);
if (nodes) {
var titleNodes = nodes.id(app.包名 + ":id/tv_book_title");
if (titleNodes && titleNodes.count() > 0) {
var idx = Math.min(retry, titleNodes.count() - 1);
var titleNode = titleNodes.getNode(idx);
if (titleNode) {
// AIWROK节点text是属性不是方法
bookTitle = titleNode.text || ("书" + idx);
// tv_book_title 本身 clickable=false,用 clickNode 坐标fallback
if (Engine.clickNode(titleNode, bookTitle, "书名")) {
print.log("[找书] 2A. 点击书名[" + bookTitle + "] idx=" + idx);
bookClicked = true;
}
}
}
}
} catch(e2a) {
if (CONFIG.调试模式) print.log("[找书] 2A异常: " + e2a.message);
}
// 策略B: 用 rank_book_cover 节点点击
if (!bookClicked) {
try {
var nodes2 = auto.nodeSearch(2000);
if (nodes2) {
var coverIds = [
app.包名 + ":id/rank_book_cover",
"rank_book_cover",
"book_cover", "iv_cover", "item_book"
];
for (var ci = 0; ci < coverIds.length; ci++) {
try {
var coverNodes = nodes2.id(coverIds);
if (coverNodes && coverNodes.count() > 0) {
var cIdx = Math.min(retry, coverNodes.count() - 1);
var coverNode = coverNodes.getNode(cIdx);
if (coverNode && Engine.clickNode(coverNode, "封面" + cIdx, "书籍")) {
print.log("[找书] 2B. 点击封面 id=" + coverIds + " idx=" + cIdx);
bookClicked = true;
break;
}
}
} catch(e2b2) {}
}
}
} catch(e2b) {
if (CONFIG.调试模式) print.log("[找书] 2B异常: " + e2b.message);
}
}
// 策略C: 用坐标点击不同的书
// XML实测: 第1本书 center=, 第5本书 center=
// 垂直方向间隔约0.1187 (0.3932→0.512→0.6307→0.7495)
if (!bookClicked) {
var bookPositions = [
, , , ,
, , ,
];
var posIdx = retry % bookPositions.length;
print.log("[找书] 2C. 坐标点击推荐书 (" + bookPositions + "," + bookPositions + ")");
Engine.clickPercent(bookPositions, bookPositions);
bookClicked = true;
}
if (!bookClicked) {
print.log("[找书] ⚠ 无法找到可点击的书籍,重试...");
sleep.second(2);
continue;
}
// 3. 等待页面跳转,然后关闭弹窗
sleep.second(3);
Engine.closePopup();
// 4. 检查是否直接进入了阅读页(有些App会直接打开)
if (Engine.isOnReadingPage(app)) {
print.log("[找书] ✓ 直接进入阅读页");
return true;
}
// 5. 在书籍详情页找"开始阅读"按钮或"左滑开始阅读"提示
print.log("[找书] 3. 查找阅读入口...");
var found = false;
// 5a. 先检测是否有"左滑开始阅读"提示(七猫特有)
try {
var nodesTip = auto.nodeSearch(2000);
if (nodesTip) {
// 七猫详情页左滑进入阅读
var tipNode = nodesTip.id(app.包名 + ":id/tv_tip1");
if (tipNode && tipNode.count() > 0) {
print.log("[找书] 检测到【左滑开始阅读】提示,执行左滑手势...");
// 左滑:从右(0.8)到左(0.2),在屏幕中部
auto.swipPercent_v2(0.8, 0.5, 0.2, 0.5, 500, 0);
sleep.second(3);
Engine.closePopup();
if (Engine.isOnReadingPage(app)) {
print.log("[找书] ✓ 左滑后进入阅读页");
return true;
}
found = true; // 假设左滑成功了
}
}
} catch(e5a) {
if (CONFIG.调试模式) print.log("[找书] 5a左滑检测异常: " + e5a.message);
}
// 5b. 精确匹配阅读按钮文字
if (!found) {
for (var i = 0; i < readBtns.length; i++) {
if (Engine.findAndClickText(readBtns)) {
print.log("[找书] ✓ 点击了【" + readBtns + "】");
found = true;
break;
}
}
}
// 5c. 模糊匹配(七猫按钮可能含图标符号)
if (!found) {
var readKeywords = ["免费读", "开始读", "立即读", "阅读", "左滑"];
try {
var nodes3 = auto.nodeSearch(2000);
if (nodes3) {
for (var ri = 0; ri < readKeywords.length; ri++) {
try {
var inc = nodes3.textIncludes(readKeywords);
if (inc && inc.count() > 0) {
var rn = inc.getNode(0);
if (rn && Engine.clickNode(rn, readKeywords, "模糊阅读")) {
print.log("[找书] ✓ 模糊点击【" + readKeywords + "】");
found = true;
break;
}
}
} catch(e3) {}
}
}
} catch(e3b) {}
}
// 5d. 如果找到"左滑"文字但之前没处理,做左滑手势
if (!found) {
try {
var nodes4 = auto.nodeSearch(2000);
if (nodes4) {
var swipeTip = nodes4.textIncludes("左滑");
if (swipeTip && swipeTip.count() > 0) {
print.log("[找书] 检测到【左滑】文字,执行左滑手势...");
auto.swipPercent_v2(0.8, 0.5, 0.2, 0.5, 500, 0);
sleep.second(3);
Engine.closePopup();
found = true;
}
}
} catch(e5d) {}
}
// 5e. 兜底:如果以上都没找到,先尝试左滑(七猫最常见的入口),再尝试点底部
if (!found) {
print.log("[找书] 3b. 尝试左滑手势进入阅读...");
auto.swipPercent_v2(0.8, 0.5, 0.2, 0.5, 500, 0);
sleep.second(3);
Engine.closePopup();
if (Engine.isOnReadingPage(app)) {
print.log("[找书] ✓ 左滑后进入阅读页");
return true;
}
// 左滑不行,再试点底部常见按钮位置
print.log("[找书] 3c. 左滑未成功,点底部按钮位置...");
Engine.clickPercent(0.5, 0.88);
sleep.second(2);
if (!Engine.isOnReadingPage(app)) {
Engine.clickPercent(0.5, 0.80);
sleep.second(2);
}
}
// 6. 等待进入阅读页
sleep.second(3);
Engine.closePopup();
if (Engine.isOnReadingPage(app)) {
print.log("[找书] ✓ 已进入阅读页");
return true;
}
// 7. 可能需要先加入书架才能阅读
print.log("[找书] 4. 尝试加入书架...");
for (var j = 0; j < addBtns.length; j++) {
if (Engine.findAndClickText(addBtns)) {
print.log("[找书] ✓ 点击了【" + addBtns + "】");
sleep.second(2);
break;
}
}
// 8. 加入书架后再找阅读按钮
for (var k = 0; k < readBtns.length; k++) {
if (Engine.findAndClickText(readBtns)) {
print.log("[找书] ✓ 加入书架后点击了【" + readBtns + "】");
found = true;
break;
}
}
sleep.second(3);
Engine.closePopup();
if (Engine.isOnReadingPage(app)) {
print.log("[找书] ✓ 通过加入书架进入阅读页");
return true;
}
// 9. 本轮失败,返回书城重试
print.log("[找书] ⚠ 第" + (retry + 1) + "轮失败,返回书城重试...");
Engine.back();
sleep.second(2);
if (app.书城Tab坐标) {
Engine.clickPercent(app.书城Tab坐标, app.书城Tab坐标);
sleep.second(2);
}
} catch(e) {
print.log("[找书] 第" + (retry + 1) + "轮异常: " + e.message);
try { Engine.back(); sleep.second(2); } catch(e2) {}
}
}
print.log("[找书] ⚠ " + maxRetry + "轮尝试后仍未进入阅读页");
return false;
},
// 看广告领奖励
watchAd: function() {
this.totalAds++;
var elapsedMin = ((Date.now() - this.startTime) / 60000).toFixed(1);
print.log("\n[" + elapsedMin + "m] 📺 第" + this.totalAds + "次看广告领奖励");
try {
// 0. 先关闭可能挡住的浮窗
Engine.closePopup();
// 1. 点底部福利/任务Tab
print.log("[广告] 1. 点击福利Tab (" + this.app.福利页坐标 + "," + this.app.福利页坐标 + ")");
Engine.clickPercent(this.app.福利页坐标, this.app.福利页坐标);
sleep.second(3);
Engine.closePopup();
// 2. 找"看视频领金币"按钮并点击
print.log("[广告] 2. 查找【" + this.app.广告按钮文字 + "】");
var clicked = Engine.findAndClickText(this.app.广告按钮文字);
if (!clicked) {
// 尝试其他常见的看广告按钮文字
var adBtns = ["看视频", "看广告", "领金币", "领取", "看视频奖励", "立即领取"];
for (var i = 0; i < adBtns.length; i++) {
if (Engine.findAndClickText(adBtns)) {
clicked = true;
break;
}
}
}
if (!clicked) {
// 兜底:点屏幕中下方常见位置
print.log("[广告] 2b. 文字未找到,点常见位置 (0.5, 0.65)");
Engine.clickPercent(0.5, 0.65);
sleep.second(2);
}
// 3. 等待广告播放
print.log("[广告] 3. 等待广告播放 " + CONFIG.广告等待秒 + " 秒...");
Engine.smartSleep(CONFIG.广告等待秒, 5);
// 4. 关闭广告结束后的弹窗
print.log("[广告] 4. 关闭广告弹窗");
Engine.closePopup();
sleep.second(2);
// 5. 返回阅读页
print.log("[广告] 5. 返回阅读页");
Engine.back();
sleep.second(2);
Engine.closePopup();
} catch(e) {
print.log("⚠ 看广告异常: " + e.message);
// 尽力恢复
try { Engine.back(); sleep.second(2); } catch(e2) {}
try { Engine.closePopup(); } catch(e3) {}
}
},
// 确保回到阅读页
ensureReadingPage: function() {
if (Engine.isOnReadingPage(this.app)) return;
print.log("[恢复] 不在阅读页,尝试恢复...");
var tryCount = 0;
while (tryCount < 3) {
tryCount++;
Engine.back();
sleep.second(2);
Engine.closePopup();
if (Engine.isOnReadingPage(this.app)) {
print.log("[恢复] ✓ 已回到阅读页");
return;
}
// 点击屏幕中央尝试进入阅读
Engine.clickPercent(0.5, 0.5);
sleep.second(2);
if (Engine.isOnReadingPage(this.app)) {
print.log("[恢复] ✓ 已回到阅读页");
return;
}
}
// 多次返回都不在阅读页,可能回退到了书架/书城
// 尝试重新找书进入阅读
if (this.app.需要找书) {
print.log("[恢复] 返回到非阅读页,尝试重新找书...");
this.findBookAndRead(this.app);
if (Engine.isOnReadingPage(this.app)) {
print.log("[恢复] ✓ 重新进入阅读页");
return;
}
}
print.log("[恢复] ⚠ 多次尝试后仍未回到阅读页,继续翻页");
}
};
// =============================================================================
//第四部分:主入口
// =============================================================================
function main() {
if (!Engine.init()) {
print.log("✗ 引擎初始化失败,退出");
return;
}
// 获取目标App配置
var app = null;
for (var i = 0; i < CONFIG.App表.length; i++) {
if (CONFIG.App表.编号 === CONFIG.目标App编号) {
app = CONFIG.App表;
break;
}
}
if (!app) {
print.log("✗ 目标App编号 " + CONFIG.目标App编号 + " 不存在!");
print.log("可用编号:");
for (var j = 0; j < CONFIG.App表.length; j++) {
print.log(" " + CONFIG.App表.编号 + " = " + CONFIG.App表.名称 + "(" + CONFIG.App表.包名 + ")");
}
return;
}
// 先回桌面
Engine.home();
sleep.second(2);
// 运行
try {
ReadingBot.run(app);
} catch(e) {
print.log("⚠ 主流程异常: " + e.message);
print.log("尝试恢复...");
try { Engine.home(); } catch(e2) {}
}
print.log("\n✓ 脚本完成!");
print.timeEnd();
}
// 启动
main();
页:
[1]