Maestro 移动 UI 自动化测试入门教程
Maestro 移动 UI 自动化测试入门教程本文带你从零开始掌握 Maestro —— 一款开源的跨平台移动 UI 自动化测试框架。涵盖安装配置、YAML 测试流编写、核心命令、选择器、高级用法及实战案例让你 10 分钟写出第一条自动化测试。一、Maestro 是什么Maestro 是一款开源的端到端移动 UI 自动化测试框架支持Android、iOS 和 Web应用包括 React Native、Flutter 和混合应用。它的核心理念是拥抱不稳定性通过人类可读的 YAML 语法和解释型执行引擎让测试编写变得简单高效。与传统自动化框架如 Appium、XCUITest相比Maestro 最大的优势在于极低的上手门槛—— 你不需要编写复杂的代码只需用 YAML 描述用户操作即可。核心特性特性说明跨平台一套 YAML 语法同时测试 Android、iOS 和 Web 应用人类可读的 YAML用launchApp、tapOn、assertVisible等命令表达交互内置抗抖动自动等待 UI 稳定无需手动写sleep()解释型执行无需编译修改即运行快速迭代智能元素定位默认使用 Accessibility Tree模拟真实用户视角JavaScript 集成在 YAML 中内嵌 JS 处理复杂逻辑、调用外部 API测试录制自动将执行过程录制成 MP4 视频Maestro Studio可视化测试构建器支持录制交互、检查元素为什么选择 Maestro学习曲线低5 分钟写出第一条测试无需编程经验维护成本低YAML 语法直观测试即文档稳定性高内置智能等待机制减少 flaky tests生态完善支持本地测试、CI/CD 集成、云端测试二、环境准备与安装2.1 前置条件安装 Maestro 前请确保系统已安装Java 17 或更高版本。验证 Java 版本java-version如果未安装 Java推荐使用 Temurin JDK 或 Oracle JDK 安装。确保JAVA_HOME环境变量指向 Java 17 的安装路径。2.2 安装 Maestro CLImacOS 安装方式一使用 curl 脚本安装curl-fsSLhttps://get.maestro.mobile.dev|bash方式二使用 Homebrew 安装brew tap mobile-dev-inc/tap brew trust--formulamobile-dev-inc/tap/maestro brewinstallmobile-dev-inc/tap/maestromacOS 用户还需安装最新版 Xcode 和 Xcode Command Line Tools用于 iOS 模拟器测试。Windows 安装前往 Maestro GitHub Releases 下载最新的maestro.zip解压到稳定目录如C:\maestro将 Maestro 的bin目录添加到系统 PATHsetx PATH%PATH%;C:\maestro\bin重启终端使配置生效Linux 安装curl-fsSLhttps://get.maestro.mobile.dev|bash安装完成后默认安装路径为$HOME/.maestro/bin。如果maestro命令不可用手动添加 PATHexportPATH$PATH:$HOME/.maestro/bin2.3 验证安装运行以下命令若显示帮助信息则安装成功maestro--help2.4 准备测试设备Maestro 需要一个正在运行的设备或模拟器来执行测试。Android 测试打开 Android Studio进入 Virtual Device Manager启动一个虚拟设备如 Pixel 8等待设备启动到主屏幕iOS 测试打开 Xcode启动 iOS 模拟器如 iPhone 15确保模拟器处于运行状态三、第一个测试10 分钟快速上手3.1 创建测试文件创建一个新目录并新建contacts.yaml文件appId:com.google.android.contacts----launchApp:clearState:true-tapOn:Allow-tapOn:Create contact-tapOn:First name-inputText:John-tapOn:Last name-inputText:Doe-tapOn:Company-inputText:Maestro-tapOn:1-inputText:111-111-1111-tapOn:Save-back3.2 运行测试确保模拟器正在运行然后执行maestrotestcontacts.yamlMaestro 会连接到模拟器按顺序执行每个步骤。终端会显示实时进度报告你可以在模拟器上看到自动化操作的过程。3.3 测试录像在 Flow 中加入录像命令执行后会在当前目录生成recording.mp4appId:com.google.android.contacts----launchApp:clearState:true-startRecording:recording# 开始录像-tapOn:Create contact-tapOn:First name-inputText:John-tapOn:Last name-inputText:Doe-tapOn:Save-stopRecording# 停止录像生成 recording.mp4四、Flow 结构详解Maestro 的测试文件称为Flow使用 YAML 格式编写。一个标准的 Flow 由两部分组成用---分隔# 配置区 appId:com.example.app# 必填被测应用的包名/Bundle IDname:登录测试# 选填Flow 的自定义名称tags:# 选填标签用于筛选测试-smoke-test-loginenv:# 选填环境变量USERNAME:userexample.comPASSWORD:123456---# 命令区 -launchApp# 启动应用-tapOn:Username# 点击用户名输入框-inputText:${USERNAME}# 输入环境变量-tapOn:Password-inputText:${PASSWORD}-tapOn:Login# 点击登录-assertVisible:Welcome# 断言欢迎信息可见配置区字段说明字段必填说明appId是被测应用的包名Android或 Bundle IDiOSname否Flow 的显示名称会出现在测试报告中tags否标签列表配合--include-tags/--exclude-tags使用env否环境变量映射在命令区通过${变量名}引用五、核心命令速查5.1 常用命令一览命令说明示例launchApp启动应用- launchAppkillApp强制关闭应用- killApptapOn点击元素- tapOn: 登录doubleTapOn双击元素- doubleTapOn: 头像longPressOn长按元素- longPressOn: 消息inputText输入文本- inputText: helloeraseText删除文本- eraseText: 10swipe滑动操作- swipe: { direction: UP }scroll滚动- scrollscrollUntilVisible滚动直到元素可见- scrollUntilVisible: { element: 加载更多 }back返回Android- backpressKey按键- pressKey: EnterhideKeyboard隐藏键盘- hideKeyboardassertVisible断言元素可见- assertVisible: 欢迎assertNotVisible断言元素不可见- assertNotVisible: 错误takeScreenshot截图- takeScreenshot: resultwaitForAnimationToEnd等待动画结束- waitForAnimationToEndopenLink打开链接- openLink: https://example.com5.2 命令详细用法launchApp —— 启动应用# 基本启动-launchApp# 启动并清除应用状态重新开始-launchApp:clearState:true# 启动并清除权限设置-launchApp:clearState:trueclearKeychain:truetapOn —— 点击元素# 通过文本点击-tapOn:登录# 通过 ID 点击-tapOn:id:login_button# 通过文本点击指定第几个匹配项-tapOn:text:删除index:2# 多条件组合定位-tapOn:text:提交enabled:truebelow:个人信息inputText —— 输入文本# 直接输入-inputText:hello world# 输入环境变量-inputText:${USERNAME}# 输入数字-inputText:13800138000swipe —— 滑动操作# 方向滑动-swipe:direction:UP# 指定百分比区域滑动-swipe:start:50%,80%end:50%,20%# 元素间滑动-swipe:from:id:item_1to:id:item_5assertVisible —— 断言元素可见# 简单断言-assertVisible:登录成功# 带超时的断言-extendedWaitUntil:visible:欢迎页面timeout:10000# 可选断言不通过也不会失败-assertVisible:text:弹窗广告optional:true六、选择器Selectors选择器是 Maestro 定位 UI 元素的核心机制。Maestro 默认使用Accessibility Tree无障碍树从用户视角来识别界面元素。6.1 选择器类型文本选择器最常用# 简写形式-tapOn:Login# 完整形式-tapOn:text:Logintext默认支持正则表达式可用于匹配动态文本。ID 选择器最稳定-tapOn:id:submit_buttonID 是 Accessibility Identifier不受语言切换影响适合多语言应用。索引选择器当有多个匹配元素时用index指定第几个从 0 开始-tapOn:text:删除index:1# 点击第 2 个删除按钮坐标选择器-tapOn:point:50%,50%6.2 关系选择器当元素本身没有唯一标识时可以用相对位置来定位# 点击密码下方的元素-tapOn:below:密码# 点击标题上方的元素-tapOn:above:标题# 点击某个父容器内的元素-tapOn:text:删除childOf:id:list_item6.3 状态选择器# 只在元素可点击时操作-tapOn:text:提交enabled:true# 检查勾选状态-assertVisible:text:记住密码checked:true# 检查焦点状态-assertVisible:text:搜索框focused:true6.4 选择器最佳实践场景推荐策略有固定文本的按钮/标签使用text选择器直观且自文档化图标、图片等无文字元素使用idAccessibility Identifier跨语言稳定动态文本或无唯一标识用关系选择器above/below锚定位置文本部分变化使用正则text: 订单.*成功等待异步加载完成在选择器中加enabled: true自动等待可交互状态七、高级用法7.1 子 FlowSubflows将通用操作抽取为子 Flow实现复用。例如创建login.yaml# login.yamlappId:com.example.app----tapOn:用户名-inputText:${USERNAME}-tapOn:密码-inputText:${PASSWORD}-tapOn:登录-assertVisible:首页在其他 Flow 中调用# main_flow.yamlappId:com.example.app----launchApp-runFlow:login.yaml# 调用子 Flow-tapOn:我的订单-assertVisible:订单列表7.2 条件执行使用runFlow配合when条件来控制执行逻辑-runFlow:when:visible:升级提示commands:-tapOn:稍后7.3 循环-repeat:times:3commands:-tapOn:下一个-assertVisible:图片7.4 JavaScript 集成在 YAML 中直接执行 JavaScript处理复杂逻辑appId:com.example.app----evalScript:${output.date new Date().toISOString()}-tapOn:日期-inputText:${output.date}发起 HTTP 请求-evalScript:${output.response http.get(https://api.example.com/test-data)}-inputText:${output.response.body.id}7.5 重试机制对不稳定操作使用retry-retry:maxRetries:3commands:-tapOn:刷新-assertVisible:数据加载完成八、CLI 命令参考8.1 常用命令命令说明maestro test flow.yaml执行测试maestro test -c flow.yaml连续模式文件变更自动重跑maestro test --include-tagssmoke .只运行带smoke标签的 Flowmaestro test --formatJUNIT .生成 JUnit 格式报告maestro start-device --platformandroid启动 Android 模拟器maestro list-devices列出本地可用设备maestro record flow.yaml录制测试执行过程maestro download-samples下载官方示例maestro hierarchy打印当前应用的视图层级8.2 test 命令常用选项选项说明-c, --continuous连续模式监控文件变化自动重跑-e, --envKEYVALUE设置环境变量--include-tagstags只运行包含指定标签的 Flow--exclude-tagstags排除包含指定标签的 Flow--formatFORMAT报告格式JUNIT、HTML、NOOP--outputPATH指定报告输出路径--deviceUDID指定运行的设备 ID--platformPLATFORM指定平台android、ios、web-s, --shardsCOUNT并行分片执行8.3 实用示例# 运行单个 Flowmaestrotestlogin.yaml# 运行目录下所有 Flowmaestrotest./flows/# 只运行冒烟测试maestrotest--include-tagssmoke ./flows/# 连续开发模式maestrotest-clogin.yaml# 生成 HTML 报告maestrotest--formatHTML--outputreport.html ./flows/# 传入环境变量maestrotest-eUSERNAMEtesttest.com-ePASSWORD123456login.yaml# 在指定设备上运行maestro--deviceemulator-5554testlogin.yaml# 启动设备maestro start-device--platformandroid --device-osandroid-34九、实战案例登录功能测试下面通过一个完整的登录测试场景综合运用前面学到的知识。9.1 测试场景启动应用处理首次启动的权限弹窗输入用户名和密码点击登录验证登录成功退出登录9.2 测试文件# login_test.yamlappId:com.example.myappname:登录功能测试tags:-smoke-loginenv:USERNAME:testuserexample.comPASSWORD:Test1234---# 启动应用清除状态-launchApp:clearState:true# 处理可能出现的权限弹窗-runFlow:when:visible:允许commands:-tapOn:允许# 进入登录页面-tapOn:登录# 输入用户名-tapOn:id:username_input-inputText:${USERNAME}# 输入密码-tapOn:id:password_input-inputText:${PASSWORD}# 点击登录按钮-tapOn:text:登录index:1enabled:true# 验证登录成功-assertVisible:首页-takeScreenshot:login_success# 退出登录-tapOn:我的-scroll-tapOn:退出登录-tapOn:确认-assertVisible:登录9.3 运行测试# 基本运行maestrotestlogin_test.yaml# 生成 JUnit 报告用于 CI/CDmaestrotest--formatJUNIT--outputreport.xml login_test.yaml# 连续模式开发调试maestrotest-clogin_test.yaml十、Maestro Studio 可视化工具Maestro Studio 是一个轻量级的可视化测试构建工具帮助你快速编写测试。启动 Maestro Studiomaestro studio核心功能功能说明视觉流构建器点击界面元素自动生成对应命令元素检查器查看元素的 ID、文本、层级等属性实时预览在模拟器上操作实时生成 YAMLAI 辅助用自然语言描述操作AI 生成命令对于初学者推荐先用 Maestro Studio 录制操作生成基础 Flow再手动优化 YAML。十一、测试优化与最佳实践11.1 减少测试 flaky善用enabled: true在点击按钮前确保它可交互使用optional: true对可能出现的弹窗做可选断言避免硬等待用assertVisible代替sleep合理使用retry对网络相关操作加重试# 处理可能出现的弹窗-runFlow:when:visible:更新提示commands:-tapOn:稍后提醒# 等待元素可点击再操作-tapOn:text:提交enabled:true11.2 测试组织结构推荐的目录结构project/ ├── config.yaml # 全局配置 ├── flows/ │ ├── login/ # 按功能模块分组 │ │ ├── login_success.yaml │ │ └── login_failure.yaml │ ├── search/ │ │ └── search_flow.yaml │ └── checkout/ │ └── checkout_flow.yaml ├── subflows/ # 可复用的子 Flow │ ├── login.yaml │ └── navigate_home.yaml └── reports/ # 测试报告输出11.3 使用 config.yaml 统一配置在项目根目录创建config.yaml设置全局行为# config.yamlappId:com.example.myapp# 测试执行配置flowOrder:-subflows/login.yaml-flows/# 全局环境变量env:API_BASE_URL:https://test-api.example.com运行时指定配置文件maestrotest--configconfig.yaml ./flows/11.4 CI/CD 集成在 GitHub Actions 中集成 Maestro# .github/workflows/test.ymlname:Maestro Testson:[push,pull_request]jobs:test:runs-on:macOS-lateststeps:-uses:actions/checkoutv4-uses:reactivecircus/android-emulator-runnerv2with:api-level:34script:|curl -fsSL https://get.maestro.mobile.dev | bash export PATH$PATH:$HOME/.maestro/bin maestro test --formatJUNIT --outputreport.xml ./flows/-uses:actions/upload-artifactv4with:name:test-reportpath:report.xml十二、常见问题Q1元素找不到怎么办使用maestro hierarchy命令查看当前界面的视图层级用 Maestro Studio 的元素检查器查看元素属性尝试使用不同的选择器text、id、关系选择器检查元素是否在 WebView 或 Flutter 渲染层中Q2测试运行超时设置启动超时环境变量exportMAESTRO_DRIVER_STARTUP_TIMEOUT180000Q3如何测试 Flutter 应用Maestro 原生支持 Flutter。确保 Flutter 应用启用了语义信息Semantics然后在 Flow 中正常使用选择器即可。Q4如何处理系统弹窗使用runFlow条件执行来处理-runFlow:when:visible:Allowcommands:-tapOn:AllowQ5如何在多台设备上并行测试使用--shards选项maestrotest--shards3./flows/总结Maestro 以其简洁的 YAML 语法、内置的抗抖动机制和跨平台支持大幅降低了移动 UI 自动化测试的门槛。本文涵盖了从安装到实战的完整流程安装配置一行命令完成安装Java 17 即可运行快速上手YAML 描述操作maestro test一键执行核心命令launchApp、tapOn、inputText、assertVisible等选择器文本、ID、关系、状态等多维定位策略高级用法子 Flow 复用、条件执行、循环、JS 集成工程化标签筛选、报告生成、CI/CD 集成对于想要快速建立移动 UI 自动化测试体系的团队Maestro 是一个非常值得尝试的选择。建议从简单的冒烟测试开始逐步扩展到完整的回归测试套件。官方资源官方文档https://docs.maestro.devGitHub 仓库https://github.com/mobile-dev-inc/Maestro社区 Slackhttps://slack.maestro.dev

相关新闻

智能降维在量化交易中的应用:解决高维数据过拟合问题

智能降维在量化交易中的应用:解决高维数据过拟合问题

在金融科技和人工智能的交汇点上,量化投资正经历一场深刻的变革。很多人以为量化交易就是写几个策略、跑回测、然后自动化执行,但真正的挑战往往隐藏在数据维度爆炸和模型过拟合的陷阱里。Alex Wang作为业内资深专家,近期提出的“智能降维”理…

2026/10/15 5:24:19 阅读更多 →
TI EMAC/MDIO中断管理实战:从寄存器到驱动避坑指南

TI EMAC/MDIO中断管理实战:从寄存器到驱动避坑指南

1. 从寄存器手册到实战:理解EMAC/MDIO中断管理的核心逻辑搞嵌入式网络驱动,尤其是像TI这种大厂的复杂外设,最头疼的往往不是写数据收发流程,而是把那一大本寄存器手册里的中断机制给整明白。手册里每个比特位都给你列得清清楚楚&a…

2026/10/13 23:50:19 阅读更多 →
不会写代码的人,终于迎来了属于自己的开发时代

不会写代码的人,终于迎来了属于自己的开发时代

每次参加各种科技大会,我都会留意会场里的一个特殊区域:那里没有炫目的舞台,没有重量级嘉宾,也没有热闹的抽奖,却总能吸引很多人的目光。这就是黑客松(Hackathon)现场。这些年,无论是…

2026/10/4 22:14:39 阅读更多 →

最新新闻

虚拟机Ubuntu部署OpenClaw与Ollama:搭建私有本地AI代理

虚拟机Ubuntu部署OpenClaw与Ollama:搭建私有本地AI代理

上个月我又被一份云端 API 账单气到不行:只是让 AI 助手帮我写点小脚本、整理几份日志,月底一算居然够我吃好几顿火锅。更别扭的是,工作内容还要先经过别人家的服务器转一圈,数据隐私这块始终心里没底。于是我开始认真琢磨一件事—…

2026/10/15 5:24:10 阅读更多 →
自动化脚本的八种静默失败:每一个都“看起来成功了“

自动化脚本的八种静默失败:每一个都“看起来成功了“

写在前面调试里最贵的一类 bug,不是抛异常的,而是返回成功、显示在跑、日志正常,但什么都没发生的。本文八个案例全部来自同一台 Windows 机器上真实运行的一整套自动化设施(计划任务守护 浏览器自动化 Vue 表单操作&#xff09…

2026/10/15 5:24:10 阅读更多 →
Keras激活函数可视化:用图像理解Sigmoid、ReLU与训练难题

Keras激活函数可视化:用图像理解Sigmoid、ReLU与训练难题

有一段时间,我做某个图像分类小项目,训练曲线一直下不去。层数、学习率、优化器都调过了,最后才怀疑到激活函数头上。说实话,激活函数的公式我都能背,但真到选型时,帮上忙的居然是“看图像”。这次我用 Pyt…

2026/10/15 5:24:10 阅读更多 →
DPU深度解析:BlueField-2如何卸载网络、存储与安全

DPU深度解析:BlueField-2如何卸载网络、存储与安全

简介:这是一份面向数据中心架构师、云平台管理员与虚拟化开发者的 NVIDIA BlueField-2 DPU 官方解决方案,PDF 格式呈现。文档系统阐述第二代 DPU 如何将安全、存储、网络等基础设施任务从 CPU 卸载到 Arm 核心与专用加速引擎,覆盖裸金属云、虚…

2026/10/15 5:24:10 阅读更多 →
【新闻】链上共生,芯向未来!艾为电子战配投资粤芯半导体,产业链布局纵深推进

【新闻】链上共生,芯向未来!艾为电子战配投资粤芯半导体,产业链布局纵深推进

10月13日,粤芯半导体(股票代码301660)正式登陆深交所创业板。艾为电子作为粤芯半导体首次公开发行股票战略配售投资者之一参与本次发行,以资本为纽带、产业协同为牵引,向上游晶圆制造关键环节纵深延伸,产业…

2026/10/15 5:24:10 阅读更多 →
从模型轻量化到TFLite部署:边缘设备上的TensorFlow完整实践指南

从模型轻量化到TFLite部署:边缘设备上的TensorFlow完整实践指南

1. 边缘计算的落地困境与TensorFlow的角色先聊点实际的。这两年“边缘计算”四个字被各家厂商反复重提,趋势确实在那,但真正动手做过的人应该都有体会:把模型跑在云端和跑在边缘设备上,完完全全是两种工作量级。云端GPU随手就能跑…

2026/10/15 5:23:10 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →