AI-powered Android & web UI automation via Midscene.js, bridged into Python
Project description
Midscene Python
将 Midscene.js AI 驱动的 UI 自动化能力桥接到 Python 测试框架。
无需自行安装 Node.js;无需维护 UI 选择器——用自然语言描述操作,AI 负责定位和执行。
单一 midscene 包,工程代码按模块划分,同时支持:
| 模块 | 能力 | 入口 |
|---|---|---|
agent_android |
Android 自动化(ADB + @midscene/android) |
from midscene import MidsceneAndroidAgent |
agent_web / drivers |
网页自动化(Puppeteer + @midscene/web,预留 Playwright/Bridge) |
from midscene import MidsceneWebAgent |
| 共享底层 | 配置、异常、Node 运行时桥接、RPC 服务管理、BaseAgent |
from midscene import MidsceneConfig, BaseAgent |
本 README 以 Android 为主线说明;网页用法见 网页自动化。
目录
架构
Python 测试代码
└── agent.ai_action("点击登录按钮")
│
│ JSON-RPC 2.0(本地回环,无网络开销)
▼
midscene(共享底层)
├── Node 运行时(首次使用自动下载到 ~/.midscene/node_runtime/,android/web 共享)
├── NodeServiceManager(按平台 ServiceSpec 多实例:android / web 各一个 Node 进程)
└── BaseAgent(跨平台 ai_action / ai_tap / ai_query / ai_assert …)
│
├── MidsceneAndroidAgent → @midscene/android → ADB → Android 设备 / 模拟器
└── MidsceneWebAgent → @midscene/web → Puppeteer → Chromium 浏览器
关键特性:
- 每个平台的 Python 进程与其 Node 进程 1:1;同平台多个 Agent 共享一个 Node 进程(通过 sessionId 隔离)
- android 与 web 各自拥有独立的 Node 服务与缓存命名空间,可并存
- Python 进程退出时 Node 子进程自动清理
- 无需系统已安装
node或npm
安装
pip install midscene
首次使用:会按需自动执行
npm install(Android 用@midscene/android,Web 用@midscene/web+ puppeteer),需要访问 npm registry。只有实际使用的平台才会触发对应安装。
系统要求:
| 条件 | 说明 |
|---|---|
| Python | 3.9 及以上 |
| ADB | 已安装并在 PATH 中(adb devices 能看到目标设备) |
| AI API | 支持 OpenAI 兼容接口的视觉模型(如 qwen-vl-max、GPT-4o) |
| Node.js | 无需预装;首次使用自动下载到 ~/.midscene/node_runtime/(wheel 不内置 Node) |
快速开始
1. 配置 AI 模型
推荐使用 .env 文件(存放项目根目录,自动加载,无需 export;请勿将含密钥的 .env 提交到版本库):
# .env
MIDSCENE_MODEL_BASE_URL=https://ark.cn-beijing.volces.com/api/v3/
MIDSCENE_MODEL_API_KEY=ark-your-api-key
MIDSCENE_MODEL_NAME=doubao-seed-1-6-vision-250815
MIDSCENE_MODEL_FAMILY=doubao-seed
首次使用:还会自动下载 Node.js / npm 到
~/.midscene/node_runtime/(需访问 nodejs.org;与系统是否已安装 Node 无关)。
2. 编写测试
from midscene import MidsceneAndroidAgent
# 从 .env 或环境变量自动读取配置
agent = MidsceneAndroidAgent("emulator-5556")
with MidsceneAndroidAgent("emulator-5556") as agent:
agent.ai_action("等待应用首页加载完成")
agent.ai_tap("登录按钮")
agent.ai_input("用户名输入框", "testuser")
agent.ai_input("密码输入框", "Test@123456")
agent.ai_tap("确认登录")
agent.ai_wait_for("登录成功,显示用户首页", timeout_ms=10000)
agent.ai_assert("当前页面是用户首页")
3. 在 pytest 中使用
# conftest.py
import pytest
from midscene import MidsceneAndroidAgent
@pytest.fixture
def agent():
ag = MidsceneAndroidAgent("emulator-5556")
yield ag
ag.destroy()
# test_login.py
def test_login(agent: MidsceneAndroidAgent):
agent.ai_action("打开登录页面")
agent.ai_input("用户名", "testuser")
agent.ai_input("密码", "password")
agent.ai_tap("登录")
agent.ai_assert("登录成功,显示用户名 testuser")
网页自动化
网页自动化由 MidsceneWebAgent 提供,默认使用 Puppeteer 驱动(首次使用会自动安装 @midscene/web 与 puppeteer,并下载 Chromium)。
from midscene import MidsceneWebAgent
agent = MidsceneWebAgent("https://example.com")
agent.ai_action("在搜索框输入 midscene 并回车")
agent.ai_assert("搜索结果已展示")
agent.destroy()
选择 / 配置驱动:
from midscene import MidsceneWebAgent, PuppeteerDriver
# 有头模式 + 指定视口
agent = MidsceneWebAgent(
"https://example.com",
driver=PuppeteerDriver(headless=False, viewport={"width": 1440, "height": 900}),
)
# 连接已运行的 Chrome(chrome --remote-debugging-port=9222)
agent = MidsceneWebAgent(driver=PuppeteerDriver(cdp_endpoint="http://127.0.0.1:9222"))
网页专有方法:goto / back / forward / reload / current_url / current_title、多标签(new_tab / list_tabs / switch_tab / close_tab)、set_viewport、wait_for_selector / wait_for_navigation、run_script、ai_hover / ai_right_click,以及全部跨平台 ai_* 方法。PlaywrightDriver / BridgeDriver 为占位,后续接入。
pytest 插件
安装 midscene 后,pytest 会自动加载内置插件,无需额外配置。提供 midscene_agent(Android)与 midscene_web_agent(Web)两个 fixture。
内置 fixture:midscene_agent
无需在 conftest.py 中自行声明 fixture,直接在测试函数参数中使用即可:
# test_my_app.py
import pytest
@pytest.mark.device
def test_login(midscene_agent):
midscene_agent.ai_action("点击登录按钮")
midscene_agent.ai_input("用户名", "testuser")
midscene_agent.ai_input("密码", "Test@123456")
midscene_agent.ai_assert("登录成功,显示用户首页")
设备 ID 解析顺序:
| 优先级 | 来源 |
|---|---|
| 1 | --midscene-device CLI 参数 |
| 2 | MIDSCENE_DEVICE_ID 环境变量 |
| 3 | ANDROID_DEVICE_ID 环境变量 |
| 4 | 自动选取第一台已连接设备 |
失败自动截图与报告
使用 midscene_agent 的测试用例失败时,插件会自动:
- 调用
get_screenshot()将当前屏幕保存为 PNG。 - 调用
get_report_file()获取 Midscene HTML 报告路径。 - 将上述路径附加到 pytest 报告的 sections(终端
-v输出和 pytest-html 均可见)。
截图保存路径示例:
midscene_artifacts/tests__test_login__test_login.png
CLI 选项
# 指定设备
pytest --midscene-device emulator-5556 tests/ -m device
# 自定义截图保存目录
pytest --midscene-artifact-dir /tmp/ci_artifacts tests/ -m device
| 选项 | 默认值 | 说明 |
|---|---|---|
--midscene-device |
自动检测 | midscene_agent 使用的 Android 设备 ID |
--midscene-url |
无 | midscene_web_agent 的起始页面 URL(或 MIDSCENE_WEB_URL) |
--midscene-headed |
关闭 | midscene_web_agent 以有头模式启动浏览器 |
--midscene-artifact-dir |
midscene_artifacts/ |
失败截图与报告的保存目录 |
midscene_web_agent 用法:
def test_search(midscene_web_agent):
midscene_web_agent.goto("https://example.com")
midscene_web_agent.ai_action("点击更多信息链接")
midscene_web_agent.ai_assert("页面已跳转")
配置
MidsceneConfig
可以通过环境变量、.env 文件或代码直接传入配置:
from midscene import MidsceneAndroidAgent, MidsceneConfig
# 方式一:从 .env / 环境变量自动读取(推荐)
agent = MidsceneAndroidAgent("emulator-5556")
# 方式二:代码直接传入
config = MidsceneConfig(
base_url="https://ark.cn-beijing.volces.com/api/v3/",
api_key="ark-your-api-key",
model_name="doubao-seed-1-6-vision-250815",
model_family="doubao-seed",
)
agent = MidsceneAndroidAgent("emulator-5556", config)
支持的模型家族
model_family |
适用模型 | 示例 model_name |
|---|---|---|
openai |
OpenAI GPT 系列 | gpt-4o |
qwen |
阿里通义千问 | qwen-vl-max |
doubao |
字节豆包 | doubao-vision-pro-32k |
gemini |
Google Gemini | gemini-2.0-flash |
claude |
Anthropic Claude | claude-opus-4-5 |
环境变量说明
| 变量 | 必填 | 说明 |
|---|---|---|
MIDSCENE_MODEL_BASE_URL |
✅ | AI API 的 base URL |
MIDSCENE_MODEL_API_KEY |
✅ | API Key |
MIDSCENE_MODEL_NAME |
✅ | 模型名称 |
MIDSCENE_MODEL_FAMILY |
❌ | 模型家族 |
API 参考
所有方法均为同步调用,内部通过 JSON-RPC 与 Node.js 微服务通信。
初始化与销毁
agent = MidsceneAndroidAgent(device_id, config=None)
# device_id : ADB 设备 ID,如 "emulator-5556" 或 "192.168.1.100:5555"
# config : MidsceneConfig 实例,可选,默认从环境变量读取
agent.destroy() # 释放 session,进程退出时自动调用
agent.is_closed() # 返回 True/False
弃用说明:
MidsceneAgent已更名为MidsceneAndroidAgent(与MidsceneWebAgent对称)。旧名仍可from midscene import MidsceneAgent导入,但实例化时会触发DeprecationWarning,将在后续版本移除。
Auto Planning
agent.ai_action(prompt: str) -> None
AI 自动规划并执行多步操作。适合描述复合目标:
agent.ai_action("打开设置,找到蓝牙选项并开启")
agent.ai_action("滑动到页面底部,点击'加载更多'")
Instant Actions — 精确单步操作
比 ai_action 更快、更稳定,适合已知元素的直接操作:
agent.ai_tap(locate: str) -> None
# 点击元素
agent.ai_tap("屏幕右上角的关闭按钮")
agent.ai_tap("文字为'立即购买'的按钮")
agent.ai_input(locate: str, value: str) -> None
# 在指定输入框中输入文本(先清空再输入)
agent.ai_input("搜索框", "midscene python")
agent.ai_clear_input(locate: str) -> None
# 清空输入框内容
agent.ai_clear_input("用户名输入框")
agent.ai_scroll(
locate: str = None,
direction: str = "down", # "up" | "down" | "left" | "right"
scroll_type: str = None,
distance: int = None,
) -> None
# 滚动操作
agent.ai_scroll("商品列表", direction="down", distance=3)
agent.ai_long_press(locate: str, duration: int = None) -> None
# 长按,duration 单位毫秒
agent.ai_long_press("消息列表第一条")
agent.ai_double_click(locate: str) -> None
# 双击
agent.ai_double_click("图片预览区域")
agent.ai_keyboard_press(key_name: str, locate: str = None) -> None
# 模拟按键,如 "Enter"、"Back"、"Home"
agent.ai_keyboard_press("Enter")
agent.ai_keyboard_press("Back")
agent.ai_pinch(
direction: str, # "in"(缩小)| "out"(放大)
locate: str = None,
distance: int = None,
duration: int = None,
) -> None
# 捏合/张开手势
agent.ai_pinch("out", locate="地图区域")
Utility — 断言与数据提取
agent.ai_assert(assertion: str) -> None
# AI 视觉断言,失败时抛出 AssertionError
agent.ai_assert("当前页面显示用户名 testuser")
agent.ai_assert("购物车商品数量为 3")
agent.ai_wait_for(assertion: str, timeout_ms: int = 15000) -> None
# 等待条件满足,超时抛出异常
agent.ai_wait_for("加载动画消失", timeout_ms=10000)
agent.ai_wait_for("弹窗出现", timeout_ms=5000)
agent.ai_query(data_demand) -> Any
# 从当前屏幕提取结构化数据
products = agent.ai_query({"name": "string", "price": "number", "in_stock": "boolean"})
title = agent.ai_query("页面标题文字")
agent.ai_ask(prompt: str) -> Any
# 自由问答,返回 AI 对当前屏幕的理解
answer = agent.ai_ask("当前页面的主要功能是什么?")
agent.ai_boolean(prompt: str) -> bool
# 返回布尔值
is_logged_in = agent.ai_boolean("用户是否已登录?")
agent.ai_number(prompt: str) -> Any
# 返回数字
count = agent.ai_number("购物车中的商品数量")
agent.ai_string(prompt: str) -> str
# 返回字符串
username = agent.ai_string("当前登录的用户名")
agent.ai_locate(locate_prompt: str) -> Any
# 定位元素,返回位置信息(坐标等)
pos = agent.ai_locate("确认按钮")
原生 ADB
agent.run_adb_shell(command: str, timeout_ms: int = None) -> str
# 执行 adb shell 命令,返回输出文本;timeout_ms 单位为毫秒
output = agent.run_adb_shell("dumpsys activity top | grep 'ACTIVITY'")
output = agent.run_adb_shell("pm list packages | grep com.example", timeout_ms=5000)
异常处理
from midscene import MidsceneRPCError
try:
agent.ai_assert("某个不存在的条件")
except AssertionError as e:
# AI 断言失败(pass=False),包含失败原因
print(f"断言失败: {e}")
try:
agent.ai_action("点击某个按钮")
except MidsceneRPCError as e:
# Node.js 侧报错(如设备断开、ADB 错误)
print(f"RPC 错误 [code={e.code}]: {e}")
| 异常 | 触发场景 |
|---|---|
AssertionError |
ai_assert() 条件不满足 |
MidsceneRPCError |
Node.js 侧业务错误(ADB 断开、元素找不到等) |
MidsceneConfigError |
必填配置缺失,或同一平台复用 Node 服务时传入了不同的 MidsceneConfig |
MidsceneSetupError |
Node 二进制缺失、npm install 失败等初始化问题 |
MidsceneNodeServiceError |
Node.js 服务启动失败或意外退出 |
MidsceneError |
使用已 destroy() 的 Agent |
开发者指南
本地开发
git clone https://github.com/zypdominate/midscene-python
cd midscene_python
# 以可编辑方式安装(含开发工具)
pip install -e ".[dev]"
# 首次运行测试会自动下载 Node 到 ~/.midscene/node_runtime/
根目录 pyproject.toml 同时承载打包元数据与 ruff / pytest / mypy 配置,并把 src 加入 pythonpath,因此在根目录直接执行 pytest / ruff check . / mypy 即可。
运行测试
# 全部非真机/非浏览器测试(首次需联网下载 Node + npm 依赖)
pytest -m "not device and not web" -v
# 需要真实 Android 设备的测试(需配置好 .env 并连接设备)
pytest tests/ -m device -v -s
# 需要真实浏览器 + AI Key 的网页测试
pytest tests/ -m web -v -s
构建与发布
# 构建 py3-none-any wheel + sdist
python tools/build_wheel.py --clean
# 检查并上传 PyPI
python tools/upload_pypi.py --dry-run
python tools/upload_pypi.py --require-all --yes
项目结构
src/midscene/
├── __init__.py # 顶层导出(MidsceneAndroidAgent / MidsceneWebAgent / 驱动 / 异常 …)
├── config.py # MidsceneConfig(环境变量 / .env 支持)
├── exceptions.py # 公开异常体系
├── agent_android.py # MidsceneAndroidAgent(BaseAgent) + 设备/系统方法
├── agent_web.py # MidsceneWebAgent(BaseAgent) + 网页导航/等待/脚本执行
├── drivers.py # PuppeteerDriver(实现)+ Playwright/Bridge(占位)
├── py.typed
├── _internal/ # 私有实现(非公共 API,可能随版本变动)
│ ├── node_bootstrap.py # 首次运行从 nodejs.org 下载 Node/npm
│ ├── runtime.py # ServiceSpec + 按平台参数化的 npm install / 缓存
│ ├── node_service.py # NodeServiceManager(按 spec 名称多实例)
│ ├── base_agent.py # BaseAgent(跨平台 ai_* 方法 + RPC)
│ ├── _pytest_plugin.py # midscene_agent / midscene_web_agent fixture + pytest11 入口
│ └── _pytest_support.py # pytest 插件共享逻辑(失败截图/报告)
└── _node_driver/
├── android/ # package.json(@midscene/android) + service.js
└── web/ # package.json(@midscene/web + puppeteer) + service.js
# 运行时缓存(不在 pip 包内,android/web 共享 Node 运行时):
# ~/.midscene/node_runtime/ ← Node + npm
# ~/.midscene/android/node_service/ ← npm install @midscene/android
# ~/.midscene/web/node_service/ ← npm install @midscene/web + puppeteer
tests/ # Android + Web 测试集中在根目录
tools/
├── build_wheel.py # 构建 py3-none-any wheel + sdist
└── upload_pypi.py # 检查 dist/ 并上传 PyPI
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file midscene-0.1.2.tar.gz.
File metadata
- Download URL: midscene-0.1.2.tar.gz
- Upload date:
- Size: 59.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
21f1632678cf842668a7043c40ca27b1ae9205ffddc0758cc1aeee339eab8440
|
|
| MD5 |
a1df129023dcb3cb0f4344125e02ca03
|
|
| BLAKE2b-256 |
911c511b6aa2766de096d1f721bc2d6b5ebbf03a812f911e01d4bda6d2ab94fa
|
File details
Details for the file midscene-0.1.2-py3-none-any.whl.
File metadata
- Download URL: midscene-0.1.2-py3-none-any.whl
- Upload date:
- Size: 49.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fa9ef4a86c890c71a15ca36cff530a41f955cea5d74b6e68c7d6c50d0a4df14a
|
|
| MD5 |
d4c52a8fe1e234ef2c0d1bcf8394a35f
|
|
| BLAKE2b-256 |
39ac856abc43f8c070a356a23d09f77a684299c11ea26e75dc4cea23b492d495
|