当前位置: 首页 > news >正文

Python + uiautomator2 手机自动化控制教程

简介

uiautomator2 是比 ADB 更强大的 Android 自动化框架,支持元素定位、控件操作、应用管理等高级功能。本教程适合需要更精细控制的开发者。

一、环境准备

1.1 前置要求

  • Python 3.6 或更高版本
  • Android 手机(需开启开发者模式和 USB 调试)
  • USB 数据线
  • 已安装 ADB 工具(参考第一篇教程)

1.2 检查 Python 环境

python --version
# 应显示 Python 3.6 或更高版本

1.3 检查 ADB 连接

adb devices
# 应显示已连接的设备

二、安装 uiautomator2

2.1 安装 Python 库

pip install uiautomator2

使用国内镜像加速:

pip install uiautomator2 -i https://pypi.tuna.tsinghua.edu.cn/simple

2.2 初始化手机环境

重要步骤: 首次使用需要在手机上安装 ATX-Agent 和 uiautomator 服务。

# 方法一:使用命令行工具初始化
python -m uiautomator2 init# 方法二:使用 Python 脚本初始化
python
>>> import uiautomator2 as u2
>>> u2.connect_usb()  # 会自动安装必要组件
>>> exit()

初始化过程:

  1. 会在手机上安装两个 APK:
    • ATXAgent.apk - 核心服务
    • app-uiautomator.apkapp-uiautomator-test.apk - UI 自动化服务
  2. 安装过程需要 1-3 分钟
  3. 手机上会弹出安装提示,点击"安装"

2.3 验证安装

创建测试文件 test_u2.py

import uiautomator2 as u2# 连接设备
d = u2.connect()  # 自动连接 USB 设备
print("设备信息:", d.info)
print("✅ uiautomator2 安装成功!")

运行测试:

python test_u2.py

成功会显示设备信息(型号、分辨率、Android 版本等)。

三、uiautomator2 核心功能

3.1 设备连接方式

import uiautomator2 as u2# 方式1:自动连接(推荐)
d = u2.connect()# 方式2:通过 USB 连接
d = u2.connect_usb()# 方式3:通过设备序列号连接
d = u2.connect('device_serial')# 方式4:通过 WiFi 连接(需先配置)
d = u2.connect('192.168.1.100')

3.2 基础操作

# 获取设备信息
print(d.info)# 获取屏幕分辨率
width, height = d.window_size()
print(f"分辨率: {width}x{height}")# 截图
d.screenshot("screen.png")# 点击坐标
d.click(500, 1000)# 滑动
d.swipe(500, 1500, 500, 500, 0.3)  # 从下往上滑# 长按
d.long_click(500, 1000)# 输入文本
d.send_keys("Hello World")# 按键操作
d.press("home")  # 返回主屏幕
d.press("back")  # 返回键

3.3 应用管理

# 启动应用
d.app_start("com.ss.android.ugc.aweme")# 停止应用
d.app_stop("com.ss.android.ugc.aweme")# 清除应用数据
d.app_clear("com.ss.android.ugc.aweme")# 检查应用是否运行
if d.app_current().get('package') == "com.ss.android.ugc.aweme":print("抖音正在运行")# 获取当前应用信息
current = d.app_current()
print(f"当前应用: {current['package']}")

四、编写自动化脚本

4.1 基础滑动脚本

创建 u2_basic_swipe.py

"""
uiautomator2 基础滑动脚本
功能:自动滑动视频
"""import uiautomator2 as u2
import timedef main():# 连接设备d = u2.connect()print(f"✅ 已连接设备: {d.info['productName']}")# 获取屏幕尺寸width, height = d.window_size()print(f"📱 屏幕分辨率: {width}x{height}")# 配置参数interval = 5  # 滑动间隔(秒)count = 0print(f"⏰ 每 {interval} 秒滑动一次")print("按 Ctrl+C 停止\n")try:while True:count += 1# 从屏幕下方滑到上方# 使用相对坐标,自适应不同分辨率d.swipe(width // 2,      # x: 屏幕中央height * 0.8,    # y1: 屏幕 80% 位置width // 2,      # x: 保持在中央height * 0.2,    # y2: 屏幕 20% 位置0.3              # 滑动持续时间(秒))print(f"[{count}] {time.strftime('%H:%M:%S')} ✅ 滑动成功")time.sleep(interval)except KeyboardInterrupt:print(f"\n⏹️  已停止,共执行 {count} 次滑动")except Exception as e:print(f"\n❌ 发生错误: {e}")if __name__ == "__main__":main()

运行:

python u2_basic_swipe.py

4.2 高级功能脚本

创建 u2_advanced_swipe.py

"""
uiautomator2 高级自动化脚本
功能:
1. 启动指定应用
2. 智能检测页面状态
3. 支持多种滑动模式
4. 异常处理和自动恢复
"""import uiautomator2 as u2
import time
import random
from datetime import datetimeclass VideoAutomation:def __init__(self, package_name, interval=5, total_count=None):"""初始化视频自动化控制器参数:package_name: 应用包名interval: 滑动间隔(秒)total_count: 总滑动次数(None=无限次)"""self.package_name = package_nameself.interval = intervalself.total_count = total_countself.device = Noneself.count = 0self.width = 0self.height = 0def connect(self):"""连接设备"""try:self.device = u2.connect()self.width, self.height = self.device.window_size()print(f"✅ 已连接设备: {self.device.info.get('productName', 'Unknown')}")print(f"📱 分辨率: {self.width}x{self.height}")print(f"🤖 Android 版本: {self.device.info.get('version', 'Unknown')}")return Trueexcept Exception as e:print(f"❌ 连接设备失败: {e}")return Falsedef start_app(self):"""启动应用"""try:print(f"🚀 正在启动应用: {self.package_name}")self.device.app_start(self.package_name)time.sleep(3)  # 等待应用启动# 验证应用是否启动成功current = self.device.app_current()if current.get('package') == self.package_name:print(f"✅ 应用启动成功")return Trueelse:print(f"⚠️  启动的应用不匹配,当前: {current.get('package')}")return Falseexcept Exception as e:print(f"❌ 启动应用失败: {e}")return Falsedef check_app_running(self):"""检查应用是否在前台运行"""try:current = self.device.app_current()return current.get('package') == self.package_nameexcept:return Falsedef swipe_up(self):"""向上滑动(下一个视频)"""try:# 使用屏幕中央位置滑动x = self.width // 2y1 = int(self.height * 0.75)  # 起始位置:75%y2 = int(self.height * 0.25)  # 结束位置:25%self.device.swipe(x, y1, x, y2, 0.3)self.count += 1return Trueexcept Exception as e:print(f"❌ 滑动失败: {e}")return Falsedef swipe_down(self):"""向下滑动(上一个视频)"""try:x = self.width // 2y1 = int(self.height * 0.25)y2 = int(self.height * 0.75)self.device.swipe(x, y1, x, y2, 0.3)return Trueexcept Exception as e:print(f"❌ 滑动失败: {e}")return Falsedef random_swipe(self):"""随机滑动(模拟人类行为)"""# 90% 概率向上,10% 概率向下if random.random() < 0.9:return self.swipe_up()else:print("   ↓ 随机向下滑动")return self.swipe_down()def should_continue(self):"""判断是否继续执行"""if self.total_count is None:return Truereturn self.count < self.total_countdef get_random_interval(self):"""获取随机间隔时间(模拟人类)"""# 在设定间隔基础上 ±20% 浮动variation = self.interval * 0.2return self.interval + random.uniform(-variation, variation)def run(self):"""运行自动化任务"""if not self.connect():returnif not self.start_app():returnprint(f"\n⏰ 平均滑动间隔: {self.interval} 秒(随机波动)")if self.total_count:print(f"🎯 目标次数: {self.total_count} 次")else:print(f"🔄 持续运行(按 Ctrl+C 停止)")print("-" * 50)start_time = time.time()try:while self.should_continue():# 检查应用是否还在前台if not self.check_app_running():print("⚠️  应用不在前台,尝试重新启动...")if not self.start_app():break# 执行滑动current_time = datetime.now().strftime('%H:%M:%S')print(f"[{self.count + 1}] {current_time} ", end="")if self.random_swipe():print("✅")else:print("❌ 失败,继续...")# 等待随机间隔if self.should_continue():wait_time = self.get_random_interval()time.sleep(wait_time)except KeyboardInterrupt:print("\n\n⏹️  用户停止")except Exception as e:print(f"\n❌ 发生错误: {e}")finally:elapsed = time.time() - start_timeself.print_statistics(elapsed)def print_statistics(self, elapsed_time):"""打印统计信息"""print(f"\n{'='*50}")print(f"📊 运行统计:")print(f"   - 总滑动次数: {self.count}")print(f"   - 运行时长: {int(elapsed_time)} 秒 ({int(elapsed_time/60)} 分钟)")if self.count > 0:print(f"   - 平均间隔: {elapsed_time/self.count:.1f} 秒")print(f"{'='*50}")def main():import argparse# 解析命令行参数parser = argparse.ArgumentParser(description='uiautomator2 视频自动化脚本')parser.add_argument('package', help='应用包名,如: com.ss.android.ugc.aweme')parser.add_argument('-i', '--interval', type=float, default=5.0,help='滑动间隔(秒),默认5秒')parser.add_argument('-n', '--count', type=int, default=None,help='滑动次数,不指定则无限循环')args = parser.parse_args()# 创建并运行自动化任务automation = VideoAutomation(package_name=args.package,interval=args.interval,total_count=args.count)automation.run()if __name__ == "__main__":main()

4.3 智能元素定位脚本

创建 u2_smart_control.py

"""
基于 UI 元素的智能控制脚本
功能:通过识别页面元素来智能操作
"""import uiautomator2 as u2
import timeclass SmartController:def __init__(self, package_name):self.package_name = package_nameself.device = u2.connect()def start(self):"""启动应用"""self.device.app_start(self.package_name)time.sleep(2)def wait_and_click(self, text=None, description=None, timeout=10):"""等待元素出现并点击"""try:if text:# 通过文本查找并点击self.device(text=text).click(timeout=timeout)print(f"✅ 点击了: {text}")return Trueelif description:# 通过描述查找并点击self.device(description=description).click(timeout=timeout)print(f"✅ 点击了: {description}")return Trueexcept u2.exceptions.UiObjectNotFoundError:print(f"⚠️  未找到元素")return Falsedef swipe_if_video_exists(self):"""如果检测到视频元素就滑动"""# 示例:检测特定 ID 的视频容器if self.device(resourceId="video_container").exists:width, height = self.device.window_size()self.device.swipe(width//2, height*0.8, width//2, height*0.2, 0.3)print("✅ 检测到视频,已滑动")return Truereturn Falsedef auto_handle_popups(self):"""自动处理弹窗"""# 常见弹窗按钮文本close_texts = ["关闭", "取消", "不感兴趣", "跳过", "我知道了"]for text in close_texts:if self.device(text=text).exists:self.device(text=text).click()print(f"✅ 关闭弹窗: {text}")time.sleep(0.5)return Truereturn False# 使用示例
if __name__ == "__main__":controller = SmartController("com.ss.android.ugc.aweme")controller.start()# 自动处理启动页弹窗time.sleep(2)controller.auto_handle_popups()# 持续滑动for i in range(10):controller.swipe_if_video_exists()time.sleep(5)

五、运行指南

5.1 基础脚本运行

# 运行基础滑动脚本
python u2_basic_swipe.py

5.2 高级脚本运行

抖音自动刷视频(每5秒一次):

python u2_advanced_swipe.py com.ss.android.ugc.aweme

快手自动刷视频(每8秒一次,共50次):

python u2_advanced_swipe.py com.smile.gifmaker -i 8 -n 50

B站自动刷视频(每3秒一次):

python u2_advanced_swipe.py tv.danmaku.bili -i 3

5.3 查看帮助

python u2_advanced_swipe.py -h

六、WiFi 无线连接配置

6.1 配置步骤

1. 确保手机和电脑在同一 WiFi 网络

2. 通过 USB 启用 WiFi 调试:

# 查看手机 IP 地址
adb shell ip addr show wlan0# 启用 WiFi ADB(端口 5555)
adb tcpip 5555# 记下手机 IP 地址(如 192.168.1.100)

3. 连接 WiFi:

# 断开 USB 线
adb connect 192.168.1.100:5555

4. 在脚本中使用 WiFi 连接:

import uiautomator2 as u2# 使用 IP 地址连接
d = u2.connect('192.168.1.100')

6.2 WiFi 连接优势

  • 无需 USB 线,更自由
  • 可以同时控制多台手机
  • 适合长时间运

七、UI 元素定位技巧

7.1 查看页面元素

安装 weditor(UI 查看器):

pip install weditor

启动 weditor:

python -m weditor

浏览器会自动打开 http://localhost:17310

使用方法:

  1. 输入设备 IP 或序列号,点击 Connect
  2. 点击 Dump Hierarchy 获取当前页面结构
  3. 点击元素查看属性(text、resourceId、className 等)
  4. 可以实时测试定位表达式

7.2 常用定位方法

import uiautomator2 as u2
d = u2.connect()# 通过文本定位
d(text="立即登录").click()# 通过文本包含
d(textContains="登录").click()# 通过 resourceId 定位
d(resourceId="com.app:id/button").click()# 通过 className 定位
d(className="android.widget.Button").click()# 通过 description 定位
d(description="确认按钮").click()# 组合定位
d(className="android.widget.Button", text="确认").click()# 索引定位(多个相同元素时)
d(className="android.widget.Button")[0].click()  # 第一个按钮
d(className="android.widget.Button")[1].click()  # 第二个按钮

7.3 等待元素出现

# 等待元素出现(最多等待10秒)
d(text="加载完成").wait(timeout=10)# 等待元素消失
d(text="加载中...").wait_gone(timeout=10)# 判断元素是否存在
if d(text="登录").exists:print("找到登录按钮")# 获取元素信息
info = d(text="登录").info
print(info)

八、高级功能示例

8.1 自动点赞脚本

"""
视频自动点赞脚本
"""
import uiautomator2 as u2
import timed = u2.connect()
d.app_start("com.ss.android.ugc.aweme")
time.sleep(3)for i in range(10):# 双击屏幕点赞(适用于抖音)width, height = d.window_size()d.double_click(width//2, height//2)print(f"❤️  点赞第 {i+1} 次")time.sleep(1)# 滑动到下一个视频d.swipe(width//2, height*0.8, width//2, height*0.2, 0.3)time.sleep(5)

8.2 自动关注脚本

"""
自动关注作者脚本
"""
import uiautomator2 as u2
import timed = u2.connect()
d.app_start("com.ss.android.ugc.aweme")
time.sleep(3)for i in range(5):# 查找并点击关注按钮if d(text="关注").exists:d(text="关注").click()print(f"✅ 关注第 {i+1} 个作者")elif d(textContains="关注").exists:d(textContains="关注").click()print(f"✅ 关注第 {i+1} 个作者")else:print("⚠️  未找到关注按钮")time.sleep(2)# 滑到下一个视频width, height = d.window_size()d.swipe(width//2, height*0.8, width//2, height*0.2, 0.3)time.sleep(5)

8.3 截图并保存

"""
定时截图脚本
"""
import uiautomator2 as u2
import time
from datetime import datetimed = u2.connect()
d.app_start("com.ss.android.ugc.aweme")for i in range(10):# 生成带时间戳的文件名timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")filename = f"screenshot_{timestamp}.png"# 截图d.screenshot(filename)print(f"📸 已保存截图: {filename}")# 滑动width, height = d.window_size()d.swipe(width//2, height*0.8, width//2, height*0.2, 0.3)time.sleep(5)

8.4 监控屏幕变化

"""
监控屏幕变化脚本
"""
import uiautomator2 as u2
import timed = u2.connect()# 获取初始截图
last_screen = d.screenshot()while True:time.sleep(1)current_screen = d.screenshot()# 简单对比(可用图像相似度算法优化)if current_screen != last_screen:print("🔄 屏幕内容已变化")last_screen = current_screen

九、故障排查

9.1 “ConnectionError: Unable to connect to device”

解决方案:

# 1. 检查 ADB 连接
adb devices# 2. 重新初始化 uiautomator2
python -m uiautomator2 init# 3. 检查 ATX-Agent 是否运行
adb shell ps | grep atx# 4. 重启 ATX-Agent
adb shell am force-stop com.github.uiautomator
python -m uiautomator2 init

9.2 元素定位失败

解决方案:

  1. 使用 weditor 查看实际元素属性
  2. 检查元素是否在屏幕可见区域
  3. 增加等待时间
  4. 使用更精确的定位方式
# 添加等待
d(text="按钮").wait(timeout=10)# 尝试不同定位方式
if not d(text="登录").exists:d(textContains="登录").click()

9.3 “UiObjectNotFoundError”

解决方案:

# 使用异常处理
try:d(text="按钮").click()
except u2.exceptions.UiObjectNotFoundError:print("元素不存在,跳过")# 或先判断
if d(text="按钮").exists:d(text="按钮").click()

9.4 操作响应慢

解决方案:

# 设置操作超时时间
d.settings['operation_delay'] = (0, 0)  # 点击前后延迟
d.settings['operation_delay_methods'] = ['click', 'swipe']# 设置 implicitly_wait
d.implicitly_wait(10)  # 隐式等待10秒

9.5 WiFi 连接断开

解决方案:

# 重新连接
adb connect <手机IP>:5555# 保持连接
adb connect <手机IP>:5555
adb -s <手机IP>:5555 shell settings put global stay_on_while_plugged_in 7

十、性能优化

10.1 加快操作速度

# 关闭等待时间
d.settings['wait_timeout'] = 10  # 全局等待超时
d.settings['operation_delay'] = (0, 0)  # 操作延迟# 使用 shell 命令代替高级 API
d.shell("input swipe 500 1500 500 500 100")  # 更快

10.2 减少资源占用

# 不需要截图时关闭
# 使用 shell 命令代替截图检查# 批量操作
for i in range(100):d.swipe(500, 1500, 500, 500, 0.1)  # 减少滑动时间

10.3 异步操作

import asyncio
import uiautomator2 as u2async def swipe_task(device, count):for i in range(count):width, height = device.window_size()device.swipe(width//2, height*0.8, width//2, height*0.2, 0.3)await asyncio.sleep(3)async def main():d = u2.connect()await swipe_task(d, 10)asyncio.run(main())

十一、完整项目结构

phone-automation-u2/
├── test_u2.py                  # 测试连接
├── u2_basic_swipe.py           # 基础滑动
├── u2_advanced_swipe.py        # 高级滑动
├── u2_smart_control.py         # 智能控制
├── screenshots/                # 截图目录
│   └── screenshot_*.png
└── logs/                       # 日志目录└── automation.log

十二、uiautomator2 vs ADB 对比

功能uiautomator2ADB
元素定位✅ 支持❌ 不支持
应用管理✅ 便捷⚠️ 需命令
WiFi 连接✅ 简单⚠️ 需配置
学习曲线⚠️ 中等✅ 简单
性能⚠️ 中等✅ 快速
功能丰富度✅ 丰富⚠️ 基础
配置复杂度⚠️ 需初始化✅ 简单

十三、实战案例

13.1 完整的抖音自动刷视频脚本

"""
抖音自动刷视频完整脚本
功能:
- 自动启动抖音
- 智能跳过广告
- 随机间隔滑动
- 异常自动恢复
"""import uiautomator2 as u2
import time
import random
from datetime import datetimeclass DouyinAutomation:def __init__(self):self.device = u2.connect()self.package = "com.ss.android.ugc.aweme"self.count = 0def start(self):"""启动抖音"""print("🚀 启动抖音...")self.device.app_start(self.package)time.sleep(3)self.handle_popups()def handle_popups(self):"""处理启动弹窗"""close_buttons = ["关闭", "跳过", "我知道了", "取消"]for btn in close_buttons:if self.device(text=btn).exists:self.device(text=btn).click()print(f"✅ 关闭弹窗: {btn}")time.sleep(0.5)def swipe_next(self):"""滑到下一个视频"""width, height = self.device.window_size()# 添加轻微随机偏移x = width // 2 + random.randint(-50, 50)y1 = int(height * 0.75) + random.randint(-20, 20)y2 = int(height * 0.25) + random.randint(-20, 20)duration = random.uniform(0.25, 0.35)self.device.swipe(x, y1, x, y2, duration)self.count += 1def check_status(self):"""检查应用状态"""current = self.device.app_current()if current.get('package') != self.package:print("⚠️  应用不在前台,重新启动")self.start()return Falsereturn Truedef run(self, duration_minutes=30):"""运行指定时长"""self.start()end_time = time.time() + duration_minutes * 60print(f"🎬 开始刷视频,持续 {duration_minutes} 分钟")print("-" * 50)try:while time.time() < end_time:if not self.check_status():continue# 滑动timestamp = datetime.now().strftime('%H:%M:%S')print(f"[{self.count + 1}] {timestamp} ✅")self.swipe_next()# 随机间隔 4-8 秒interval = random.uniform(4, 8)time.sleep(interval)except KeyboardInterrupt:print("\n⏹️  用户停止")finally:print(f"\n📊 总共观看 {self.count} 个视频")if __name__ == "__main__":automation = DouyinAutomation()automation.run(duration_minutes=10)  # 运行10分钟

十四、总结

恭喜完成 uiautomator2 教程!你现在已经掌握:

✅ uiautomator2 环境搭建和初始化
✅ 设备连接(USB 和 WiFi)
✅ 基础操作(点击、滑动、输入等)
✅ UI 元素定位技巧
✅ 应用管理和控制
✅ 高级功能实现
✅ 异常处理和优化

uiautomator2 优势:

  • 功能强大,支持复杂交互
  • 可以精确定位 UI 元素
  • 支持无线连接
  • Python API 友好

适用场景:

  • 需要元素定位的自动化
  • 复杂交互逻辑
  • 应用测试
  • UI 自动化操作

下一步建议:

  • 学习图像识别(OpenCV)
  • 研究 OCR 文字识别
  • 探索 AI 辅助自动化
  • 学习 Appium 实现跨平台自动化

参考资源:

  • uiautomator2 文档:https://github.com/openatx/uiautomator2
  • weditor 工具:https://github.com/alibaba/web-editor
  • Android UI 文档:https://developer.android.com/reference/android/support/test/uiautomator/package-summary
http://www.dtcms.com/a/532548.html

相关文章:

  • 黑龙江省城乡建设厅网站注册广告公司名字
  • 杨校老师课堂之C++备赛信奥中STL常用库函数梳理汇总(含样例代码)
  • UU远程深度测评:聚焦游戏与Windows多屏场景,免费实用的远程控制选择
  • week7
  • 【Python刷力扣hot100】15. 3Sum
  • MacOS平台Keil代替方案
  • 建设项目技术服务网站笋岗网站建设
  • 【AI原生架构:数据架构】10、从主数据治理到价值落地
  • jQuery JSONP详解
  • GitHub等平台形成的开源文化正在重塑和解
  • 网站首页包含的内容wordpress扩展class名称
  • MCoT在医疗AI工程化编程的实践手册(上)
  • 济南网站建设淄博外贸网站哪家好
  • 阮一峰《TypeScript 教程》学习笔记——类型工具
  • 怎样做钓鱼网站网站建设电话营销话术
  • 51c大模型~合集32
  • 生物化学Learning Track(14)酶催化机制
  • 力扣2:两数相加
  • 构建通用并发下载工具:用Golang重构wget脚本的实践分享
  • 多国语言 网站源码邦邻营销型网站建设
  • 深圳网站制作服杭州专业网站
  • (N_156)基于springboot,vue小区物业管理系统
  • 短信验证码
  • mysql的 in 用法
  • 《考研408数据结构》第六章(5.1+5.2+5.3树、二叉树、线索二叉树)复习笔记
  • Python如何做语义分析
  • apipost如何设置mock接口
  • 网站流量显示openresty wordpress
  • Python装饰器解包装技术详解:从原理到高级应用
  • Spring事务自调用失效问题:Spring 默认使用代理(proxy)来实现事务拦截:只有通过代理对象的调用才会触发事务增强