Unity ET框架与Test Runner集成:构建异步ECS架构的自动化测试方案
1. 项目概述为什么我们需要新的测试范式在Unity项目开发中尤其是涉及复杂业务逻辑和网络同步的游戏或应用测试一直是个老大难问题。传统的单元测试往往只针对孤立的类和方法而集成测试和端到端测试的搭建成本又高得吓人。很多团队最终陷入“手动点点点”的泥潭或者写了一大堆难以维护、运行缓慢的测试代码。我自己在多个中大型Unity项目里摸爬滚打深刻体会到一套好的测试框架不仅仅是“写测试”更是关乎开发效率、代码质量和团队协作的基石。最近我在一个基于ET框架的服务端-客户端一体化项目中尝试将ET框架与Unity官方的Test Runner进行深度集成摸索出了一套新的测试工作流。ET框架本身是一个基于ECS实体-组件-系统和Actor模型的单线程异步处理框架在服务端开发中非常流行其清晰的逻辑分层和热更新能力是巨大优势。但它的异步特性和独特的生命周期让传统的、基于MonoBehaviour的Unity测试方法几乎无从下手。Test Runner虽然是Unity的亲儿子功能强大但默认主要面向的是编辑器和运行时环境下的常规代码测试。将这两者结合核心目标就是为ET框架的异步逻辑、网络消息、组件系统等提供一套能在Unity编辑器内一键运行、可重复、且能集成到CI/CD流水线中的自动化测试方案。这不仅仅是技术上的缝合更是一种开发范式的转变——让我们能用写单元测试的效率和信心去验证那些过去只能靠人工联调才能确认的复杂交互逻辑。2. 核心思路拆解ET框架与Test Runner的融合点要实现“无缝集成”我们不能简单地把ET的代码扔进Test Runner里跑那样肯定会因为生命周期、初始化顺序等问题而崩溃。我们需要深入理解两者的运作机制找到关键的结合点。2.1 ET框架的测试挑战ET框架的核心运行依赖于一个Game对象或类似的入口类来启动整个引擎管理所有的Scene、Entity和System。它的生命周期是自驱动的通常由一条主线程的异步循环如EventSystem来推动。这带来了几个测试难点环境初始化复杂启动一个完整的ET环境需要初始化一大堆World、Root、Scene加载配置表注册组件和系统。这个过程在测试中必须被精确地模拟和控制。强异步依赖ET中几乎所有的逻辑都是异步的比如等待一个网络响应、一个定时器到期或者一个事件被触发。传统的[Test]方法默认是同步的无法直接await一个ET的异步方法。资源与依赖隔离测试不应该依赖真实的网络连接、数据库或复杂的资源加载。我们需要能够Mock模拟这些外部依赖例如模拟一个网络会话(Session)或一个数据库查询结果。2.2 Unity Test Runner的能力与扩展Unity Test Runner基于NUnit提供了两种主要的测试模式Edit Mode Tests在编辑器环境下运行不进入Play模式。速度快适合测试不依赖游戏运行时的工具类、数据结构和编辑器扩展逻辑。Play Mode Tests会启动一个独立的Unity Player可以是独立运行或特定平台测试依赖于游戏运行时如GameObject、MonoBehaviour、物理系统的代码。对于ET框架Play Mode Tests是我们的主战场因为ET的完整生命周期需要Unity的运行时环境。但Test Runner默认并不理解ET的“世界”。因此集成的核心思路是利用Test Runner的[SetUp]和[TearDown]特性在每一个测试用例开始前为我们手动创建并启动一个纯净的、用于测试的ET运行环境在测试结束后完整地清理和销毁它。此外NUnit提供了一个强大的[UnityTest]属性。与普通的[Test]不同[UnityTest]方法可以返回一个IEnumerator这意味着我们可以在方法内部使用yield return来等待一帧或者等待某个异步操作完成。这正是我们处理ET异步逻辑的钥匙——我们可以通过yield return来等待ET框架内部的一个异步任务完成信号。2.3 整体架构设计基于以上分析我设计的集成架构主要包含以下几个层次测试根节点 (Test Bootstrap)一个放在Assets/Tests目录下的MonoBehaviour它负责在Play Mode测试启动时全局初始化一次ET框架的核心资源如代码配置、协议类型等。这个初始化通常只做一次。测试场景 (Test Scene)创建一个专用于测试的.unity场景。这个场景非常“干净”可能只包含一个用于挂载测试启动脚本的空GameObject。Test Runner可以配置为在运行Play Mode测试前自动加载这个场景。测试夹具 (Test Fixture)对应于NUnit的[SetUp]和[TearDown]。我们创建一个基类比如ETTestBase。每个测试类继承它。在[SetUp]方法中我们创建新的ETWorld、RootScene并注册测试所需的系统。在[TearDown]中我们调用World.Dispose()来销毁整个世界确保测试之间完全隔离没有残留状态污染。异步测试适配器在ETTestBase中提供一些辅助方法用于将ET的ETTask或async方法适配到[UnityTest]的IEnumerator中。例如一个WaitForETTask方法内部通过while (!task.IsCompleted) yield return null;来等待任务完成。这样每个测试用例都运行在一个独立沙盒中前一个测试的Entity不会影响到后一个保证了测试的独立性和可重复性。3. 环境搭建与项目配置实操理论说完了我们动手搭一个。假设你已经有一个基础的Unity项目建议2021.3 LTS或更新版本并导入了ET框架。3.1 创建测试专用程序集首先为了避免测试代码被打进正式包也为了更好的依赖管理我们使用Assembly Definition (asmdef) 文件。在Assets目录下创建Tests文件夹。在Tests文件夹内右键 -Create-Assembly Definition命名为Game.ET.Tests。选中这个Game.ET.Tests.asmdef文件在Inspector面板中在Assembly Definition References中添加引用nunit.framework.dll,UnityEngine.TestRunner。在Version Defines部分确保添加了UNITY_INCLUDE_TESTS通常Test Runner会自动处理但检查一下更保险。在References中引用你的游戏主逻辑程序集例如Game.ET.Core以及ET框架的核心程序集。注意这里有个关键点。你的游戏主逻辑程序集被测试对象不能直接引用nunit或UnityEngine.TestRunner。否则这些测试代码会被包含进最终的产品构建中。测试程序集是单向引用关系测试程序集引用产品代码和测试框架。3.2 配置Test Runner运行设置打开Window General Test Runner。切换到PlayMode标签页。在Test Runner窗口的右上角点击三个小点的菜单图标选择Edit Playmode Test Runner Settings不同Unity版本路径可能略有不同。在弹出的设置中你可以指定一个Test Scene。我们创建一个在Assets/Tests下创建一个新场景命名为TestEnvironment.unity。场景里可以什么都不放或者放一个空的GameObject命名为TestRunnerBootstrap。回到Test Runner设置将这个TestEnvironment.unity场景拖入指定区域。这样每次运行Play Mode测试前都会自动加载这个干净的场景。3.3 编写测试环境启动器 (TestBootstrap)在TestEnvironment.unity场景中我们创建一个GameObject并挂载一个脚本TestBootstrap.cs。这个脚本的职责是在Play Mode测试开始时执行一次性的全局初始化。using UnityEngine; public class TestBootstrap : MonoBehaviour { // 使用RuntimeInitializeOnLoadMethod确保在运行时最早执行 [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] private static void InitializeBeforeSceneLoad() { // 1. 初始化ET框架的全局代码配置 // 这里调用ET框架提供的初始化方法例如注册所有组件类型、协议类型等。 // 假设ET框架有一个Game.Enter方法或类似入口 // Game.Enter(); // 2. 初始化资源管理测试环境可能需要使用虚拟的或本地的资源加载器 // ResourcesComponent.Instance.LoadAll(); Debug.Log([TestBootstrap] ET Framework global initialization for tests completed.); } void Start() { // 这个Start方法可能不会在Test Runner环境下被调用取决于执行顺序。 // 主要依赖上面的静态方法。 DontDestroyOnLoad(this.gameObject); // 保持这个启动器在整个测试过程中存在 } }这个启动器的作用是模拟游戏启动时的那一套初始化流程但只为测试服务。关键是[RuntimeInitializeOnLoadMethod]这个属性它保证了代码在场景加载前执行顺序可控。4. 构建可复用的测试基类 (ETTestBase)这是整个集成方案的核心。我们将创建一个所有ET相关测试类都继承的基类。using System.Collections; using NUnit.Framework; using UnityEngine.TestTools; using ET; namespace ET.Tests { public class ETTestBase { protected World World { get; private set; } protected Scene RootScene { get; private set; } // 每个测试用例开始前运行 [SetUp] public virtual void SetUp() { // 1. 创建一个新的World这是ET的根容器 World new World(); // 2. 设置World的更新器为Test模式可能需要自定义避免依赖Unity的Update // World.AddSingletonITimeInfo, TestTimeInfo(); // 3. 创建根Scene RootScene World.AddChildScene(); RootScene.Name RootScene_Test; // 4. 注册测试所需的核心单例组件到RootScene // 例如RootScene.AddComponentObjectPool(); // RootScene.AddComponentIdGenerater(); // RootScene.AddComponentEventSystem(); // 5. 注册你自定义的、测试需要的System // World.AddSystemYourSystemType(); Debug.Log($[ETTestBase] Test World and Scene initialized. Test: {TestContext.CurrentContext.Test.Name}); } // 每个测试用例结束后运行 [TearDown] public virtual void TearDown() { if (World ! null !World.IsDisposed) { // 销毁World这会递归销毁所有Entity和Component World.Dispose(); World null; RootScene null; } Debug.Log($[ETTestBase] Test World disposed. Test: {TestContext.CurrentContext.Test.Name}); } // 一个辅助协程用于在UnityTest中等待ETTask完成 protected IEnumerator WaitForETTask(ETTask task) { while (!task.IsCompleted) { yield return null; // 等待一帧 } // 如果任务有异常在这里可以抛出让测试失败 if (task.IsFaulted) { throw task.Exception; } } // 另一个辅助方法等待若干帧模拟时间流逝 protected IEnumerator WaitForFrames(int frameCount) { for (int i 0; i frameCount; i) { yield return null; } } } }这个基类为每个测试建立了一个独立的ET沙箱。SetUp就是建房子TearDown就是拆房子保证下个测试有一块干净的地皮。5. 编写第一个集成测试用例现在我们来针对一个具体的ET功能写测试。假设我们有一个简单的HealthComponent和一个DamageSystem。// 被测代码 (示例) namespace ET { // 生命值组件 public class HealthComponent : Entity, IAwake, IDestroy { public int HP { get; set; } 100; public bool IsDead HP 0; } // 伤害系统 public static class DamageSystem { public static ETTask ApplyDamage(this HealthComponent health, int damage) { health.HP - damage; if (health.IsDead) { // 触发死亡事件等... await health.GetParentUnit().PublishAsync(new DeadEvent()); } await ETTask.CompletedTask; } } }对应的测试类如下using System.Collections; using NUnit.Framework; using UnityEngine.TestTools; using ET; namespace ET.Tests { // 继承我们刚才写的测试基类 public class HealthSystemTests : ETTestBase { // 一个普通的同步测试 [Test] public void HealthComponent_Initialization_ShouldHaveFullHP() { // Arrange Act var health RootScene.AddChildHealthComponent(); // Assert Assert.AreEqual(100, health.HP); Assert.IsFalse(health.IsDead); // 测试结束TearDown会自动清理health实体 } // 一个测试异步DamageSystem的UnityTest [UnityTest] public IEnumerator DamageSystem_ApplyDamage_ShouldReduceHP() { // Arrange var health RootScene.AddChildHealthComponent(); int initialHP health.HP; int damageAmount 30; // Act // 调用异步方法得到一个ETTask ETTask damageTask health.ApplyDamage(damageAmount); // 使用基类的辅助方法等待任务完成 yield return WaitForETTask(damageTask); // Assert Assert.AreEqual(initialHP - damageAmount, health.HP); Assert.IsFalse(health.IsDead); } [UnityTest] public IEnumerator DamageSystem_ApplyLethalDamage_ShouldMarkAsDead() { // Arrange var health RootScene.AddChildHealthComponent(); bool deadEventTriggered false; // 订阅事件来验证系统行为需要你的事件系统支持测试环境下的订阅 // RootScene.GetComponentEventSystem().AddListenerDeadEvent((e) deadEventTriggered true); // Act ETTask damageTask health.ApplyDamage(150); // 造成过量伤害 yield return WaitForETTask(damageTask); // 可能还需要等待一帧让事件系统处理 yield return null; // Assert Assert.IsTrue(health.IsDead); // Assert.IsTrue(deadEventTriggered, DeadEvent should be published.); } } }在Test Runner窗口中你可以看到这些测试用例。点击Run AllTest Runner会加载测试场景然后依次执行每个测试。绿色的对勾表示测试通过。这种反馈是即时且清晰的。6. 模拟Mock外部依赖与进阶技巧真实的ET系统不可能孤立运行它需要与网络、数据库、资源服务等交互。在测试中我们必须隔离这些不稳定或不可控的外部因素。6.1 模拟网络会话 (Mock Session)假设你有一个NetService需要Session来发送消息。在测试中我们可以创建一个MockSession。public class MockSession : Entity, ISession { // 实现ISession接口的必要方法 public long Id { get; set; } public MemoryStream LastSentStream { get; private set; } // 记录最后发送的消息 public bool IsDisposed { get; private set; } public void Send(IMessage message) { // 不真的发送只是记录下消息内容供测试断言 LastSentStream MessageSerializeHelper.SerializeTo(message); Debug.Log($[MockSession] Message recorded: {message.GetType().Name}); } public void Dispose() { IsDisposed true; } // ... 其他接口实现如SendAsync可以返回一个完成的ETTask }在测试的SetUp中你可以将这个MockSession添加到某个测试用的Unit实体上替换掉真实的网络层。这样当你测试一个需要发送网络消息的逻辑时就可以断言MockSession.LastSentStream里是否包含了预期的消息。6.2 使用接口与依赖注入更优雅的方式是让业务逻辑依赖于接口而非具体实现。例如定义一个IResourceService接口真实游戏中使用AssetBundle实现测试中则使用MockResourceService从本地内存加载数据。在ET框架中可以通过在RootScene上添加不同的单例组件来实现这种“服务”的替换。在测试基类的SetUp中注册Mock服务在产品代码中注册真实服务。6.3 测试异步流程与超时控制有些异步操作可能因为逻辑错误而永远无法完成。为了防止测试卡死我们需要为[UnityTest]添加超时机制。NUnit的[UnityTest]属性本身可以结合[Timeout(milliseconds)]使用。[UnityTest] [Timeout(5000)] // 5秒超时 public IEnumerator LongRunningAsyncOperation_ShouldCompleteWithinTimeout() { // 执行一个可能很长的异步操作 ETTask longTask SomeLongRunningETMethod(); yield return WaitForETTask(longTask); Assert.IsTrue(longTask.IsCompletedSuccessfully); }如果操作超过5秒未完成测试会自动失败并提示超时。7. 常见问题排查与实战心得在实际集成过程中我踩过不少坑这里总结一下问题1测试运行时ET的EventSystem报空引用或未初始化错误。排查检查测试基类SetUp中是否在创建World和RootScene后正确初始化了EventSystem单例。通常需要执行World.AddSingletonEventSystem()或RootScene.AddComponentEventSystem()取决于ET版本。心得ET框架内各单例的初始化顺序非常关键。最好在测试基类里完全复制一份游戏启动时精简版的初始化流程。问题2[UnityTest]协程执行完了但ET的异步回调如Timer、事件还没触发导致断言失败。排查ET的异步回调可能在下一帧或某个特定的系统更新中执行。在yield return WaitForETTask(someTask);之后再加一句yield return null;或yield return WaitForFrames(1);给ET框架一帧的时间去处理内部队列。心得对于涉及ET内部EventSystem.Update或TimerComponent.Update的逻辑在测试末尾yield return null一下是个好习惯。问题3多个测试用例并行运行虽然NUnit默认是顺序的但CI环境可能配置并行导致状态污染。排查确保你的测试基类ETTestBase中的World和RootScene是实例字段非静态并且[SetUp]和[TearDown]是实例方法。这样NUnit会为每个测试类实例创建一个新的对象天然隔离。绝对不要在测试中使用静态变量来共享状态。心得每个测试都应该是独立的、幂等的。依赖静态状态是测试腐化的开始。问题4测试在CI服务器上如GitLab Runner, Jenkins失败但在本地编辑器里成功。排查资源路径测试中如果有加载本地配置文件如Json、Bytes确保使用Application.dataPath等相对路径或者将测试资源放在Resources文件夹并使用Resources.Load。CI环境的工作目录可能不同。平台差异如果你在CI上针对不同平台如Standalone Linux, Android进行测试注意某些Unity API或ET的底层实现可能有差异。Mock掉所有平台相关的调用。初始化顺序CI上可能是“无头模式”运行测试一些依赖于图形设备或输入系统的初始化可能会失败。确保测试环境的初始化不依赖这些。心得尽早将测试集成到CI流水线中能暴露出很多环境依赖问题。使用Unity的-batchmode和-runTests命令行参数来运行Test Runner。问题5测试运行速度太慢。排查每个测试都重新初始化整个ET世界如果世界很复杂注册了成百上千个System确实会慢。考虑优化使用[OneTimeSetUp]和[OneTimeTearDown]来初始化和清理只读的、全局的资源如协议类型注册、配置表结构。但绝不能用它们来初始化World和Scene。审视你的测试是否真的需要启动一个“完整”的ET世界也许某些纯逻辑的单元测试可以直接new出对象来测无需通过ET框架。心得测试金字塔仍然适用。大量低层级的、不依赖ET容器的单元测试应该是最快的。ETTest Runner的集成测试用于验证组件、系统间的交互数量应控制在中层。将ET框架与Unity Test Runner集成初期需要一些搭建成本但一旦这套基础设施就位它带来的收益是巨大的快速的回归测试、清晰的接口验证、以及重构时那无与伦比的安全感。它让ET框架那种优雅而复杂的异步架构变得像普通代码一样易于验证和调试。

相关新闻

面向对象与面向过程

面向对象与面向过程

目录 类与对象 类(Class) 定义类 self 关键字 “魔法方法” 对象(Object) 定义对象 获取属性及调用方法 面向对象(Object-Oriented,OO) 封装(Encapsulation) …

2026/10/13 14:19:48 阅读更多 →
如何实现ElasticJob任务依赖调度:5个简单方法解决复杂任务编排难题

如何实现ElasticJob任务依赖调度:5个简单方法解决复杂任务编排难题

如何实现ElasticJob任务依赖调度:5个简单方法解决复杂任务编排难题 【免费下载链接】shardingsphere-elasticjob Distributed scheduled job 项目地址: https://gitcode.com/gh_mirrors/shar/shardingsphere-elasticjob 你是否遇到过这样的问题:数…

2026/10/13 19:39:40 阅读更多 →
【软件系统架构案例分析 Day 9】性能战术:千万级QPS秒杀系统设计

【软件系统架构案例分析 Day 9】性能战术:千万级QPS秒杀系统设计

【Day 9】性能战术:千万级QPS秒杀系统设计 一、题目还原 某大型电商平台计划在"618"大促期间推出限量秒杀活动,预计活动开始瞬间将迎来千万级QPS的并发请求洪峰(历史最高峰值约1200万QPS),而常规业务峰值仅约…

2026/10/8 9:12:31 阅读更多 →

最新新闻

基于Python的微博舆情分析与话题热度预测毕设实战指南

基于Python的微博舆情分析与话题热度预测毕设实战指南

简介:这份资源是面向计算机、电子信息工程、数学等专业大学生的课程设计或毕业设计参考资料,聚焦新浪微博#新冠疫情话题的舆情分析与话题热度预测。项目经导师指导并认可通过,适合作为大作业、期末课设或毕设的完整参考方案,帮助读…

2026/10/14 9:49:28 阅读更多 →
context-mode 上下文管理模式:设计选型、传播机制与工程实践

context-mode 上下文管理模式:设计选型、传播机制与工程实践

1. 从“context-mode”说起:一个被低估的工程概念第一次看到“context-mode”这个词,很多人会下意识地把它归到某个具体框架或库的配置项里去。但如果你在工程一线待过几年,就会发现它其实是一个跨语言、跨框架、跨场景的通用设计思路。简单说…

2026/10/14 9:49:28 阅读更多 →
沐问MuAsk:开源桌面版Text2SQL工具,本地优先的自然语言查数方案

沐问MuAsk:开源桌面版Text2SQL工具,本地优先的自然语言查数方案

直接从项目本身聊起吧。这两年“Text2SQL”项目我见了不少,GitHub上动不动就十来个星标的demo遍地都是,老实说大部分都是套个LLM外壳,跑通一条SELECT语句就算完事。直到我拿到“沐问 MuAsk”这个开源桌面版工具,才觉得终于有个能正…

2026/10/14 9:49:28 阅读更多 →
Codex与Claude代码生成的token优化实战指南

Codex与Claude代码生成的token优化实战指南

1. 项目概述:为什么“节省token”成了当前代码生成场景里的硬通货最近在多个技术社区和开发者群聊里,频繁看到“codex和claude code节省token的方式”这个短语被反复提起——它不像一个功能名称,倒更像一句实操口诀,一种经验总结&…

2026/10/14 9:49:28 阅读更多 →
机械控制电缆技术演进与智能制造应用趋势

机械控制电缆技术演进与智能制造应用趋势

1. 机械控制电缆行业现状与市场背景机械控制电缆作为工业自动化领域的"神经脉络",承担着设备间信号传输与电力分配的双重使命。在智能制造浪潮推动下,这个看似传统的细分领域正经历着技术迭代与市场扩张的双重变革。根据最新市场研究数据&…

2026/10/14 9:49:28 阅读更多 →
AnyPS5模拟器架构深度解析:从系统库翻译到着色器缓存

AnyPS5模拟器架构深度解析:从系统库翻译到着色器缓存

AnyPS5 这个项目,最早是在模拟器开发讨论区里看到有人贴出的一组截图:一台普通 PC 上,跑通了一个 PS5 自制测试程序,屏幕上打印出系统版本号字符串。当时很多人第一反应是不相信,直到作者把构建日志和配置文件贴出来&a…

2026/10/14 9:48:27 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

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

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

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

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

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

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

2026/10/13 16:22:04 阅读更多 →
影刀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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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 阅读更多 →