HOWTO: Web 自动化中使用 OCR

在进行 Web 自动化测试时,经常会遇到无法直接通过 DOM 树提取文本的图形化文字区域。例如:由 Canvas 渲染的各种图表和文字、图片格式的广告横幅(Banner)、自定义文字徽章(Badge),以及部分简单的图片验证码。

借助 CukeTest 提供的图像字符识别(OCR)库,我们可以对这些网页控件进行内存截图,并直接识别其中的文字内容,从而实现图形化文字的自动提取、核对或断言。

本文将介绍如何结合 Web 自动化模块与 OCR 库在网页上进行通用的文字识别。

适用场景与边界

结合 Web 截图与 OCR 能够有效扩展传统定位器的边界,解决特殊元素的文本比对与校验问题。在实际开发中,清晰划分其适用边界有助于您设计出更稳定的测试脚本。

推荐使用的场景

  • Canvas 与非标准渲染区域:目标文字被渲染在 canvas、SVG,或复杂的图形化报表组件中,无法通过常规的选择器(如 CSS/XPath)直接提取文本字符串。
  • 图形化文本验证:网页中包含带有特定促销、提示信息或动态生成文字的图片(如广告横幅 Banner、图片卡片、带文字的自定义徽章等),需要验证图片内的文案。
  • 极简图片验证码:处理无复杂干扰噪点、字形端正、字符无黏连的极简单数字或字母图片验证码。

不建议使用的场景

  • 常规标准 DOM 文本:如果文本能够直接通过选择器的常规文本属性(如 .innerText().textContent.getAttribute('alt') 等)直接提取,请优先使用标准 DOM 获取方式。常规提取在运行速度和识别精度上均远优于 OCR。
  • 复杂的安全人机验证码大多数现代安全验证码为防止爬虫干扰,均带有高强度的混淆混淆线、重叠噪点或滑块、旋转等复杂人机交互。 通用 OCR 无法实现极高精度的稳定识别。为保证自动化测试的健壮性,强烈建议在测试环境中配置白名单、采用固定测试验证码,或在后端通过免验证后门绕过。

一、准备工作

在编写代码之前,请确保以下前置条件:

  1. 已在项目中正确安装并引入 leanpro.web(Web 自动化模块)和 leanpro.visual(图像与 OCR 模块)。
  2. 在 CukeTest 界面的“设置” -> “高级” -> “OCR引擎”中选择合适的引擎(主要识别英文和数字时两者皆可;若需识别中文,建议切换并保存为 paddle 引擎)。
  3. 确保目标图形元素在页面上有唯一的定位标识(如带有 id="promo-banner"<div><img> 标签),以便脚本定位和截图。

二、执行步骤

在 Web 自动化中,使用 OCR 提取并验证图形文字的通用流程包含以下三个步骤:

1. 定位目标元素并截图

  • 操作说明:在页面加载完毕后,使用选择器定位到含有目标文字的图形元素(如横幅、Canvas),随后调用该元素的 screenshot() 方法。这会在内存中直接捕获该控件的快照并返回二进制数据(在 JavaScript 中为 Buffer,在 Python 中为 bytes),而无需将其写入本地磁盘,从而提高了执行效率。
  • 预期结果:成功获取代表控件图像的二进制缓冲区数据。
  • 失败排查入口:如果提示无法获取控件,说明元素可能尚未渲染完成,请在截图前使用等待机制确保元素处于可见状态。

2. 传输快照并调用 OCR 识别

  • 操作说明:引入 leanpro.visual 中的 Ocr 类,直接调用其 getVisualText(imageData) 方法。此方法将上一步中获取的二进制快照传递给 OCR 引擎进行分析,并异步或同步返回识别出的文本字符串。
  • 预期结果:OCR 引擎正确解析图像,并返回其内含的文字内容。
  • 失败排查入口:如果返回结果为空,可确认元素是否被其他悬浮窗遮挡,或临时开启调试保存本地图片,观察截图内容是否正常。

3. 清洗识别结果并进行验证

  • 操作说明:OCR 引擎在识别文字时,由于字间距或排版,经常会在返回字符中混入多余的换行、首尾空格或多余的空字符。在对文本进行断言校验前,必须使用字符串清洗方法(如 trim() 或正则表达式)过滤掉不需要的空白,然后使用测试框架提供的断言或判断条件进行核对。
  • 预期结果:文字清洗完成,并成功通过断言核对。
  • 失败排查入口:如果断言失败,可先将识别到的原始字符串打印到日志中,检查是否由于边缘模糊或字体原因导致了个别字符的识别误差。

三、示例代码

以下提供完整的双语言实现示例。该示例模拟了启动浏览器打开页面、定位一个包含促销码的图形横幅(#promo-banner)、截图并利用 OCR 识别、清洗文本、并验证促销码是否存在的完整操作流程。

示例代码

JavaScript
Python
const { chromium } = require('leanpro.web');
const { Ocr } = require('leanpro.visual');

(async () => {
    // 启动浏览器并打开目标页面
    const browser = await chromium.launch({ headless: false });
    const context = await browser.newContext();
    const page = await context.newPage();
    await page.goto('https://example.com');

    // 确保目标图形元素已加载并可见(例如活动横幅或带有文字的卡片)
    const elementSelector = '#promo-banner';
    await page.waitForSelector(elementSelector, { state: 'visible' });
    const targetElement = await page.$(elementSelector);

    if (targetElement) {
        // Step 1: 对目标图形元素进行截图,获取内存 Buffer 数据
        const screenshotBuffer = await targetElement.screenshot();

        // Step 2: 调用 OCR 库识别截图中的文字
        const rawText = await Ocr.getVisualText(screenshotBuffer);
        console.log(`OCR 识别原始结果: "${rawText}"`);

        // Step 3: 清洗提取出的文字内容(去除多余空格与换行)
        const cleanedText = rawText.trim().replace(/\s+/g, ' ');
        console.log(`清洗后的文本内容: "${cleanedText}"`);

        // 进行断言校验:验证横幅中是否包含预期的优惠券代码 "DISCOUNT100"
        if (cleanedText.includes('DISCOUNT100')) {
            console.log('测试通过:成功在促销横幅中识别出优惠券代码!');
        } else {
            console.warn('测试警告:未在促销横幅中识别到预期代码,请检查图片内容。');
        }
    } else {
        console.error('未找到目标图形元素。');
    }

    // 关闭浏览器
    await context.close();
    await browser.close();
})();
from leanproWeb import WebAuto
from leanproAuto import Ocr
import time

def run(webauto: WebAuto) -> None:
    # 启动浏览器并打开目标页面
    browser = webauto.chromium.launch(headless=False)
    context = browser.new_context()
    page = context.new_page()
    page.goto('https://example.com')

    # 确保目标图形元素已加载并可见(例如活动横幅或带有文字的卡片)
    element_selector = '#promo-banner'
    page.wait_for_selector(element_selector, state='visible')
    target_element = page.query_selector(element_selector)

    if target_element:
        # Step 1: 对目标图形元素进行截图,获取内存 bytes 数据
        screenshot_bytes = target_element.screenshot()

        # Step 2: 调用 OCR 库识别截图中的文字
        raw_text = Ocr.getVisualText(screenshot_bytes)
        print(f"OCR 识别原始结果: \"{raw_text}\"")

        # Step 3: 清洗提取出的文字内容(去除多余空格与换行)
        cleaned_text = ' '.join(raw_text.strip().split())
        print(f"清洗后的文本内容: \"{cleaned_text}\"")

        # 进行断言校验:验证横幅中是否包含预期的优惠券代码 "DISCOUNT100"
        if 'DISCOUNT100' in cleaned_text:
            print("测试通过:成功在促销横幅中识别出优惠券代码!")
        else:
            print("测试警告:未在促销横幅中识别到预期代码,请检查图片内容。")
    else:
        print("未找到目标图形元素。")

    # 关闭浏览器
    context.close()
    browser.close()

if __name__ == '__main__':
    with WebAuto() as webauto:
        run(webauto)

四、提升识别稳定性的最佳实践

OCR 是一项基于视觉的图形识别技术,其识别准确率深受字体、对比度、图片分辨率及缩放比例的影响。为提高在自动化测试中的稳定性,建议:

  1. 调整网页的缩放比例(提供高分辨率截图) 当目标图片的字号太小、文字边缘有明显锯齿时,OCR 引擎极易发生漏读。在执行 screenshot() 之前,可在脚本中通过执行 CSS 或调用页面缩放,将元素或页面比例放大(如放大至 1.5 倍),以获得更高清的文字渲染快照。
  2. 容错与净化处理 针对不同字符集的特殊情况,识别结果可能会混入标点或不可见字符。可通过清洗机制净化提取出的文本。例如:
    • 将多重空白统一合并为一个空格。
    • 如果识别的是纯英数字,通过正则表达式 replace(/[^a-zA-Z0-9]/g, '') 剔除所有无关噪点。
    • 使用模糊匹配、包含校验(如 includes / in)或正则表达式,而避免使用全等匹配。
  3. 关于简单验证码的特殊处理 如果页面包含最基础的、完全不扭曲的纯英数图片验证码:
    • 需在获取识别到的字符串后,完全剔除其中所有的空格字符:text.replace(/\s+/g, '')
    • 如果初次尝试提示验证码输入错误,建议捕捉该错误,触发刷新验证码图片的点击事件,并加入重试循环。一般通过 2-3 次刷新重试,即可通过简单的验证码校验。

results matching ""

    No results matching ""