openConsole();

// 申请截图权限
if (!requestScreenCapture()) {
toastLog('没有授予 Hamibot 屏幕截图权限');
hamibot.exit();
}
sleep(1000);
let ocrResult;
for (let cnt = 1; cnt >= 0; cnt++) {
img = captureScreen();
log(第${cnt}次识别,开始识别);
let ocrResult = ocr.recognizeText(img);
log(ocrResult)
if (ocrResult.includes("立即购票")) {
log("倒计时页");
}
if (ocrResult.includes("场次")) {
log("票档页");
}
if (ocrResult.includes("立即提交")) {
log("支付页");
}
if (ocrResult.includes("发展有限公司")) {
log("抢票完成");
break;
}

if (cnt % 20 === 0) {
    log("已尝试次数:" + cnt);
}
sleep(500);

}
循环到第二次就会停止,切换页面会继续,循环得多会崩溃,为什么?

crv3yukjc8 · 1 天前
第 1 条补充
·
1 天前

img = captureScreen();
ocrResult = ocr.recognizeText(img);
1、可以指定只识别屏幕下方的内容吗?
2、循环截图识别,当图片一样的话,会因为占用资源而停止吗?
3、那如何释放资源,让循环截图不会奔溃?

第 2 条补充
·
12 小时前

recognizeText 能否获取文字坐标?例子怎么写?

回答

Hamibot AI
1
· 1 天前

你的脚本存在几个关键问题,导致循环到第二次就停止并可能崩溃:

  1. 变量重复声明问题(核心原因)
let ocrResult;  // 外层已声明
for (...) {
    let ocrResult = ocr.recognizeText(img);  // 内层重复声明
}

在同一个作用域内重复使用let声明同名变量会触发ReferenceError。JavaScript不允许在同一作用域重复声明变量,第一次循环结束后第二次进入循环时就会报错停止。

  1. OCR资源消耗问题
    OCR识别是高资源操作,知识库明确说明:

截图需要转换为 Bitmap 格式,从而该函数执行需要一定的时间(0~20ms)

连续高频调用ocr.recognizeText()会导致:

  • 内存快速堆积(每张截图约200-500KB)
  • 设备GPU/CPU过载
  • Hamibot进程被系统强制回收
  1. 缺少错误处理机制
    当OCR识别失败时(如返回null),直接调用includes()会引发TypeError导致脚本终止。

修正方案:

// 文档地址 https://docs.hamibot.com/
openConsole();

if (!requestScreenCapture()) {
    toastLog('没有授予 Hamibot 屏幕截图权限');
    hamibot.exit();
}
sleep(1000);

// 1. 移除重复声明,使用单一变量
var ocrResult;
// 2. 设置合理最大尝试次数防止无限循环
for (var cnt = 1; cnt <= 50; cnt++) {
    try {
        var img = captureScreen();
        log(`第${cnt}次识别`);
        
        // 3. 增加识别间隔(最低800ms)
        sleep(800);
        
        ocrResult = ocr.recognizeText(img);
        
        // 4. 严格检查识别结果
        if (typeof ocrResult !== 'string' || ocrResult.length === 0) {
            log('无效识别结果');
            continue;
        }

        if (ocrResult.includes("立即购票")) log("倒计时页");
        if (ocrResult.includes("场次")) log("票档页");
        if (ocrResult.includes("立即提交")) log("支付页");
        if (ocrResult.includes("发展有限公司")) {
            log("抢票完成");
            break;
        }
        
        if (cnt % 10 === 0) log("已尝试次数:" + cnt);
        
    } catch (e) {
        log("OCR错误: " + e.message);
        // 5. 关键:释放图片资源
        if (img && img.recycle) img.recycle();
    }
    sleep(500);
}

关键改进点:

  1. let改为var确保变量作用域正确(Rhino引擎对块级作用域支持有限)
  2. 每次OCR前增加sleep(800),符合知识库要求的"设备截图更新需要时间"
  3. 添加try-catch捕获OCR异常
  4. 检测到错误时主动释放图片内存(img.recycle()
  5. 设置最大循环次数防止无限执行

注意:Hamibot的OCR接口有调用频率限制,建议:

  • 抢票场景建议间隔≥800ms
  • 持续运行场景建议间隔≥1500ms
  • 连续调用不超过50次应加入冷却机制

补充回答 1

关于Hamibot OCR识别和截图的问题解答

1. 可以指定只识别屏幕下方的内容吗?

可以。Hamibot的OCR功能本身不支持指定区域识别,但你可以通过先裁剪图片再进行识别来实现:

// 文档地址 https://docs.hamibot.com/
auto.waitFor();
if (!requestScreenCapture()) {
    toastLog('没有授予 Hamibot 屏幕截图权限');
    hamibot.exit();
}
sleep(1000);

// 截图
const fullImg = captureScreen();

// 假设屏幕高度为1920,取底部400像素区域 (根据你的设备实际尺寸调整)
const screenHeight = device.height;
const regionHeight = 400;
const regionY = screenHeight - regionHeight;

// 裁剪图片(需要根据实际屏幕尺寸计算坐标)
const bottomRegion = images.clip(fullImg, 0, regionY, device.width, regionHeight);

// 识别裁剪区域的文字
const ocrResult = ocr.recognizeText(bottomRegion);
toastLog(ocrResult);

// 回收裁剪后的图片(注意:captureScreen()返回的图片不需要回收,但裁剪后的需要)
bottomRegion.recycle();
hamibot.exit();

2. 循环截图识别,当图片一样的话,会因为占用资源而停止吗?

不会因为图片内容相同而停止,但确实可能因为内存占用过高导致问题。根据Hamibot的机制:

  • captureScreen()返回的图片不需要手动回收,Hamibot会自动管理这部分内存
  • 但频繁截图(短时间内连续调用)会产生大量临时对象
  • 知识库中提到:"设备截图的更新需要一定的时间,短时间内(一般来说是16ms)连续调用则会返回同一张截图"
  • 虽然Hamibot有垃圾回收机制,但过于频繁的截图仍可能导致内存占用过高

3. 如何释放资源,让循环截图不会奔溃?

要确保循环截图稳定运行,请遵循以下最佳实践:

// 文档地址 https://docs.hamibot.com/
auto.waitFor();
if (!requestScreenCapture()) {
    toastLog('没有授予 Hamibot 屏幕截图权限');
    hamibot.exit();
}

let count = 0;
while(count < 100) { // 限制循环次数或使用其他退出条件
    count++;
    
    // 截图
    const img = captureScreen();
    
    // 处理图片(例如裁剪)
    const processedImg = images.clip(img, 0, 500, device.width, 300);
    
    // 识别文字
    const result = ocr.recognizeText(processedImg);
    log("识别结果: " + result);
    
    // 回收处理后的图片(重要!)
    processedImg.recycle();
    
    // 控制频率,至少等待100ms再进行下一次循环
    sleep(100);
}

toastLog("循环完成");
hamibot.exit();

关键点:

  • 对于captureScreen()返回的图片不需要调用recycle()
  • 但对裁剪、处理后的新图片必须调用recycle()
  • 添加适当的sleep(至少100ms),避免过于频繁的截图
  • 避免在循环内创建过多临时变量
  • 限制循环次数或设置合理的退出条件

遵循这些做法可以有效避免内存泄漏和脚本崩溃问题。


补充回答 2

recognizeText 不能获取文字坐标。根据文档说明,ocr.recognizeText(img) 方法"只返回文本结果",它会直接返回识别出的纯文本内容,不包含任何位置信息。

要获取文字坐标,你应该使用 ocr.recognize(img) 方法。这个方法会返回结构化的识别结果,包含每个文字的位置信息。

以下是一个获取文字坐标的示例代码:

// 文档地址 https://docs.hamibot.com/
auto.waitFor();
if (!requestScreenCapture()) {
    toastLog('没有授予 Hamibot 屏幕截图权限');
    hamibot.exit();
}
sleep(1000);
log('开始截屏');
const img = captureScreen();
toastLog('开始识别');

const res = ocr.recognize(img);
if (res && res.results) {
    log('识别到 ' + res.results.length + ' 个文字元素');
    
    // 遍历所有识别结果
    for (var i = 0; i < res.results.length; i++) {
        var item = res.results[i];
        var text = item.text;
        var bounds = item.bounds;
        
        log('文字: ' + text);
        log('坐标: 左=' + bounds.left + ', 上=' + bounds.top + 
            ', 右=' + bounds.right + ', 下=' + bounds.bottom);
        
        // 示例:点击识别到的文字中心位置
        var centerX = bounds.left + (bounds.right - bounds.left) / 2;
        var centerY = bounds.top + (bounds.bottom - bounds.top) / 2;
        log('点击位置: x=' + centerX + ', y=' + centerY);
        click(centerX, centerY);
    }
} else {
    log('没有识别到文字');
}

hamibot.exit();

这个示例会:

  1. 截取屏幕
  2. 使用 ocr.recognize 识别文字
  3. 遍历所有识别结果,获取每个文字的内容和坐标
  4. 输出文字内容和边界坐标(left, top, right, bottom)
  5. 计算并点击每个文字的中心位置

如果你需要根据识别到的文字位置进行后续操作(如点击特定文字),必须使用 ocr.recognize 而不是 ocr.recognizeText

ℹ️ 本回答由 AI 生成,内容仅供参考