 | |  |  | 通用找图OCR点字完整脚本骨架
- // ============================================================================
- // AIWROK 通用「找图 + OCR 点字」完整脚本骨架 (案例 #02 配套)
- // ============================================================================
- // 这才是一条正常在跑的脚本:复位 → 主循环 → 每轮 找图/OCR → 命中就点 → 下滑 → 随机等待 → 打日志。
- // 会持续运行(默认 20 轮、每轮等 1.5~4 秒,几十秒~几分钟),不是一秒结束的自检。
- //
- // 用法:
- // 1) 只改【配置区 CFG】:targets 里填你的按钮模板(base64,没有就留 null),words 里填界面真实文字;
- // 2) 直接运行,看日志:每一轮做什么、点没点、坐标多少、下一轮什么时候开,全打出来;
- // 3) 里面 findPic / ocrFind / doClick / doSwipe 都是可抠走的通用函数,避坑写法已焊死:
- // 判 null 不崩、百分比坐标 percentToWidth/Height 转像素、截图用完 recycle。
- //
- // 安全:默认 RUN_CLICK=false 时只“找到并打印坐标”不真点,先空跑验证再放开,防误点。
- // ============================================================================
- // ============================ 一、配置区(只改这里) ============================
- var CFG = {
- rounds: 20, // 跑多少轮后自动结束(想一直跑就写很大,如 999999)
- runClick: true, // ★先 false 空跑看日志,确认找得对再改 true 真点
- scroll: true, // 每轮结束后下滑一屏(养机/信息流常用)
- waitMin: 1500, waitMax: 4000, // 每轮随机等待(ms),防封,别设固定值
- idleStop: 6, // 连续这么多轮啥都没命中就提前收工(0=不停)
- // 模板找图:{名字, base64模板(没有填 null), 搜索区域比例[x1,y1,x2,y2]}
- targets: [
- { name: "关注按钮", tpl: null, region: [0, 0, 1, 1] },
- { name: "关闭广告X", tpl: null, region: [0.80, 0, 1, 0.20] },
- ],
- // OCR 点字兜底:界面里出现这些文字就点它(换成你 App 的真实按钮文案)
- words: ["关注", "点赞", "下一条"],
- threshold: 0.82, // 找图阈值,找不到先降到 0.75 再试
- };
- // ============================ 二、通用函数(可整段复制进工程) ============================
- function log(msg) { printl("[" + new Date().getTime() % 100000 + "] " + msg); } // printl 才有输出
- function getScr() {
- var s = { w: 1080, h: 2400 };
- try { s.w = screen.getScreenWidth(); s.h = screen.getScreenHeight(); } catch (e) {}
- return s;
- }
- function rand(a, b) { return Math.floor(a + Math.random() * (b - a + 1)); }
- function sleepMs(ms) { try { sleep.millisecond(ms); } catch (e) { java.lang.Thread.sleep(ms); } }
- // 点击:无障碍 auto.clickPoint → 全局 click 两级降级(不用HID);runClick=false 时只打印
- function doClick(x, y, tag) {
- x = Math.max(1, Math.min(getScr().w - 1, x));
- y = Math.max(1, Math.min(getScr().h - 1, y));
- if (!CFG.runClick) { log(" 占位不点[" + tag + "] (" + x + "," + y + ") —— runClick=false"); return false; }
- var ok = false;
- try { if (typeof auto !== "undefined" && auto.clickPoint) { auto.clickPoint(x, y); ok = true; } } catch (e) {}
- if (!ok) { try { click(x, y); ok = true; } catch (e) {} }
- log(" 点击[" + tag + "] (" + x + "," + y + ") ok=" + ok);
- return ok;
- }
- // 下滑一屏:auto.swip → auto.dispatchGesture 两级降级(无障碍,不用HID)
- function doSwipe() {
- if (!CFG.scroll) return;
- var s = getScr();
- var cx = Math.round(s.w * 0.5), y1 = Math.round(s.h * 0.75), y2 = Math.round(s.h * 0.30);
- var ok = false;
- try { if (typeof auto !== "undefined" && auto.swip) { auto.swip(cx, y1, cx, y2, 600, 0); ok = true; } } catch (e) {}
- if (!ok) { try { if (typeof auto !== "undefined" && auto.dispatchGesture) { auto.dispatchGesture(cx, y1, cx, y2, 600); ok = true; } } catch (e) {} }
- log(" 下滑 (" + y1 + "→" + y2 + ") ok=" + ok);
- }
- // 找图:★判 null + ★百分比转像素(案例 #02 两条命门都在这)
- function findPic(templateB64, regionPct, threshold) {
- if (!templateB64) return null;
- var region = regionPct || [0, 0, 1, 1];
- var detects = null;
- try { detects = auto.findImages([templateB64], threshold == null ? CFG.threshold : threshold, 0, 1, region); }
- catch (e) { log(" findImages异常(当null): " + e); return null; }
- if (!detects || detects.length === 0) return null; // 命门①:先判空,找不到返回 null 不崩
- var cx = detects[0].getRect().getCenterX(); // 命门②:这是百分比 0~1
- var cy = detects[0].getRect().getCenterY();
- var px = screen.percentToWidth(cx), py = screen.percentToHeight(cy); // 必须换算成像素
- return { px: Math.round(px), py: Math.round(py), count: detects.length };
- }
- // OCR 找字并点击(换分辨率/改版都能点,找图的最佳兜底)
- function ocrFindAndClick(word) {
- var img = screen.screenShotFull();
- try {
- var ocr = img.paddleOCR(640, [0, 0, 1, 1]);
- var hit = (ocr && ocr.findIncludeText) ? ocr.findIncludeText(word) : null;
- if (!hit) return null;
- var r = (hit.getRect) ? hit.getRect() : null;
- var x, y;
- if (r) { x = screen.percentToWidth(r.getCenterX()); y = screen.percentToHeight(r.getCenterY()); }
- else { x = null; y = null; }
- if (CFG.runClick) { try { hit.click(); } catch (e) {} }
- return { x: x, y: y };
- } catch (e) { return null; }
- finally { try { img.recycle(); } catch (e) {} } // 命门③:用完回收
- }
- // ============================ 三、主循环(真在跑的那段) ============================
- function reset() {
- log("复位:回到桌面清残留,再进目标页");
- try { if (typeof auto !== "undefined" && auto.home) auto.home(); } catch (e) {}
- sleepMs(800);
- try { if (typeof back !== "undefined") back(); } catch (e) {}
- sleepMs(500);
- }
- function oneRound(i) {
- log("— 第 " + i + " 轮 开始(屏 " + getScr().w + "x" + getScr().h + ",runClick=" + CFG.runClick + ")");
- var acted = false;
- // 1) 先按模板找图
- for (var t = 0; t < CFG.targets.length; t++) {
- var tg = CFG.targets[t];
- if (!tg.tpl) continue; // 没配模板跳过
- var f = findPic(tg.tpl, tg.region, CFG.threshold);
- if (f) { log(" 找图命中[" + tg.name + "] 共" + f.count + "处 → 像素(" + f.px + "," + f.py + ")"); doClick(f.px, f.py, tg.name); acted = true; }
- else { log(" 找图未命中[" + tg.name + "](不崩,继续)"); }
- }
- // 2) 找图没中 → OCR 点字兜底
- if (!acted) {
- for (var w = 0; w < CFG.words.length; w++) {
- var o = ocrFindAndClick(CFG.words[w]);
- if (o) { log(" OCR命中文字「" + CFG.words[w] + "」→ " + (o.x == null ? "已点(未取坐标)" : "像素(" + o.x + "," + o.y + ")")); acted = true; break; }
- }
- }
- if (!acted) log(" 本轮没找到任何目标 → 下滑换内容");
- // 3) 下滑 + 随机等待
- doSwipe();
- var wait = rand(CFG.waitMin, CFG.waitMax);
- log(" 本轮结束,等待 " + wait + "ms 后进入下一轮\n");
- sleepMs(wait);
- return acted;
- }
- function main() {
- var s = getScr();
- log("========================================");
- log(" 启动 通用找图/OCR点击脚本 本机 " + s.w + "x" + s.h + " 共 " + CFG.rounds + " 轮");
- log(" runClick=" + CFG.runClick + "(false=空跑只看日志不真点,验证OK再改true)");
- log("========================================");
- reset();
- var idle = 0;
- for (var i = 1; i <= CFG.rounds; i++) {
- var acted = oneRound(i);
- if (acted) idle = 0; else idle++;
- if (CFG.idleStop > 0 && idle >= CFG.idleStop) { log("连续 " + idle + " 轮无命中,提前收工。多半是:目标文字/模板不对,或分辨率变了模板失配 → 见案例 #02 第6节"); break; }
- }
- log("全部结束。");
- }
- main();
复制代码
| |  | |  |
|