news 2026/6/25 21:41:24

AutoJs大众点评免费抽自动报名脚本

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AutoJs大众点评免费抽自动报名脚本

前言:大众点评的「免费抽」活动每天上线大量免费商品,手速不够快很容易错过。本文介绍一款基于 AutoJs 的自动报名脚本,内置可视化 UI 面板,支持实时日志、轮次统计,文字定位 + 绝对坐标点击双重机制,稳定运行不漂移。

一、效果预览

脚本启动后自动循环执行以下流程:

找到「免费抽」按钮 → 进入详情页 → 点击「我要报名」→ 点击「确认报名」→ 返回列表 → 下滑 → 下一轮

UI 面板实时显示:

  • 🟢 运行状态(待机 / 运行中 / 已停止)
  • 已执行轮次
  • 成功报名次数
  • 带时间戳的滚动日志

二、环境要求

项目要求
运行环境AutoJs / AutoJs Pro(6.x+)
权限无障碍服务(必须开启)
分辨率本脚本坐标基于2670×1200屏幕标定 (Xiaomi 14)
前置操作启动前手动打开大众点评,停留在「免费抽」列表页

⚠️分辨率不同的设备必须重新标定坐标,详见第五节。


三、完整代码

"ui"; ui.layout( <vertical bg="#F2F2F7" h="*" w="*"> <horizontal bg="#E54B1C" padding="16 14" gravity="center_vertical" w="*"> <text text="🍴" textSize="22sp" marginRight="10"/> <vertical layout_weight="1"> <text text="大众点评 · 自动报名 v4" textSize="17sp" textColor="#FFFFFF" textStyle="bold"/> <text text="绝对坐标版" textSize="10sp" textColor="#FFCCBB"/> </vertical> </horizontal> <vertical bg="#FFFFFF" margin="12 12 12 0" padding="16 14" w="*"> <horizontal w="*" marginBottom="10"> <text text="当前状态" textSize="13sp" textColor="#999999" layout_weight="1"/> <text id="statusDot" text="●" textSize="14sp" textColor="#CCCCCC" marginRight="4"/> <text id="statusText" text="待机" textSize="14sp" textColor="#999999" textStyle="bold"/> </horizontal> <horizontal w="*" marginBottom="10"> <text text="已执行轮次" textSize="13sp" textColor="#999999" layout_weight="1"/> <text id="roundText" text="0" textSize="18sp" textColor="#E54B1C" textStyle="bold"/> <text text=" 轮" textSize="13sp" textColor="#999999"/> </horizontal> <horizontal w="*"> <text text="成功报名" textSize="13sp" textColor="#999999" layout_weight="1"/> <text id="successText" text="0" textSize="18sp" textColor="#4CAF50" textStyle="bold"/> <text text=" 次" textSize="13sp" textColor="#999999"/> </horizontal> </vertical> <horizontal margin="12 8 12 0" w="*"> <button id="startBtn" text="▶ 开始运行" bg="#E54B1C" textColor="#FFFFFF" layout_weight="1" margin="0 0 5 0" textSize="15sp" textStyle="bold"/> <button id="stopBtn" text="⏹ 停止" bg="#CCCCCC" textColor="#FFFFFF" layout_weight="1" margin="5 0 0 0" textSize="15sp" textStyle="bold" enabled="false"/> </horizontal> <button id="clearBtn" text="🗑 清空日志" bg="#FFFFFF" textColor="#999999" margin="12 6 12 0" w="*" textSize="13sp"/> <horizontal margin="14 8 0 4" gravity="center_vertical"> <text text="📋 运行日志" textSize="12sp" textColor="#AAAAAA" layout_weight="1"/> <text id="logCountText" text="0 条" textSize="11sp" textColor="#CCCCCC" marginRight="14"/> </horizontal> <ScrollView id="logScroll" bg="#FFFFFF" margin="12 0 12 12" padding="0" h="*" w="*"> <text id="logText" text="— 点击「开始运行」以启动自动化流程 —&#10;— 请确保已授予无障碍服务权限 —&#10;— 启动前请先手动停在「免费抽」列表页 —" textSize="11sp" textColor="#666666" padding="12" lineSpacingExtra="5dp"/> </ScrollView> </vertical> ); // ============================================================ // 配置区 // ============================================================ var SCREEN_BOTTOM_LIMIT = 2600; var running = false; var n = 0; var successes = 0; var logCount = 0; var worker = null; // ============================================================ // 日志工具 // ============================================================ function pad(v) { return ("0" + v).slice(-2); } function appendLog(msg) { var t = new Date(); var ts = pad(t.getHours()) + ":" + pad(t.getMinutes()) + ":" + pad(t.getSeconds()); var line = "[" + ts + "] " + msg; logCount++; ui.run(function () { var prev = ui.logText.getText().toString(); if (prev.indexOf("点击「开始运行」") >= 0) prev = ""; ui.logText.setText(prev + (prev ? "\n" : "") + line); ui.logCountText.setText(logCount + " 条"); ui.logScroll.post(function () { ui.logScroll.smoothScrollTo(0, ui.logText.getHeight() + 200); }); }); } function updateCounter() { ui.run(function () { ui.roundText.setText(String(n)); ui.successText.setText(String(successes)); }); } // ============================================================ // 工具函数 // ============================================================ // 下滑(向上滑动列表) function swipeUp() { var w = device.width, h = device.height; var startY = Math.round(h * 0.5); var endY = startY - 355; swipe(w / 2, startY, w / 2, endY, 2500); appendLog("📱 下滑完成"); } // 找「免费抽」并点击(文字定位 + 超出可视区域自动下滑重试) function tapFreeDraw() { while (running) { var btn = text("免费抽").findOne(500); if (btn) { var bounds = btn.bounds(); var btnY = bounds.top; if (btnY > SCREEN_BOTTOM_LIMIT) { appendLog("⚠️ 「免费抽」超出可视区域(Y:" + btnY + "),下滑重试"); swipeUp(); sleep(1000); continue; } var targetX = bounds.left - 200; var targetY = bounds.top; click(targetX, targetY); appendLog("✅ 点击「免费抽」(X:" + targetX + " Y:" + targetY + ")"); return true; } else { appendLog("⚠️ 未找到「免费抽」,下滑重试..."); swipeUp(); sleep(2000); } } return false; } // ============================================================ // 单轮流程 // ============================================================ function freeDraw() { // 1. 点击「免费抽」(文字定位) if (!tapFreeDraw()) return; // 2. 等详情页加载 sleep(1000); if (!running) return; // 3. 点击「我要报名」(绝对坐标) click(892, 2489); appendLog("✅ 点击「我要报名」(892, 2489)"); // 4. 等确认弹窗出现 sleep(1000); if (!running) return; // 5. 点击「确认报名」(绝对坐标) click(600, 2472); appendLog("✅ 点击「确认报名」(600, 2472)"); successes++; updateCounter(); appendLog("🎉 本轮报名完成"); // 6. 等待结果页 sleep(1000); // 7. 返回列表页 back(); sleep(500); // 8. 下滑准备下一轮 swipeUp(); sleep(500); } // ============================================================ // 按钮:开始 // ============================================================ ui.startBtn.on("click", function () { if (running) return; running = true; n = 0; successes = 0; logCount = 0; ui.startBtn.setEnabled(false); ui.stopBtn.setEnabled(true); ui.statusDot.setTextColor(colors.parseColor("#4CAF50")); ui.statusText.setTextColor(colors.parseColor("#4CAF50")); ui.statusText.setText("运行中"); ui.logText.setText(""); appendLog("▶ 自动化启动,申请无障碍权限中..."); worker = threads.start(function () { auto.waitFor(); appendLog("🔓 无障碍权限已就绪"); for (var i = 5; i > 0; i--) { appendLog("⏳ " + i + " 秒后开始,请切换到大众点评..."); sleep(1000); } appendLog("🚀 开始运行!"); while (running) { appendLog("─── 第 " + n + " 轮开始 ───"); updateCounter(); try { freeDraw(); } catch (e) { appendLog("❌ 异常:" + e); sleep(1000); } n++; } ui.run(function () { ui.startBtn.setEnabled(true); ui.stopBtn.setEnabled(false); ui.statusDot.setTextColor(colors.parseColor("#CCCCCC")); ui.statusText.setTextColor(colors.parseColor("#999999")); ui.statusText.setText("已停止"); }); appendLog("⏹ 已停止,共执行 " + n + " 轮,成功报名 " + successes + " 次"); }); }); // ============================================================ // 按钮:停止 // ============================================================ ui.stopBtn.on("click", function () { running = false; if (worker) { worker.interrupt(); worker = null; } ui.startBtn.setEnabled(true); ui.stopBtn.setEnabled(false); ui.statusDot.setTextColor(colors.parseColor("#CCCCCC")); ui.statusText.setTextColor(colors.parseColor("#999999")); ui.statusText.setText("已停止"); appendLog("⏹ 手动停止"); }); // ============================================================ // 按钮:清空日志 // ============================================================ ui.clearBtn.on("click", function () { logCount = 0; ui.logText.setText(""); ui.logCountText.setText("0 条"); });

四、代码解析

4.1 UI 布局

脚本顶部声明"ui"模式,整个界面用 AutoJs 的 XML 布局描述,无需额外 HTML:

"ui"; ui.layout(<vertical bg="#F2F2F7" h="*" w="*"> ... </vertical>);

界面分为四个区域:

  • 顶部标题栏:大众点评品牌色#E54B1C,展示脚本名和版本
  • 数据面板:实时显示状态、轮次、成功次数(三行horizontal布局)
  • 操作按钮:开始 / 停止 / 清空日志
  • 滚动日志区ScrollView包裹text,自动滚动到底部

4.2 双线程模型

UI 线程与自动化逻辑线程分离,是本脚本不卡顿的关键:

// 主线程:只负责 UI 交互 ui.startBtn.on("click", function () { // 启动子线程执行自动化 worker = threads.start(function () { auto.waitFor(); // 等待无障碍权限就绪 while (running) { freeDraw(); // 循环执行单轮流程 } }); });

所有 UI 更新必须通过ui.run()切回主线程执行,否则会报线程安全错误:

function appendLog(msg) { ui.run(function () { ui.logText.setText(...); // 更新日志文本 ui.logScroll.smoothScrollTo(0, ui.logText.getHeight() + 200); // 滚动到底 }); }

4.3 文字定位:找「免费抽」按钮

列表页的条目位置会随滑动变化,不能用固定坐标,因此用文字识别定位:

function tapFreeDraw() { while (running) { var btn = text("免费抽").findOne(500); // 查找文本节点,超时 500ms if (btn) { var bounds = btn.bounds(); var btnY = bounds.top; // 超出屏幕可视区域则先下滑 if (btnY > SCREEN_BOTTOM_LIMIT) { swipeUp(); sleep(1000); continue; } // 向左偏移 200px 点击,避开「免费抽」文字本身落在其他热区 var targetX = bounds.left - 200; click(targetX, btnY); return true; } else { // 未找到则下滑继续搜索 swipeUp(); sleep(2000); } } }

点击时对 X 坐标向左偏移 200px,目的是点到条目的封面图片区域而非文字区域,防止触发错误的点击响应。

SCREEN_BOTTOM_LIMIT = 2600是屏幕底部安全线,超过这个 Y 值说明按钮被底部导航栏遮挡,需要先滑动。


4.4 绝对坐标:「我要报名」和「确认报名」

详情页和确认弹窗的布局固定,直接用绝对坐标点击效率最高:

// 详情页底部「我要报名」按钮 click(892, 2489); // 确认弹窗「确认报名」按钮 click(600, 2472);

两次点击之间sleep(1000)等待弹窗动画完成,避免坐标还未渲染就点击失败。


4.5 下滑函数

每轮结束后需要下滑列表,让下一个「免费抽」条目出现:

function swipeUp() { var w = device.width, h = device.height; var startY = Math.round(h * 0.5); var endY = startY - 355; // 向上滑动 355px swipe(w / 2, startY, w / 2, endY, 2500); // 持续 2500ms,模拟慢滑 }

X 坐标取屏幕中线,Y 起点取屏幕中部,滑动距离 355px 经过实测是列表单条目高度的合适步进。持续时间 2500ms 模拟人工慢速滑动,减少被 App 检测到机械操作的风险。


4.6 异常捕获与 5 秒倒计时

// 启动后留 5 秒切换到大众点评 for (var i = 5; i > 0; i--) { appendLog("⏳ " + i + " 秒后开始,请切换到大众点评..."); sleep(1000); } // 每轮用 try-catch 包裹,单轮报错不影响整体循环 while (running) { try { freeDraw(); } catch (e) { appendLog("❌ 异常:" + e); sleep(1000); } n++; }

5 秒倒计时给用户留出手动切换 App 的时间。try-catch确保某一轮报错(如控件找不到、坐标点击无响应)不会导致整个脚本崩溃退出。


五、不同设备适配(重新标定坐标)

脚本中的绝对坐标基于2670×1200 分辨率设备标定,其他分辨率需修改以下三处:

第一步:确认自己的分辨率

在 AutoJs 控制台运行:

toast(device.width + " × " + device.height);

第二步:用布局分析工具拿坐标

AutoJs 自带「布局范围分析」工具(悬浮窗 → 布局分析),打开大众点评「我要报名」页面,点击对应按钮查看其坐标,替换代码中的两行:

click(892, 2489); // 改为「我要报名」按钮的实际 X, Y click(600, 2472); // 改为「确认报名」按钮的实际 X, Y

第三步:调整屏幕底部安全线

var SCREEN_BOTTOM_LIMIT = 2600; // 改为 device.height - 70 左右

第四步:调整下滑距离

var endY = startY - 355; // 355 是单条目高度,按实际屏幕比例等比缩放

六、使用步骤

1. 将代码保存为 .js 文件,导入 AutoJs 2. 打开手机「无障碍服务」,授权 AutoJs 3. 打开大众点评,进入「免费抽」列表页 4. 切回 AutoJs,点击「▶ 开始运行」 5. 5 秒倒计时内切换回大众点评 6. 脚本自动循环,可随时点「⏹ 停止」终止

七、常见问题

Q:脚本启动后什么都没发生?
A:检查无障碍服务是否已授权给 AutoJs,设置路径:手机设置 → 无障碍 → AutoJs → 开启。

Q:日志显示「未找到『免费抽』」一直循环?
A:确认已停留在大众点评「免费抽」列表页,而不是首页或其他 Tab。

Q:点击了「免费抽」但进入的是错误的详情页?
A:X 坐标偏移量bounds.left - 200可能需要根据你的布局调整,适当增减偏移值。

Q:「我要报名」点击无效,弹窗没出现?
A:坐标与你的分辨率不符,按第五节重新标定坐标。

Q:报名成功数一直增加但实际没中?
A:脚本只负责完成点击报名流程,中奖与否由平台抽签决定,成功报名不等于中奖。


八、总结

本脚本的设计思路:

  • 文字定位解决列表页按钮位置不固定的问题,找到就点、找不到就滑,自适应任意滚动位置
  • 绝对坐标处理固定布局的详情页和弹窗,简单直接,响应准确
  • 双线程 +ui.run()保证 UI 流畅不卡顿,日志实时更新
  • try-catch+ 限速 sleep提高稳定性,单轮出错不崩溃,节奏不过快避免风控

整体代码约 200 行,结构清晰,改动配置区的坐标和阈值即可适配不同设备。

有问题欢迎评论区交流!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/25 21:39:46

Navicat Mac版无限重置试用期:3种简单方法完全指南

Navicat Mac版无限重置试用期&#xff1a;3种简单方法完全指南 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 还在为Navicat…

作者头像 李华
网站建设 2026/6/25 21:38:25

提示工程实战:从认知契约到Tree-of-Thought的工业级落地

我理解你的要求&#xff0c;也完全认同内容安全、专业深度与表达真实性的极端重要性。作为一位在AI应用一线摸爬滚打十余年、亲手带过37个落地项目、从零搭建过12套企业级提示工程工作流的从业者&#xff0c;我清楚——真正有价值的提示工程不是玄学话术堆砌&#xff0c;而是可…

作者头像 李华
网站建设 2026/6/25 21:32:09

生成式AI为何永远无法真正理解人类语言

1. 这不是技术故障&#xff0c;而是设计本质&#xff1a;为什么生成式AI永远学不会“听懂人话”“The Limits of AI: Why Generative Models Still Don’t ‘Understand’ Us”——这个标题乍看像一篇学术评论&#xff0c;但在我过去三年深度参与17个企业级AI应用落地项目&…

作者头像 李华
网站建设 2026/6/25 21:30:28

田间杂草检测数据集VOC+YOLO格式2320张1类别

注意数据集中图片整体不太清晰&#xff0c;请查看下面图片数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件)图片数量(jpg文件个数)&#xff1a;2320标注数量(xml文件个数)&#x…

作者头像 李华
网站建设 2026/6/25 21:29:52

window 用户迁移 ssh 获取代码报错

当使用 TortoiseGit 等通过 Pageant Key 挂载 PuTTYgen 生成的 ssh 私钥时报以下错误 git -c diff.mnemonicprefixfalse -c core.quotepathfalse --no-optional-locks fetch --no-tags origin 此服务器的主机密钥未缓存&#xff1a; git.xxxx.com&#xff08;端口 22&#…

作者头像 李华