UI自动化控制技术 - 极简实战指南

大家好,我是Cline。

最近收到不少同学的私信,都在问同一个问题:Android端的App爬虫或者简单的自动化测试,怎么才能快速落地? 大家都不想啃几百页的框架文档,也不想折腾深不见底的自定义控制器类。今天这篇内容就只聚焦3个主流工具,帮你5分钟看懂场景对比,30分钟抄完就能跑的抖音实战,全程不涉及任何数学公式,完全是面向工程落地的指南。

核心目标

  1. 按照「轻量级/跨平台/游戏」三个维度,3秒内选出最合适的工具
  2. 掌握「UI树定位」和「图像识别」两种最核心的精准定位方法
  3. 复制并运行一个带安全避坑策略的同步版抖音点赞+评论脚本
  4. 记住移动端自动化的3个基础反爬要点

1. 工具对比与核心快速上手

先别急着安装,直接看下方的场景速查表,一眼就能找到最适合你当前需求的工具。

工具最佳适用场景安装难度运行性能原生图像识别核心优势
Appium全平台测试(Android/iOS/PC应用)中高一般需集成OpenCVWebDriver工业标准,多语言支持
Airtest游戏/UI树无法解析的复杂界面✅ 原生强(网易自研算法)自带可视化IDE + 录制,Poco + 图像双定位
uiautomator2Android专属Python轻量级项目极低需额外装opencv纯Python,基于Google官方uiautomator,爬虫/小脚本首选

对于绝大多数纯Android端的快速任务,uiautomator2 是成本最低、上手最快的选择。本文就用它来做主力演示。

1.1 uiautomator2 优先入门(实战用它)

uiautomator2 是一个纯 Python 库,底层调用了 Android 官方的 uiautomator 框架,性能高、接口简洁,对爬虫和自动化测试非常友好。

极简安装 & 初始化

只需两步,就能让电脑控制住你的安卓手机:

# 1. 电脑端安装 Python 库
pip install uiautomator2

# 2. 手机开启「USB调试」后连接电脑,运行一次即可完成手机端代理安装
python -c "import uiautomator2 as u2; d = u2.connect(); d.healthcheck()"

5行核心操作演示(以淘宝为例)

下面这段代码展示了最常用的操作流程:连接设备 → 启动 App → 定位元素 → 点击输入 → 滑动并搜索。

import uiautomator2 as u2
import time

# 1. 连接默认 USB 设备(WiFi 连接可用 u2.connect("192.168.1.100"))
d = u2.connect()
# 2. 启动指定 App(包名可通过 adb shell dumpsys window | grep mCurrentFocus 获取)
d.app_start("com.taobao.taobao")
time.sleep(3)  # 硬等待仅用于演示,实际建议用 exists() 做条件等待

# 3. 通过 resourceId 精准定位搜索框(resourceId 最稳定、最推荐)
search_box = d(resourceId="com.taobao.taobao:id/searchEdit")
# 4. 点击并输入关键词
search_box.click()
search_box.set_text("学生党备用机")
# 5. 上滑页面并点击「搜索」按钮
d.swipe_ext("up", scale=0.8)
d(text="搜索").click()

1.2 Airtest 快速入门(补盲游戏、特殊场景)

当界面元素无法通过 UI 树解析时(例如游戏、H5 内嵌页、特殊自定义控件),Airtest 的原生图像识别能力就是最佳选择。同时它也提供了 Poco 模块来解析 UI 树,双管齐下。

极简安装

# 纯 Python 版(方便集成到现有项目)
pip install airtest pocoui

# 推荐额外下载 Airtest IDE,内置录制、Poco Inspector、图像截取等工具,新手体验极佳

5行核心演示:图像 + UI 双定位

from airtest.core.api import *
from poco.drivers.android.uiautomation import AndroidUiautomationPoco

# 1. 连接默认 USB 设备
connect_device("Android:///")
# 2. 初始化 Poco 解析器
poco = AndroidUiautomationPoco(use_airtest_input=True)

# 3. 图像识别定位(需提前截图保存为 like.png,建议只截纯图标,不要带动态文字)
# Template(r"like.png", record_pos=(0.7, 0.5), resolution=(1080, 2400)).click()

# 4. Poco UI 树定位(当元素有稳定属性时优先使用)
poco(text="点赞").click()

# 5. 执行滑动操作
swipe((500, 1800), (500, 600), duration=0.8)

2. 核心避坑 + 稳定定位方案

2.1 UI 元素定位:按稳定度从高到低选择

移动端界面变化频繁,定位策略应该尽量依赖那些不容易变动的属性,优先级如下:

  1. resourceId(最稳定)

    # uiautomator2 示例
    d(resourceId="com.ss.android.ugc.aweme:id/aweme_like_layout")  # 抖音点赞按钮的容器
    # Appium / Poco 中也都有类似属性,只是具体字段名可能不同
  2. contentDescription / description(无障碍标签)

    d(desc="点赞")
  3. textMatches(模糊文本匹配)

    # 适合文本前缀/后缀固定的情况
    d(textMatches=".*备用机推荐.*")
  4. 图像识别(迫不得已的最后选择)

    • 截图时只截取那些没有动态文字、仅包含核心图标的小图
    • 务必设置 threshold 参数(建议 0.7~0.9,数值越高匹配越严格,但可能找不到)
    # Airtest 带阈值示例
    Template(r"like.png", threshold=0.8).click()

总结一个口诀:resourceId 优先,描述文本次之,图像识别断后。

2.2 基础反爬手势:模拟「真人操作」

平台的风控系统会检测操作是否过于机械,因此我们需要在脚本中刻入一些“人味儿”。

  1. 用条件等待代替硬等待,再加一点随机延迟

    # 条件等待:最多等5秒,元素一出现就立刻执行
    search_box.wait(timeout=5)
    
    # 随机延迟:每次操作后留一个「思考间隙」
    import random
    time.sleep(1.2 + random.uniform(-0.3, 0.3))
  2. 滑动距离、时长、位置随机化

    # uiautomator2 示例:随机化滑动幅度和速度
    d.swipe_ext(
        "up",
        scale=0.7 + random.random() * 0.1,        # 滑动屏幕高度的 70%~80%
        duration=0.8 + random.random() * 0.2     # 耗时 0.8~1.0 秒
    )
  3. 点击位置加入随机偏移

    def safe_click(element):
        """在元素中心附近随机点选,避免每次都命中同一坐标"""
        if not element.exists(timeout=2):
            return False
        bounds = element.bounds
        x = random.randint(bounds['left'] + 8, bounds['right'] - 8)
        y = random.randint(bounds['top'] + 8, bounds['bottom'] - 8)
        d.click(x, y)
        return True

这三点是移动端反爬的基础防线,成本极低,但效用显著。


3. 实战:带安全避坑的同步版抖音自动点赞 + 评论

⚠️ 重要提醒
本脚本仅供个人学习交流使用,请勿用于大规模刷量或批量抓取,否则可能触发抖音的风控机制,导致限流、禁言甚至封号。

3.1 前置准备

  1. 安卓手机开启「USB 调试」(首次连接必须通过 USB 授权;之后可切换 WiFi 调试)
  2. 手机打开抖音,停留在首页推荐流或某个视频的主页
  3. 使用元素定位工具(新手强烈推荐 Airtest IDE 自带的 Poco Inspector,有 Android SDK 的同学也可以使用 uiautomatorviewer)获取界面元素的 resourceId 等属性

3.2 完整可执行代码

代码已经内置了随机点赞概率、随机评论概率,以及多种元素定位的降级策略,你可直接复制运行。

import uiautomator2 as u2
import time
import random

# ----------------------- 配置区(可根据实际需求修改) -----------------------
DOUYIN_PKG = "com.ss.android.ugc.aweme"
LIKE_PROB = 0.4                # 40% 的概率给视频点赞
COMMENT_PROB = 0.1             # 10% 的概率发送评论
MAX_VIDEOS = 15                # 最多刷 15 个视频后停止
COMMENT_LIST = [
    "很棒的内容~",
    "学到了,收藏收藏!",
    "支持一下博主!",
    "这个好有意思哈哈哈哈",
    "666666"
]

# ----------------------- 连接设备 -----------------------
print("🔗 正在连接安卓设备...")
try:
    d = u2.connect()           # WiFi 调试可写 u2.connect("IP地址")
    print(f"✅ 连接成功!设备序列号:{d.serial}")
except Exception as e:
    print(f"❌ 连接失败,请检查 USB 调试或网络连接:{e}")
    exit()

# ----------------------- 安全操作工具函数 -----------------------
def safe_click(element, timeout=2):
    """带超时和随机偏移的安全点击"""
    if not element.exists(timeout=timeout):
        return False
    bounds = element.bounds
    # 避开元素边缘,防止点到无效区域
    x = random.randint(bounds['left'] + 6, bounds['right'] - 6)
    y = random.randint(bounds['top'] + 6, bounds['bottom'] - 6)
    d.click(x, y)
    return True

def random_delay(base, variance):
    """生成随机延迟,base 为基准秒数,variance 为上下浮动范围"""
    actual_delay = max(0.5, base + random.uniform(-variance, variance))
    time.sleep(actual_delay)

# ----------------------- 主运行逻辑 -----------------------
total_videos = 0
total_likes = 0
total_comments = 0

print(f"\n🚀 脚本启动!目标:最多处理 {MAX_VIDEOS} 个视频")
try:
    while total_videos < MAX_VIDEOS:
        total_videos += 1
        print(f"\n🎬 正在处理第 {total_videos}/{MAX_VIDEOS} 个视频...")
        # 模拟观看时间
        random_delay(2.5, 1)

        # 1. 随机点赞
        if random.random() < LIKE_PROB:
            # 多重降级定位,提高成功率
            like_element = (
                d(resourceId="com.ss.android.ugc.aweme:id/aweme_like_layout")
                or d(desc="赞")
                or d(resourceId="com.ss.android.ugc.aweme:id/dv9")  # 备用 ID(不同版本可能不同)
            )
            if safe_click(like_element):
                total_likes += 1
                print(f"👍 点赞成功!累计点赞:{total_likes}")
                random_delay(0.8, 0.3)

        # 2. 随机评论
        if random.random() < COMMENT_PROB:
            comment_btn = (
                d(resourceId="com.ss.android.ugc.aweme:id/aweme_comment_layout")
                or d(desc="评论")
                or d(resourceId="com.ss.android.ugc.aweme:id/dvb")
            )
            if safe_click(comment_btn):
                random_delay(1.5, 0.5)
                # 定位输入框
                input_box = (
                    d(resourceId="com.ss.android.ugc.aweme:id/chat_input_view")
                    or d(className="android.widget.EditText")
                )
                if input_box.exists(timeout=2):
                    random_comment = random.choice(COMMENT_LIST)
                    input_box.set_text(random_comment)
                    random_delay(0.9, 0.2)
                    # 点击发送按钮
                    send_btn = d(text="发送") or d(desc="发送")
                    if safe_click(send_btn):
                        total_comments += 1
                        print(f"💬 评论成功!内容:{random_comment} | 累计评论:{total_comments}")
                        random_delay(1, 0.3)
                # 返回视频播放页
                d.press("back")
                random_delay(0.8, 0.3)

        # 3. 上滑到下一个视频
        print("⬆️  滑动到下一个视频...")
        d.swipe_ext(
            "up",
            scale=0.7 + random.random() * 0.1,
            duration=0.8 + random.random() * 0.2
        )
        # 等待下一个视频加载完成
        random_delay(1.2, 0.5)

except KeyboardInterrupt:
    print("\n⏸️ 用户手动停止了脚本")
except Exception as e:
    print(f"\n❌ 脚本运行出错:{e}")
finally:
    print("\n📊 本次运行统计:")
    print(f"  处理视频数:{total_videos}")
    print(f"  成功点赞数:{total_likes}")
    print(f"  成功评论数:{total_comments}")

总结

  1. 如何选工具?
    Android 轻量爬虫 / 快速脚本 → uiautomator2
    游戏 / 复杂 UI 无法解析 → Airtest
    跨平台 (Android + iOS) 正规测试 → Appium

  2. 元素定位优先级
    resourceId > contentDescription > textMatches > 图像识别

  3. 反爬三件套
    条件等待 + 随机延迟、随机滑动距离/时长、随机偏移点击坐标

  4. 最后的红线
    本文所有技术仅用于学习交流,切勿进行大规模刷量或违法爬取。

只要把这套思路和模板代码掌握,绝大部分移动端 UI 自动化的入门任务都能高效落地,而不需要再被笨重的框架文档拖着走。希望这篇极简指南能真正帮到你。