 | |  |  | 小红书养号脚本真实项目架
- /*
- ╔══════════════════════════════════════════════════════════╗
- ║ 案例1:小红书养号脚本真实项目架
- ║ ║
- ║ 核心架构: ║
- ║ 1. safe() 统一容错壳 — 绝不因为一个动作崩掉 ║
- ║ 2. pageHasText() 先预检 XML — 避开盲扫 nodeSearch 报错 ║
- ║ 3. findText() 节点精准定位 — 返回百分比坐标 ║
- ║ 4. clickText() 先预检再点击 — 最稳的套路 ║
- ║ 5. 三模式统一 if/else — 无障碍/HID/代理都能跑 ║
- ║ 6. pressBack() 返回键四通道兜底 — 绝不卡页面 ║
- ║ 7. humanSwipe() 人类化滑动 — 带随机抖动 ║
- ╚══════════════════════════════════════════════════════════╝
- */
- // ======================== 配置区 ========================
- var 模式选择 = '无障碍模式'; // '无障碍模式' | 'HID硬件模式' | '代理模式'
- var 小红书包名 = 'com.xingin.xhs';
- var 目标点赞数 = 50;
- var 目标评论数 = 5;
- var 收藏概率 = 0.3;
- var 关注概率 = 0.0; // 默认关闭关注!避免风控
- var 评论触发间隔 = 15; // 每 N 次点赞评论一次
- /*
- ⭐ 小红书详情页底部栏硬坐标(设备 1080×1920,已验证 ❤️ 可点)
-
- 布局:📝说点什么... ── 💬评论 ── ⭐收藏 ── ❤️点赞
- 位置: ~620px ~800px ~900px ~994px
- y = 1536 (屏高的 0.80)
-
- 按比例换算其他分辨率:
- ────────────────────────────────
- 设备分辨率 ❤️点赞 ⭐收藏 💬评论
- 1080×1920 (994,1536) (900,1536) (800,1536)
- ────────────────────────────────
- */
- var XHS_COORDS = {
- w: 1080, h: 1920, // 设计基准分辨率(按比例缩放)
- like: { xPct: 0.92, yPct: 0.80 }, // ❤️ 点赞 已验证!
- fav: { xPct: 0.83, yPct: 0.80 }, // ⭐ 收藏
- comment:{ xPct: 0.74, yPct: 0.80 } // 💬 评论
- };
- var 评论话术 = [
- '好好看呀!请问是用什么软件做的呀?',
- '求教程!这个效果太绝了 👏',
- '姐妹手速也太快了吧 😂',
- '码住码住!周末就试试',
- '收藏了!下次做一定用得上',
- ];
- /** 获取当前设备屏幕尺寸 */
- function getScreen() {
- var w = safe(function () { return screen.getScreenWidth(); }, '屏宽', XHS_COORDS.w);
- var h = safe(function () { return screen.getScreenHeight(); }, '屏高', XHS_COORDS.h);
- if (!w || w <= 0) w = XHS_COORDS.w;
- if (!h || h <= 0) h = XHS_COORDS.h;
- return [Math.round(w), Math.round(h)];
- }
- /** 按 XHS_COORDS 比例坐标 → 屏幕像素坐标 */
- function xhsXY(coord) {
- var s = getScreen();
- return [Math.round(s[0] * coord.xPct), Math.round(s[1] * coord.yPct)];
- }
- // ======================== 稳定运行库(复刻你的 05_特殊技巧合集)========================
- function llog(m) { try { printl(m); } catch (e) {} }
- function sleepMs(ms) { try { java.lang.Thread.sleep(ms); } catch (e) {} }
- function nowMs() { return java.lang.System.currentTimeMillis(); }
- function rnd(a, b) { try { return rand.randNumber(a, b); } catch (e) { return a + Math.floor(Math.random() * (b - a + 1)); } }
- function humanDelay(minMs, maxMs) { sleepMs(rnd(minMs, maxMs)); }
- /** 统一容错壳:任何可能报错的调用都包一层 */
- function safe(fn, tag, defVal) {
- try { return fn(); }
- catch (e) { llog('⚠ [' + tag + '] ' + String(e.message).substring(0, Math.min(40, String(e.message).length))); return defVal === undefined ? null : defVal; }
- }
- /** 重试执行器 */
- function retry(fn, times, gapMs, tag) {
- times = times || 3; gapMs = gapMs || 1500; tag = tag || '操作';
- for (var i = 1; i <= times; i++) {
- var ok = false;
- try { ok = !!fn(i); } catch (e) { llog('⚠ [' + tag + '] 第' + i + '次异常'); }
- if (ok) { llog('✔ [' + tag + '] 第' + i + '次成功'); return true; }
- llog('… [' + tag + '] 第' + i + '次未成功');
- if (i < times) sleepMs(gapMs);
- }
- llog('✘ [' + tag + '] ' + times + '次都没成功');
- return false;
- }
- /**
- * 预检:当前页面有没有这段文字
- * 真实生产源码写法(小红书/收藏加点赞.js 第16行):
- * if(auto.getXml().includes("打开App")){...}
- * Rhino ES5 下 Java String 自带 .includes(),直接用!
- */
- function pageHasText(text) {
- if (!text) return false;
- return safe(function () {
- var xml = auto.getXml();
- if (xml == null) return false;
- return xml.includes(text);
- }, 'pageHasText("' + text + '")', false);
- }
- /** 找文字节点并返回百分比坐标 [x%, y%] */
- function findText(text, timeoutMs) {
- var deadline = nowMs() + (timeoutMs || 8000);
- while (nowMs() < deadline) {
- if (pageHasText(text)) {
- var res = safe(function () {
- var nodes = auto.nodeSearch(1500).textIncludes(text);
- if (nodes == '' || nodes == null) return null;
- var node = nodes.getNode(0);
- var p = node.getCenterPoint();
- return [p.XPercent(), p.YPercent()];
- }, 'findText', null);
- if (res) return res;
- }
- sleepMs(500);
- }
- return null;
- }
- /** 点击文字(先预检再精准查,带超时) */
- function clickText(text, timeoutMs) {
- var xy = findText(text, timeoutMs);
- if (!xy) { llog('✘ 没找到: ' + text); return false; }
- safe(function () { auto.clickPercent(xy[0], xy[1]); }, 'clickPercent');
- llog('✔ 点击「' + text + '」@ ' + xy[0].toFixed(3) + ',' + xy[1].toFixed(3));
- return true;
- }
- /** 返回键四通道兜底 */
- function pressBack() {
- if (safe(function () { auto.pressBack(); return true; }, 'auto.pressBack', false)) { llog('← 返回(auto.pressBack)'); return true; }
- if (safe(function () { auto.back(); return true; }, 'auto.back', false)) { llog('← 返回(auto.back)'); return true; }
- if (safe(function () { device.pressBack(); return true; }, 'device.pressBack', false)) { llog('← 返回(device.pressBack)'); return true; }
- llog('✘ 所有返回通道都不可用');
- return false;
- }
- /**
- * 短视频/笔记快速翻页(一次到底)
- * 真实生产源码写法(小红书回粉.js 第0行):
- * auto.swipPercent(0.4931,0.2363,0.5069,0.7383)
- */
- function quickFlingUp() {
- safe(function () {
- auto.swipPercent(
- rnd(0.42, 0.55), rnd(0.82, 0.88), // 起点:底部中间
- rnd(0.42, 0.55), rnd(0.10, 0.18) // 终点:顶部中间
- );
- }, 'auto.swipPercent');
- llog('↕ 上滑换笔记...');
- }
- /** 三模式万能点击 */
- function 三模式点击(x, y, 标签) {
- if (x === null || x === undefined || isNaN(x) || y === null || y === undefined || isNaN(y)) { return false; }
- x = Math.round(Number(x)); y = Math.round(Number(y));
- if (模式选择 == '无障碍模式') { auto.clickPoint(x, y); }
- else if (模式选择 == 'HID硬件模式') { try { hid.click(x, y); } catch (e) { auto.clickPoint(x, y); } }
- else { try { agent.click(x, y); } catch (e) { auto.clickPoint(x, y); } }
- llog('🎯 ' + 标签 + ' (' + x + ',' + y + ')');
- return true;
- }
- /** 弹窗自动处理(关键词词库 → 先 XML 预检 → 再精准点) */
- function 处理弹窗() {
- var 弹窗关键词 = ['跳过', '关闭', '残忍离开', '稍后再说', '拒绝', '不同意', '以后再说', '始终允许', '确定'];
- for (var i = 0; i < 弹窗关键词.length; i++) {
- var kw = 弹窗关键词[i];
- if (pageHasText(kw)) {
- var xy = findText(kw, 1000);
- if (xy) {
- var w = safe(function () { return screen.getScreenWidth(); }, '屏宽', 1080);
- var h = safe(function () { return screen.getScreenHeight(); }, '屏高', 2400);
- 三模式点击(Math.round(xy[0] * w), Math.round(xy[1] * h), '关闭"' + kw + '"');
- humanDelay(1200, 1800);
- return true;
- }
- }
- }
- return false;
- }
- // ======================== 小红书详情页动作:全部硬坐标 ========================
- /** 返回发现页(必须验证真的回去了,不行再按) */
- function 返回发现页() {
- var s = getScreen();
- for (var i = 1; i <= 3; i++) {
- pressBack();
- humanDelay(800, 1200);
- // 验证:发现页应该有"发现"/"消息",没有"说点什么"
- var 在发现页 = pageHasText('发现') || pageHasText('消息');
- var 还在详情 = pageHasText('说点什么');
- if (在发现页 && !还在详情) {
- if (i > 1) llog(' ✅ 第' + i + '次返回成功');
- return true;
- }
- }
- llog(' 🚨 返回失败,强制退出(可能卡了)');
- // 实在不行,重启 App
- safe(function () { app.resetApp(小红书包名); }, 'resetApp');
- retry(function () { return pageHasText('发现') || pageHasText('消息'); }, 15, 1000, '重启后等首页');
- return false;
- }
- /** 点进笔记详情页(3 次重试) */
- function 点进详情页() {
- var s = getScreen();
- for (var attempt = 1; attempt <= 3; attempt++) {
- // 瀑布流双列笔记卡片位置:y 范围 550~1200(避开底部栏和顶部)
- var 列 = rnd(0, 1); // 0=左列 1=右列
- var x = 列 == 0 ? rnd(180, 360) : rnd(700, 900);
- x = Math.round(x * s[0] / 1080);
- var y = rnd(550, 1200);
- y = Math.round(y * s[1] / 1920);
- 三模式点击(x, y, '🖱️ 进笔记(第' + attempt + '次)');
- humanDelay(1500, 2200);
- if (pageHasText('说点什么')) return true;
- // 失败就返回再试
- if (attempt < 3) {
- pressBack();
- humanDelay(500, 700);
- }
- }
- return false;
- }
- /**
- * 小红书点赞
- * 真实生产源码写法(收藏加点赞.js 第33-35行):
- * var nodes = auto.nodeSearch().text("说点什么...").className("android.widget.TextView");
- * var node = nodes.getNode(0);
- * var success = node.nextNode().nextNode().nextNode().clickPoint();
- *
- * 优先用这个无障碍树节点链(不会因分辨率变化失效),失败再兜底硬坐标。
- */
- function 小红书点赞() {
- // === 方案 A:nodeSearch + nextNode 链(真实生产套路)===
- var nodeOk = safe(function () {
- var nodes = auto.nodeSearch().text("说点什么...").className("android.widget.TextView");
- if (!nodes) return null;
- var node = nodes.getNode(0);
- if (!node) return null;
- // 真实源码跳 3 次 = ❤️ 点赞按钮
- var likeBtn = node.nextNode().nextNode().nextNode();
- if (!likeBtn) return null;
- var ok = likeBtn.clickPoint();
- return ok;
- }, 'nodeSearch点赞', null);
-
- if (nodeOk === true) {
- llog(' ✅ node链点赞成功');
- humanDelay(400, 700);
- return true;
- }
-
- // === 方案 B:硬坐标兜底(已验证跑通)===
- var xy = xhsXY(XHS_COORDS.like);
- xy[0] += rnd(-8, 8); xy[1] += rnd(-8, 8);
- 三模式点击(xy[0], xy[1], '❤️ 点赞(硬坐标兜底)');
- humanDelay(400, 700);
- return true;
- }
- /**
- * 小红书收藏
- * 真实源码没有收藏的写法,推测 nextNode 多 1 次
- * 失败再兜底硬坐标
- */
- function 小红书收藏() {
- // === 方案 A:nodeSearch + nextNode 链 ===
- var nodeOk = safe(function () {
- var nodes = auto.nodeSearch().text("说点什么...").className("android.widget.TextView");
- if (!nodes) return null;
- var node = nodes.getNode(0);
- if (!node) return null;
- // ❤️ 跳3次 = node(3),⭐ 再跳1次 = node(4)
- var favBtn = node.nextNode().nextNode().nextNode().nextNode();
- if (!favBtn) return null;
- return favBtn.clickPoint();
- }, 'nodeSearch收藏', null);
-
- if (nodeOk === true) {
- llog(' ✅ node链收藏成功');
- humanDelay(300, 600);
- return true;
- }
-
- // === 方案 B:硬坐标兜底 ===
- var xy = xhsXY(XHS_COORDS.fav);
- xy[0] += rnd(-8, 8); xy[1] += rnd(-8, 8);
- 三模式点击(xy[0], xy[1], '⭐ 收藏(硬坐标兜底)');
- humanDelay(300, 600);
- return true;
- }
- // ======================== 小红书养号主循环 ========================
- function 小红书养号引擎() {
- llog('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
- llog(' 小红书养号脚本 v2 · 硬坐标版(已验证 ❤️ 坐标)');
- llog('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
- // 启动小红书
- llog('📱 启动小红书...');
- try { app.resetApp(小红书包名); } catch (e) { try { app.openApp(小红书包名); } catch (e2) {} }
-
- // 真实源码等待写法:sleep.waitString
- // 小红书首页必然有"发现"或"消息"
- var 启动成功 = safe(function () { sleep.waitString(字符='发现',毫秒=15000); return true; }, 'waitString发现', false)
- || safe(function () { sleep.waitString(字符='消息',毫秒=15000); return true; }, 'waitString消息', false);
-
- if (!启动成功) {
- retry(function () { return pageHasText('发现') || pageHasText('消息'); }, 30, 1000, '兜底等小红书启动');
- }
- humanDelay(1500, 2500);
- // 打印屏幕信息,方便校对坐标
- var s = getScreen();
- llog('📐 设备分辨率: ' + s[0] + ' × ' + s[1]);
- var likeXY = xhsXY(XHS_COORDS.like);
- var favXY = xhsXY(XHS_COORDS.fav);
- llog('🎯 ❤️坐标=(' + likeXY[0] + ',' + likeXY[1] + ') ⭐坐标=(' + favXY[0] + ',' + favXY[1] + ')');
- var 计数器 = { 点赞: 0, 收藏: 0, 跳过: 0, 失败: 0 };
- while (计数器.点赞 < 目标点赞数) {
- try {
- // ===== 弹窗 =====
- 处理弹窗();
- // ===== 1. 确认在发现页 =====
- if (!pageHasText('发现') && !pageHasText('消息')) {
- llog('⚠ 不在发现页,尝试返回...');
- 返回发现页();
- humanDelay(800, 1200);
- continue;
- }
- // ===== 2. 上滑换一条新笔记 =====
- llog(' 📜 上滑换笔记...');
- quickFlingUp();
- humanDelay(800, 1500);
- // ===== 3. 点击进笔记详情页(3 次重试)=====
- if (!点进详情页()) {
- 计数器.跳过++;
- llog(' ❌ 进详情页失败,跳过(累计 ' + 计数器.跳过 + ' 次)');
- if (计数器.跳过 >= 5) {
- llog('🚨 连续 5 次进详情页失败,脚本退出检查坐标');
- return;
- }
- continue;
- }
- // ===== 4. 点赞(硬坐标!)=====
- humanDelay(300, 600);
- 小红书点赞();
- 计数器.点赞++;
- 计数器.失败 = 0;
- 计数器.跳过 = 0;
- llog(' ❤️ 点赞 #' + 计数器.点赞 + '/' + 目标点赞数);
- humanDelay(300, 700);
- // ===== 5. 收藏(概率触发)=====
- if (Math.random() < 收藏概率) {
- 小红书收藏();
- 计数器.收藏++;
- llog(' ⭐ 收藏 #' + 计数器.收藏);
- }
- humanDelay(200, 500);
- // ===== 6. 返回到发现页(验证式返回)=====
- humanDelay(300, 600);
- 返回发现页();
- // ===== 7. 每 10 条休息一下 =====
- if (计数器.点赞 % 10 === 0) {
- var 休息秒 = rnd(5, 12);
- llog(' 🛏️ 已点赞 10 条,休息 ' + 休息秒 + 's 再继续...');
- humanDelay(休息秒 * 1000, 休息秒 * 1000);
- }
- } catch (e) {
- 计数器.失败++;
- llog('⚠️ 异常#' + 计数器.失败 + ': ' + String(e.message).substring(0, 50));
- humanDelay(1500, 3000);
- if (计数器.失败 >= 10) {
- llog('🚨 熔断!' + 计数器.点赞 + '❤️ ' + 计数器.收藏 + '⭐ ' + 计数器.跳过 + '跳过');
- return;
- }
- }
- }
- llog('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
- llog(' ✅ 完成!');
- llog(' ❤️ 点赞 ' + 计数器.点赞);
- llog(' ⭐ 收藏 ' + 计数器.收藏);
- llog(' ⏭️ 跳过 ' + 计数器.跳过);
- llog('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
- }
- 小红书养号引擎();
复制代码
| |  | |  |
|