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

大家好我是Cline,最近有好多同学私信问Android端App爬虫/简单自动化测试怎么快速落地——不想啃厚厚的框架文档?不想折腾复杂的自定义控制器类?今天这篇咱们只抓3个主流工具,5分钟懂场景对比,30分钟抄完就能跑的抖音实战,全程无数学公式!


核心目标

  1. 按「轻量级/跨平台/游戏」3秒选对工具
  2. 掌握「UI树定位」「图像识别」2种核心精准定位法
  3. 抄跑带安全避坑的同步版抖音点赞+评论脚本
  4. 记住移动端自动化的3个基础反爬要点

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

直接看下方场景速查表,不用纠结直接挑👇

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

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

NOTE

本文全程用这个工具,小白友好,运行流畅!

极简安装+初始化

# 1. 电脑端装Python库
pip install uiautomator2
# 2. 手机开启「USB调试」连电脑,仅需运行1次(安装手机端ATX自动化代理)
python -c "import uiautomator2 as u2; d = u2.connect(); d.healthcheck()"

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

import uiautomator2 as u2
import time

# 1. 连接默认USB设备(也可写IP连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. UI树精准定位:优先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 快速入门(补盲游戏/特殊场景)

极简安装

# 纯Python版(适合整合进现有项目
pip install airtest pocoui
# 推荐下载【Airtest IDE】(有录制、Poco Inspector、图像截图功能,对新手太友好

5行核心双定位演示

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

# 1. 连接默认USB设备
connect_device("Android:///")
# 2. 初始化Poco UI树解析器
poco = AndroidUiautomationPoco(use_airtest_input=True)
# 3. 图像识别:IDE截「点赞按钮」小图存为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元素定位(按稳定度从高到低)

移动端UI经常动,定位越依赖固定属性越稳:

  1. resourceId(所有工具通用)
# uiautomator2示例
d(resourceId="com.ss.android.ugc.aweme:id/aweme_like_layout")  # 抖音点赞容器ID
# Appium/Poco通用写法(属性名会有细微差异,但逻辑一致)
  1. content-desc/desc(无障碍标签)
d(desc="点赞")
  1. textMatches(模糊文本匹配)
# 适合文本前缀/后缀固定的情况
d(textMatches=".*备用机推荐.*")
  1. 图像识别(最后迫不得已选)
  • 不带动态文字、仅核心图标的小图
  • 一定要加threshold参数(0.7-0.9,数值越高越严格但可能找不到)
# Airtest带阈值示例
Template(r"like.png", threshold=0.8).click()

2.2 基础避反爬手势(模拟「真人操作」)

  1. 硬等待→条件等待为主,随机延迟为辅
# 条件等待(最多等5秒,有就立即执行
search_box.wait(timeout=5)
# 随机延迟(每次操作间隙留个「思考时间」
import random
time.sleep(1.2 + random.uniform(-0.3, 0.3))
  1. 随机滑动距离/时长/位置
# uiautomator2示例
d.swipe_ext(
    "up",
    scale=0.7 + random.random()*0.1,  # 滑动屏幕的70%-80%高度
    duration=0.8 + random.random()*0.2  # 滑动耗时0.8-1秒
)
  1. 随机偏移点击位置
# 点击元素中心附近的随机点,避免每次都点同一个坐标触发风控
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. 实战:带安全避坑的同步版抖音自动点赞+评论

WARNING

仅供个人学习交流使用!请勿大规模刷量/批量爬取,否则可能触发抖音账号风控(限流、禁言甚至封号)!

3.1 前置准备

  1. 安卓手机开启「USB调试」(连WiFi调试也可以,但首次必须用USB授权)
  2. 打开抖音,进入首页推荐指定的话题/博主主页
  3. 获取元素ID的工具:
    • 新手推荐:Airtest IDE的「Poco Inspector」
    • 有Android SDK的同学:uiautomatorviewer

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()  # 也可以写u2.connect("192.168.1.100")连WiFi
    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;全平台测试→Appium
  2. 定位优先级:resourceId > content-desc > textMatches > 图像识别
  3. 避反爬三要素:条件等待+随机延迟、随机滑动、随机偏移点击
  4. 红线提醒:仅供学习,勿大规模刷量/爬取!