Airtest 框架详解:游戏/Android App 图像+UI树双引擎自动化
做自动化测试时,你大概率会遇到这些头疼场景:Unity/Cocos 游戏没有公开控件 ID、原生元素抓不到的小众 App、混合开发的“缝合怪”界面。这时候,网易开源的 Airtest 双引擎框架就是救命稻草——它既能靠图像识别“截图即脚本”,又能用 Poco 解析 UI 树精准操控,无需啃完几百页 UI 文档。
本篇文章从零开始,带你搭好开发环境、封装通用基类,再手写一个抖音短视频自动交互脚本(点赞、评论、滑视频),最后还会分享风控规避和图像识别优化技巧。
一、Airtest 双引擎是什么
Airtest Project 主要由两部分组成:
- Airtest:基于图像识别的自动化框架,通过截图匹配来定位元素,不依赖系统控件树,特别适合游戏引擎(Unity、Cocos2d-x、Egret)和无法获取 UI 树的场景。
- Poco:基于 UI 控件的自动化框架,直接从安卓/iOS 原生或游戏引擎的 UI 树中获取控件属性(文本、位置、层级等),执行点击、滑动、输入等操作,稳定性远高于图像识别。
两者可以在同一脚本里无缝混合使用,真正实现“哪边方便用哪边”。比如在抖音这种混合 App 里,整体界面用图像识别处理,评论区列表控件用 Poco 精准操作,效率极高。
二、environment-setup——5 分钟跑通第一个脚本
2.1 安装 AirtestIDE(推荐新手)
Airtest 提供了图形化的 IDE,内置录制回放、设备连接、报告查看等功能,适合快速上手:
- 前往 Airtest 官网 下载对应系统的 IDE 安装包。
- 安装后打开 AirtestIDE,默认自带
airtest 和 pocoui 两个核心库。
- 安卓手机开启 开发者模式 和 USB 调试,用数据线连接电脑,IDE 设备面板点击
Connect 即可看到手机画面。
2.2 使用 pip 构建脚本工程(适合集成 CI/CD)
如果要将 Airtest 集成到已有自动化项目或 CI 流水线,推荐用纯 Python 脚本方式:
pip install airtest
pip install pocoui
验证安装:
from airtest.core.api import *
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
# 连接设备(USB 连接串号可通过 adb devices 查看)
connect_device("Android:///")
poco = AndroidUiautomationPoco()
print(poco.device)
2.3 必要工具链
- ADB:安卓调试桥,Airtest 底层依赖它操控设备。配置好环境变量,确保终端执行
adb devices 能够列出设备。
- 手机设置:除 USB 调试外,建议开启“指针位置”方便查看坐标,关闭系统自动旋转、省电模式等干扰项。
三、基础操作速览——Airtest 图像引擎怎么用
图像识别的核心思想:先截取目标元素的“模板图”,脚本运行时在设备截屏中查找该图,找到后执行操作。
3.1 常用 API
from airtest.core.api import *
# 连接设备
connect_device("Android:///")
# 点击(模板图需提前截图放在项目目录)
touch(Template("like_btn.png"))
# 滑动
swipe((500, 1500), (500, 500)) # 从下往上滑
# 文本输入
text("很棒的视频")
# 按键事件
keyevent("HOME")
# 等待元素出现
wait(Template("comment_input.png"), timeout=10)
# 断言是否存在
assert_exists(Template("success_tip.png"), "点赞成功")
3.2 图像模板制作技巧
- 截取小范围且特征明显的区域(比如点赞按钮只有心形图标部分,不要带背景色块)。
- 保存为 PNG 格式,放在项目的
images/ 目录下,便于管理。
- 如果识别不稳定,可以用
touch(Template("btn.png", threshold=0.7)) 降低置信度阈值。
四、Poco 引擎——抓取 UI 树精准操控
Poco 不需要截图,直接通过反射或 AccessibilityService 获取控件树。
4.1 初始化 Poco
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)
参数说明:
use_airtest_input=True:通过 Airtest 设备连接执行点击,避免多重输入源冲突。
screenshot_each_action=False:不在每次操作后截图,提升速度。
4.2 常用操作示例
# 通过文本查找
poco(text="首页").click()
# 通过 ID 或层级关系
poco("android.widget.ListView").child("android.widget.TextView")[0].click()
# 滑动列表
poco("com.ss.android.ugc.aweme:id/recycler_view").swipe([0, -0.3])
# 获取属性
name = poco(text="视频标题").attr("text")
4.3 混合使用:Airtest + Poco
# 先用图像识别点击“评论”按钮
touch(Template("comment_icon.png"))
# 再通过 Poco 定位评论输入框输入文字
poco("android.widget.EditText").set_text("加油!")
五、实战:编写抖音短视频自动交互脚本
下面我们为抖音(TikTok 国内版)写一个自动化脚本,模拟日常浏览操作:刷视频、点赞、评论一条龙。
注意:本教程仅用于学习自动化测试技术,请勿用于刷量、虚假互动等违反平台规定的行为。
5.1 场景设计
- 打开抖音 App,等待首页加载。
- 连续滑动 3 个视频,每个视频停留 2 秒以上。
- 对第 4 个视频点赞并打开评论框。
- 随机输入一条正面评论并发送。
- 退出评论,继续滑动。
5.2 目录结构
douyin_auto/
├── main.py # 主脚本
├── base_operator.py # 封装基类
├── images/ # 图像模板
│ ├── home_tab.png # 首页 Tab
│ ├── like_btn.png # 点赞红心
│ ├── comment_btn.png # 评论图标
│ └── close_comment.png# 关闭评论
└── requirements.txt
5.3 封装通用基类 base_operator.py
import random
import time
from airtest.core.api import *
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
class BaseOperator:
def __init__(self, device_uri="Android:///"):
self.device = connect_device(device_uri)
self.poco = AndroidUiautomationPoco(
use_airtest_input=True,
screenshot_each_action=False
)
self.package = "com.ss.android.ugc.aweme"
def start_app(self):
"""启动抖音"""
stop_app(self.package)
time.sleep(1)
start_app(self.package)
sleep(5) # 等待首页加载
def swipe_video(self, direction="up", duration=0.3):
"""滑动视频,up 向上滑看下一个,down 向下滑看上一个"""
if direction == "up":
swipe((540, 1600), (540, 400), duration=duration)
else:
swipe((540, 400), (540, 1600), duration=duration)
sleep(2) # 停留观看时间
def like_current_video(self):
"""点赞当前视频(双引擎保底)"""
try:
# 优先用 Poco 查找点赞按钮
like_btn = self.poco(name="com.ss.android.ugc.aweme:id/ae8")
if like_btn.exists():
like_btn.click()
return
except Exception:
pass
# 降级为图像识别
touch(Template("images/like_btn.png", threshold=0.7))
def comment_current_video(self, text_content):
"""评论当前视频"""
# 点击评论图标
try:
self.poco(desc="评论").click()
except Exception:
touch(Template("images/comment_btn.png"))
sleep(1)
# 输入评论内容
self.poco("android.widget.EditText").set_text(text_content)
sleep(0.5)
# 发送按钮(不同版本可能是“发送”文本或发送图标)
send_btn = self.poco(text="发送")
if send_btn.exists():
send_btn.click()
else:
self.poco(type="android.widget.ImageView", desc="发送").click()
sleep(1)
# 关闭评论面板
self.close_comment_panel()
def close_comment_panel(self):
"""关闭评论面板,回退到短视频界面"""
keyevent("BACK")
sleep(0.5)
# 如果 BACK 键无效,用图像点击关闭按钮
if exists(Template("images/close_comment.png")):
touch(Template("images/close_comment.png"))
def random_comment(self):
"""生成随机正面评论"""
comments = ["太厉害了👍", "学到了", "支持创作者", "已点赞", "这内容绝了",
"幽默风趣哈哈", "每天必看", "这个系列能多出吗"]
return random.choice(comments)
def run_interaction_flow(self, swipe_count=3):
"""完整交互流程"""
self.start_app()
# 前 swipe_count 个视频只滑动
for i in range(swipe_count):
self.swipe_video("up")
# 第 swipe_count+1 个视频执行点赞+评论
sleep(1)
self.like_current_video()
sleep(0.5)
self.comment_current_video(self.random_comment())
# 继续滑动几个视频
for i in range(2):
self.swipe_video("up")
5.4 主入口 main.py
from base_operator import BaseOperator
if __name__ == "__main__":
operator = BaseOperator()
try:
operator.run_interaction_flow(swipe_count=3)
print("自动化流程完成")
except Exception as e:
print(f"脚本运行出错: {e}")
5.5 图像模板准备
实际操作中,用 AirtestIDE 的“截图”功能获取设备当前画面,裁剪出以下图片放到 images/:
like_btn.png:点赞按钮(未点赞状态的红心框)
comment_btn.png:评论图标(气泡形状)
close_comment.png:评论页面的关闭/返回按钮
尽量保持设备分辨率和截图时一致,以提高识别率。
六、风控规避——别让平台把你当成机器人
自动化脚本如果行为过于机械,很容易触发平台的风控机制(限制互动、要求验证码甚至封号)。以下是一些防御性策略:
6.1 随机化操作
# 滑动距离加入随机偏移
import random
x1, y1 = 540, 1600
x2, y2 = 540 + random.randint(-50, 50), 400 + random.randint(-30, 30)
swipe((x1, y1), (x2, y2), duration=random.uniform(0.2, 0.5))
# 每条评论间隔随机等待
sleep(random.uniform(3, 8))
6.2 模拟真实用户行为
- 不要只点赞不浏览:让脚本有“观看时长”概念,先在视频上停留随机时间再操作。
- 偶尔“误触”回滑:真实用户有时会划回上一个视频,可设置一定概率执行
swipe("down")。
- 交互频率限制:控制每日操作总量,分时段执行,避开连续高频操作。
6.3 账号环境伪装
- 使用真实常用的设备 ID 和 IP 环境,避免同一 IP 大量操作多个账号。
- 尽量保留设备原始的传感器数据、GPS 等信息(避免模拟器特征过重),可考虑使用真机集群。
七、图像识别优化——从 70% 到 99% 的稳定性飞跃
图像识别是 Airtest 最核心也最容易受环境影响的功能,以下优化手段能大幅提高成功率。
7.1 合适的阈值与灰度处理
# 降低阈值(默认 0.7)以适应轻微变化
touch(Template("btn.png", threshold=0.6, rgb=True))
# 使用灰度模板,忽略色彩差异(适用于按钮背景色渐变的情况)
touch(Template("btn.png", threshold=0.8, rgb=False))
7.2 多分辨率适配
不同手机分辨率下,控件大小和位置都会变化。解决方案:
- 优先用 Poco 定位,Poco 基于 UI 树不受分辨率影响。
- 对于图像模板,可录制相对坐标脚本:先找到固定锚点(如底部状态栏图标),然后以此为参考偏移点击。Airtest IDE 支持基于锚点的相对坐标录制。
7.3 动态等待与重试机制
def safe_touch(template, max_retry=3):
for i in range(max_retry):
if exists(template):
touch(template)
return True
sleep(1)
raise Exception(f"未找到元素: {template}")
7.4 模板更新策略
界面改版后会识别失败,可以建立模板仓库并在执行前检查版本。高级用法:编写“自愈”逻辑,当图像匹配失败时自动触发截图回调,通过人工或图像算法更新模板。
try:
touch(Template("comment.png"))
except TargetNotFoundError:
snapshot(filename="error_screen.png")
# 上报到监控平台,通知人工介入
八、进阶技巧与总结
- 报告生成:Airtest 脚本运行后会在当前目录生成
log/,里面有 HTML 报告和每步截图,方便 Debug。
- 跨平台:Airtest 同样支持 iOS(需 WebDriverAgent 和 Mac)、Windows 窗口程序的自动化。
- 嵌入 pytest:可以把 Airtest 操作封装成 pytest 测试用例,纳入持续集成流水线。
双引擎模式下,我们真正做到了“鱼与熊掌兼得”:游戏的封闭图形用图像识别攻克,原生 App 的动态列表用 Poco 精准抓取。配上抖音实战脚本和风控优化,这套方案已经可以直接迁移到直播监控、内容审核自动化、社交运营工具等实际场景中。
现在,打开你的 IDE,连接手机,试着用 touch(Template("xxx.png")) 写出第一行自动化代码吧——不需深究 UI 源码,也不用苦读几百页控件文档,所见即所得的自动化,就从 Airtest 开始。