Python技术迷

如何用 Python 实现安卓机自动化?

昨天晚上十一点多,我在公司楼下抽烟,真困得半死,我们组那个小李突然在群里喊:“东哥,有没有啥办法,让我手机每天早上自己点开 APP 点两下就完事儿?我不想天天五点半爬起来打卡了。” 我当时看了一眼他那张睡眼惺忪的自拍,心想:这玩意儿用 Python 搞个安卓自动化不就完了嘛。

就顺着这个事儿跟你们唠一唠,怎么用 Python 把安卓手机“变成脚本”。

大概就是三件事:

  1. 电脑能连上手机,能发命令(靠的是 adb,那串命令行大家应该都见过)。
  2. Python 能在电脑上执行这些命令,或者调用现成的库。
  3. 手机那边帮你把“点击、滑动、输入文字”这些动作做出来。

你可以把这套东西想象成:Python → ADB → 手机,Python 是老板,adb 是中间的翻译,手机就是干活的打工人。 之前我搞数据库压测时,也是用脚本去怼数据库的,只不过那会儿老板是 JMeter,这次换成 Python 而已。

先把环境整好,不然后面全是玄学报错

小李当时一上来就问:“我是不是得 root ?要不要刷机?” 我说你先别把手机搞砖了,普通自动化根本用不到。

你需要这些:

  • 一部安卓机(尽量是自己机型,别拿女朋友手机乱试,出了问题不好解释…)
  • 数据线一根
  • 电脑上装好 Python 3.8+(越新越省心)
  • 手机打开开发者模式 + USB 调试
  • 电脑上装好 adb(装个 Android Platform Tools 就有)

手机那一步你应该很熟: 设置 → 关于手机 → 连续点版本号 N 下,弹出“你已处于开发者模式”。 然后回到设置里搜“开发者选项”,打开“USB 调试”。

电脑这边,确认 adb 有效,终端里敲:

adb devices

能看到类似:

ZX1Gxxxxxxxx    device

那就算通了。如果显示 unauthorized,就看手机上是不是弹了个“是否允许 USB 调试”,点允许就行。

先玩一圈“土法自动化”:Python + adb + 坐标点击

我一般教别人,会先从最土的办法开始,这样你能直观感受到“我真的是在操控手机”,而不是黑盒瞎碰。

Python 里直接调用 adb 命令,其实就是用 subprocess:

import subprocess

defadb(cmd: str) -> None:
    full_cmd = f"adb {cmd}"
    print("执行命令:", full_cmd)
    result = subprocess.run(full_cmd, shell=True, capture_output=True, text=True)
if result.stdout:
        print("输出:", result.stdout)
if result.stderr:
        print("错误:", result.stderr)

# 唤醒屏幕 + 解锁(简单粗暴版)
adb("shell input keyevent 26")   # 电源键
adb("shell input swipe 300 1000 300 300 300")  # 上滑解锁(数值按你手机分辨率改)

# 按坐标点击(x, y)
deftap(x: int, y: int):
    adb(f"shell input tap {x}{y}")

# 在某个输入框输入文字
definput_text(text: str):
# 注意空格要转义
    text = text.replace(" ", "%s")
    adb(f"shell input text '{text}'")

# 示例:点击屏幕中间,并输入一段话
tap(540, 960)
input_text("hello_android")

你可以随便打开一个聊天框、记事本之类的,然后跑这个脚本,看它自动给你敲字。 坐标咋来的?最粗暴的办法:开一个“开发者选项”里的“指针位置”,你手指点一下,就看到 X/Y 坐标了,记下来。

这个方式有两个硬伤:

  1. 手机分辨率变了,坐标就全废了。
  2. 页面稍微变动一下(比如弹了个弹窗),脚本直接点错地方。

所以这个只能算“入门感受一下”,真要上生产(哪怕是你个人每天打卡),建议还是用“根据元素定位”的方式。

别急着上高级库,先封装一下自己的“小遥控器”

我自己一般会先把这些 adb 命令封装成一个类,这样过几天再看,不至于一堆字符串看不懂。

import subprocess
from typing import Optional

classAndroidDevice:
def__init__(self, serial: Optional[str] = None):
        self.serial = serial

def_adb(self, cmd: str):
        prefix = f"adb -s {self.serial} "if self.serial else"adb "
        full_cmd = prefix + cmd
        print("[ADB]", full_cmd)
        result = subprocess.run(full_cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
            print("命令失败:", result.stderr)
return result.stdout.strip()

defwake(self):
        self._adb("shell input keyevent 26")

defswipe(self, x1, y1, x2, y2, duration_ms=300):
        self._adb(f"shell input swipe {x1}{y1}{x2}{y2}{duration_ms}")

deftap(self, x, y):
        self._adb(f"shell input tap {x}{y}")

definput_text(self, text: str):
        text = text.replace(" ", "%s")
        self._adb(f"shell input text '{text}'")

defstart_app(self, pkg: str, activity: str = None):
if activity:
            self._adb(f"shell am start -n {pkg}/{activity}")
else:
            self._adb(f"shell monkey -p {pkg} -c android.intent.category.LAUNCHER 1")

defhome(self):
        self._adb("shell input keyevent 3")

if __name__ == "__main__":
    phone = AndroidDevice()
    phone.wake()
    phone.swipe(300, 1000, 300, 300)
    phone.home()
    phone.start_app("com.android.settings")

这样你就有了一个最基础的“遥控器”。 比如你每天早上要打开某个打卡 APP,就可以把包名填进去,脚本一跑它自动帮你打开。

真正常用的玩法:用 uiautomator2 通过“控件”来操作

上面这些都是靠“坐标”点的,特别脆。 稍微靠谱一点的做法,是像写 Web 自动化那样,通过“元素”来点,比如“找到 text 是 ‘登录’ 的按钮,然后点击它”。

安卓上比较常用的一个库叫 uiautomator2,Python 版也很成熟,装起来:

pip install --upgrade pip
pip install uiautomator2

然后,手机插着电脑,命令行执行:

python -m uiautomator2 init

它会帮你把手机上必要的辅助服务装好,中间手机上可能弹权限框,一路点允许。

跑通之后,就可以在 Python 里这么写:

import uiautomator2 as u2

# 连接手机,默认 USB
d = u2.connect()  # 或者 u2.connect("设备序列号")

print("设备信息:", d.info)

# 启动一个应用,比如设置
d.app_start("com.android.settings")

# 等一会儿,等页面出来
d.wait_timeout = 10.0

# 举例:点击包含“应用”的设置项,注意不同机型文案不一样
d(textContains="应用").click()

# 滑动一下
d.swipe(0.5, 0.8, 0.5, 0.2)  # 用相对坐标,更通用

# 找搜索框输入点啥
search = d(resourceIdMatches=".*search.*")
if search.exists:
    search.click()
    d.send_keys("微信", clear=True)

你会发现,这一套写起来跟 Web 自动化特别像——都是“找元素 → 点 → 输入”。

uiautomator2 支持的定位方式挺多的,例如:

  • text="登录":按文本等于
  • textContains="登录":文本包含
  • resourceId="com.xxx:id/btn_login"
  • className="android.widget.Button"
  • description="更多":按 content-desc

你可以用它自带的可视化工具,或者配合 “uiautomatorviewer”、adb shell uiautomator dump 加 grep 去看页面上的控件信息,不过这个就有点展开聊不完了。

随便来个完整小例子:自动打开某个 APP 做一串操作

举个轻松一点的,不搞什么“代打卡”,就假设你有个“记账 APP”,每天想自动点进去,切到某个 tab,帮你点一下“新增”。

代码大概这样:

import time
import uiautomator2 as u2

PKG = "com.example.budget"# 替换成你自己的包名

defmain():
    d = u2.connect()
    print("已连接:", d.device_info)

# 亮屏 + 解锁(简单模式)
ifnot d.info.get("screenOn", True):
        d.screen_on()
        time.sleep(1)

# 如果有锁屏图案/密码,这里就有点复杂了,就不展开了

    d.app_start(PKG)
    d.wait_timeout = 10.0

# 等主界面加载,大部分 App 主按钮都有 text 或 desc
if d(text="记一笔").exists:
        d(text="记一笔").click()
elif d(description="记一笔").exists:
        d(description="记一笔").click()
else:
        print("没有找到记一笔按钮,可能 UI 改了")
return

# 输入金额
    amount_input = d(resourceIdMatches=".*amount.*")
if amount_input.exists:
        amount_input.click()
        d.send_keys("25.50", clear=True)

# 选分类
if d(text="餐饮").exists:
        d(text="餐饮").click()

# 保存
if d(text="保存").exists:
        d(text="保存").click()
else:
        print("没找到保存按钮")

# 退回桌面
    time.sleep(1)
    d.press("home")

if __name__ == "__main__":
    main()

你可以把这段脚本丢到一个 .py 文件里,每天让计划任务(Windows 任务计划程序 / Linux crontab)去跑一次,整个操作你都不用碰手机。

再高级一点的话题,比如多设备管理、截图识别、图像找点

有的人会问:“东哥,我能不能用图片识别去点某个按钮?因为 text 也不稳定。”

可以的,一般会用到:

  • uiautomator2 的截图功能:

    img = d.screenshot()  # 得到一个 PIL.Image 对象
  • 然后配合 opencv-python、aircv 去做模板匹配,找到那个按钮在屏幕上的位置,再用 d.click(x, y) 去点。

这个就像打游戏脚本一样,识别血条、识别按钮。但这一块容易越界到一些灰色地带的场景,我就不具体写代码了,你自己玩玩就好。

总之啊,用 Python 控制安卓,其实没你想的那么玄学,就是:

  • 把 adb 用熟
  • 选个顺手的库(像 uiautomator2)
  • 按“人怎么点手机”那一套动作,一步步翻译成代码

你可以从最简单的开始,比如:

  • 自动打开一个 App
  • 自动发一条固定内容的消息给自己
  • 自动每天开机后检查一下某个设置有没有被还原

等你写顺手了,再去玩更复杂的流程,别一上来就想把整条业务线全自动化,那真的容易把自己绕进去。

行,我这会儿先去泡杯咖啡,你要是有具体的场景(比如“帮我写个脚本自动打开 X App 干 Y 事”),你直接丢出来,我帮你把那段 Python 挑一挑、补全就行。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB