从 Appium WebView 痛点到 OCR 驱动的自动化测试


一、问题背景:传统自动化方案的三大痛点

在接手微信 H5 自动化测试之初,我们沿用了业界常见的 Appium 方案,但很快踩到了三个难以绕过的坑:

uiautomator2

为了更轻量化地控制设备,我们引入了 ——一个基于 Python、深度封装 Google 官方 UI Automator 的 Android 自动化框架。

它的核心优势十分突出:原生支持系统底层服务、无需 Root、API 极简(如 d(text='设置').click())、功能完备(多设备并行、截图录屏、手势模拟、UI 层级分析)。

二、破局思路:放弃 DOM 定位,改用视觉识别

核心思想一句话概括:摒弃对 DOM 结构的依赖,模拟人类视觉交互逻辑。

通过 OCR 识别屏幕上的文本,精准计算目标位置坐标,直接驱动设备执行点击操作。这样做带来三个直接收益:

  1. 无需切换上下文——彻底告别 WebView 与原生层的切换困扰,脚本执行更流畅稳定;
  2. 全端技术兼容——无视前端实现技术,H5、原生 App、小程序,只要屏幕上有可见文本就能定位;
  3. 逻辑直观稳定——完全基于用户可见的文本定位,与用户操作逻辑一致;只要界面文案不变,脚本就始终有效。

整个执行闭环只有五步:

01 屏幕截图  →  02 OCR 识别  →  03 文本匹配  →  04 坐标计算  →  05 模拟点击
实时捕获当前画面   提取画面所有文本   检索目标关键词   定位目标中心点   执行设备触控操作

OCR 定位原理:从识别到点击

OCR 引擎扫描屏幕像素,识别出文字区域后会返回一个精确的矩形框(Bounding Box)。这个矩形框由四个关键坐标定义边界:

为了实现精准点击,只需计算区域中心:

X = (Left + Right) / 2
Y = (Top  + Bottom) / 2

得到的就是目标文字的像素级中心点击坐标。整个过程完全不关心页面是 H5 还是原生,也不关心 DOM 长什么样。


三、OCR 引擎选型对比

确定方向后,我们调研了四个主流开源 OCR 引擎。

3.1 速度对比

数据来源:官方数据

四、项目 OCR 实现方案

4.1 复用同一张图片坐标

可以把上一次识别信息存在self.results这个实例变量中,当is_ocr is False时就不调用识别接口,直接查询结果

# 是否重新识别 若是同一个页面没有布局变化时可不重新识别 True重新识别
if is_ocr:
    self.results = self.recognize_text()

4.2 非文本类目标定位策略及多机型定位

核心痛点:
1 文本类天然适配多机型
2 面对"+"号、语音键等无文本的纯图标按钮,传统 OCR 因为识别不到文字而失效。而且不同手机分辨率不一样导致其他机型不一定可以定位到。

非文本类多机型定位解法分两步:

  1. 定位锚点(Anchor)——用 OCR 识别图标附近的已知文本(例如输入框旁的"输入文本"),作为坐标基准锚点;
  2. 动态偏移(Offset)——以锚点中心为原点,按屏幕百分比计算像素偏移量,精准映射到目标图标位置。

实现(consult_chat_page.py):

# 定位锚点并计算偏移量
matches = self.ocr_service.find_text(text="输入文本", is_ocr=True)
x, y = (matches[0].center_x, matches[0].center_y)
self.click_with_offset(x, y, offset_x=0.63, offset_y=0)  # 向右偏移 63%

4.3 密码输入

核心痛点: 如 支付时手机截图或者录取视频是黑屏

坐标获取:adb shell settings put system pointer_location 1

点击密码时策略

  1. 划定动态范围——为每个数字键定义基于屏幕百分比的动态区域,摒弃单点坐标,消除机械点击特征;
  2. 随机坐标生成——在预设区间内实时随机生成点击坐标,模拟人手点击的微小偏差;
  3. 模拟操作间隔——点击后随机等待 0.15~0.6 秒,复刻真人思考和操作的时间节奏。

核心实现:

def click_password_key(key):
    x1, x2, y1, y2 = KEY_AREAS[key]                 # 定义按键区域百分比
    x = random.randint(int(x1 * screen_w), int(x2 * screen_w))
    y = random.randint(int(y1 * screen_h), int(y2 * screen_h))
    device.click(x, y)
    time.sleep(random.uniform(0.15, 0.6))           # 随机延迟

五、其他手机系统框架

iautomator2 是 Android 平台专属的自动化框架
鸿蒙平台可调研 HMNextAuto https://github.com/ziguiway/hmnextauto
IOS 平台可调研 tidevice + facebook-wda https://github.com/openatx/facebook-wda


↙↙↙阅读原文可查看相关链接,并与作者交流