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 无法实现极高精度的稳定识别。为保证自动化测试的健壮性,强烈建议在测试环境中配置白名单、采用固定测试验证码,或在后端通过免验证后门绕过。
一、准备工作
在编写代码之前,请确保以下前置条件:
- 已在项目中正确安装并引入
leanpro.web(Web 自动化模块)和leanpro.visual(图像与 OCR 模块)。 - 在 CukeTest 界面的“设置” -> “高级” -> “OCR引擎”中选择合适的引擎(主要识别英文和数字时两者皆可;若需识别中文,建议切换并保存为
paddle引擎)。 - 确保目标图形元素在页面上有唯一的定位标识(如带有
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 是一项基于视觉的图形识别技术,其识别准确率深受字体、对比度、图片分辨率及缩放比例的影响。为提高在自动化测试中的稳定性,建议:
- 调整网页的缩放比例(提供高分辨率截图)
当目标图片的字号太小、文字边缘有明显锯齿时,OCR 引擎极易发生漏读。在执行
screenshot()之前,可在脚本中通过执行 CSS 或调用页面缩放,将元素或页面比例放大(如放大至 1.5 倍),以获得更高清的文字渲染快照。 - 容错与净化处理
针对不同字符集的特殊情况,识别结果可能会混入标点或不可见字符。可通过清洗机制净化提取出的文本。例如:
- 将多重空白统一合并为一个空格。
- 如果识别的是纯英数字,通过正则表达式
replace(/[^a-zA-Z0-9]/g, '')剔除所有无关噪点。 - 使用模糊匹配、包含校验(如
includes/in)或正则表达式,而避免使用全等匹配。
- 关于简单验证码的特殊处理
如果页面包含最基础的、完全不扭曲的纯英数图片验证码:
- 需在获取识别到的字符串后,完全剔除其中所有的空格字符:
text.replace(/\s+/g, '')。 - 如果初次尝试提示验证码输入错误,建议捕捉该错误,触发刷新验证码图片的点击事件,并加入重试循环。一般通过 2-3 次刷新重试,即可通过简单的验证码校验。
- 需在获取识别到的字符串后,完全剔除其中所有的空格字符: