Selenium自动化测试中Shadow DOM穿透定位的四种实战方法
1. 项目概述当Selenium遇上“影子DOM”做UI自动化测试的朋友尤其是用Selenium的最近几年肯定没少被一个叫shadow-root的东西折腾过。你写好的脚本昨天还能跑今天页面一升级元素死活定位不到打开开发者工具一看目标元素外面套了个#shadow-rootXPath、CSS Selector这些传统武器瞬间哑火。这感觉就像你拿着地图找到了宝藏的洞口结果发现洞口被一层单向透明的魔法盾罩着看得见摸不着。shadow-root中文常叫“影子DOM”是Web Components标准的核心部分之一。它的设计初衷是为了实现组件的封装和样式隔离让开发者可以创建独立、可复用的自定义HTML元素。对前端开发是福音但对自动化测试来说却成了一堵“看不见的墙”。传统的driver.find_element方法无法穿透这层影子边界直接定位其内部的元素。随着越来越多的UI库如Material-UI, Ant Design, 以及大量内部组件库和现代前端框架React, Vue, Angular的组件采用Shadow DOM技术这个问题从“偶尔遇见”变成了“家常便饭”。这篇文章我就结合自己趟过的坑系统梳理一下在Selenium自动化测试中处理shadow-root元素的几种核心方法、适用场景以及那些官方文档里不会写的实操细节。我们的目标很明确不管页面的组件封装得多深都要有办法“穿透”它稳定地定位到目标元素让自动化脚本重新健步如飞。2. 核心原理为什么Shadow DOM是道“坎”要解决问题得先理解问题。为什么shadow-root会让Selenium的传统定位方法失效这得从浏览器的渲染和DOM树结构说起。2.1 Shadow DOM的隔离机制想象一下传统的DOM树它是一个巨大的、公开的家谱从document根节点开始所有元素div,span,button都是这个家谱里明明白白列出来的成员。Selenium的定位器By.ID, By.XPATH, By.CSS_SELECTOR就像是在这份公开的家谱里按图索骥只要路径对就能找到人。而Shadow DOM引入了一个“分家”的概念。一个宿主元素Host Element比如一个自定义的my-button可以挂载一个shadow root。这个shadow root就是一个独立的、封闭的DOM子树。它内部的元素、样式都与外部的“主DOM树”隔离。外部样式不会影响里面里面的样式也不会泄露到外面JavaScript直接访问外部DOM的API也无法直接操作里面的元素。这就形成了一个“封装”的边界。从Selenium或者说WebDriver协议的视角看它获取到的是“主DOM树”的序列化信息。shadow-root作为一个特殊节点存在但其内部细节在默认情况下是不暴露的。因此当你尝试用//button[idinnerBtn]去定位一个位于Shadow DOM内部的按钮时这条XPath路径在主DOM树中根本不存在自然就会抛出NoSuchElementException。2.2 与iframe的区别很多人会把Shadow DOM和iframe搞混因为它们都提供了隔离性。但它们的本质完全不同iframe是一个完整的文档嵌入有独立的document对象。Selenium需要显式地使用driver.switch_to.frame()来切换上下文。Shadow DOM是同一个document下的一个隔离的DOM片段没有独立的document对象。你不能“切换”到它但需要“穿透”它。理解这个区别至关重要因为解决方案的思路完全不同。处理iframe是“切换上下文”而处理Shadow DOM是“获取入口后深入挖掘”。2.3 现代前端框架的推波助澜像Lit、Stencil这样的库是专门用于构建Web Components的使用Shadow DOM是标配。而即使在使用React、Vue时为了获得更好的样式封装和组件独立性开发者也会选择使用“封装模式”如Vue的scoped样式在底层也可能模拟或使用Shadow DOM或者直接集成基于Web Components的第三方组件库。这使得Shadow DOM元素在复杂的企业级应用和设计系统中越来越常见。3. 核心武器库四种主流穿透定位方法面对Shadow DOMSelenium本身没有提供像switch_to那样的一键式命令。我们需要借助JavaScript来打通道路。以下是四种经过实战检验的核心方法。3.1 方法一原生JavaScript与execute_script这是最基础、兼容性最好的方法。核心思路是利用Selenium执行JavaScript的能力在浏览器环境中直接调用Web API来访问Shadow DOM。关键APIdocument.querySelector(selector)用于定位宿主元素。.shadowRoot属性获取宿主元素附加的Shadow Root对象。.querySelector(selector)在Shadow Root内部继续定位元素。基本操作模式// 单层Shadow DOM穿透 let host document.querySelector(my-custom-element); let shadowRoot host.shadowRoot; let innerElement shadowRoot.querySelector(#inner-button); // 如果是嵌套的Shadow DOM套娃则继续 let deeperHost innerElement.querySelector(another-element); let deeperShadowRoot deeperHost.shadowRoot; // ... 如此往复在Selenium Python中的实现from selenium import webdriver driver webdriver.Chrome() driver.get(your_page_url) # 定位宿主元素 host_element driver.find_element(By.CSS_SELECTOR, my-custom-element) # 执行JS穿透Shadow DOM获取内部元素 inner_element driver.execute_script( return arguments[0].shadowRoot.querySelector(#inner-button), host_element ) # 现在可以对inner_element进行操作如点击 inner_element.click()优点原生支持无需额外依赖。原理清晰适合理解Shadow DOM访问机制。是其他更高级方法的基础。缺点代码冗长尤其是处理多层嵌套时需要写很长的JavaScript字符串或多次调用execute_script。可读性和可维护性较差。错误处理比较麻烦JavaScript执行异常需要在Python层捕获解析。3.2 方法二封装通用穿透函数为了改善方法一的缺点一个自然的进化是封装一个通用的辅助函数。这个函数的目标是给定一个从根节点到目标元素的“路径”它能自动逐层穿透Shadow DOM。函数设计思路 输入一个选择器列表每个选择器代表一层。函数从document开始判断当前层元素是否有shadowRoot有则进入然后在其中用下一个选择器查找元素如此循环直到找到最终目标。示例实现def find_element_in_shadow(driver, selector_chain): 通过选择器链定位Shadow DOM内的元素。 :param driver: WebDriver实例 :param selector_chain: 列表如[my-app, my-header, #settings, button.confirm] :return: WebElement 对象 element driver for selector in selector_chain: # 如果当前element是WebDriver则从document开始 if element driver: element driver.find_element(By.CSS_SELECTOR, selector) else: # 判断当前元素是否为shadow host shadow_root driver.execute_script(return arguments[0].shadowRoot, element) if shadow_root: # 进入shadow root并查找 element driver.execute_script( return arguments[0].querySelector(arguments[1]), shadow_root, selector ) else: # 不在shadow root内正常查找这里简化处理实际可能需支持普通DOM遍历 element element.find_element(By.CSS_SELECTOR, selector) if not element: raise NoSuchElementException(f元素未找到选择器链: {selector_chain}, 失败于: {selector}) return element # 使用示例 confirm_btn find_element_in_shadow(driver, [my-app, my-header, #settings, button.confirm]) confirm_btn.click()优点将复杂逻辑封装调用方代码简洁。一定程度上提高了可维护性。缺点函数逻辑需要处理各种边界情况如非Shadow Host元素、选择器在Shadow Root外等实现一个健壮的版本并不简单。依然依赖于拼接JavaScript字符串。3.3 方法三使用shadowdom-selector等第三方JS库通过CDN注入这是一个更“工程化”的思路。既然浏览器环境里缺一个方便查询Shadow DOM的Selector引擎那我们就在运行时给它注入一个。代表性库shadowdom-selector。这个库扩展了querySelector和querySelectorAll的功能使其能够自动穿透Shadow DOM边界。你只需要像写普通CSS选择器一样写它就能帮你找到深藏在多层Shadow DOM里的元素。操作步骤注入库在测试开始前通过driver.execute_script()将库的源代码通常是一个.js文件的内容注入到页面中。使用库的API后续定位元素时调用被注入库提供的函数。示例# 假设你已经将 shadowdom-selector.js 的内容读取到了变量 shadowdom_lib_js 中 with open(shadowdom-selector.js, r) as f: shadowdom_lib_js f.read() driver.get(your_page_url) # 注入库 driver.execute_script(shadowdom_lib_js) # 使用库提供的函数进行定位例如它可能提供了一个 shadowQuerySelector 函数 # 注意具体函数名需查看库的文档 inner_element driver.execute_script( return shadowQuerySelector(my-app #settings button.confirm) ) # 或者如果库修改了原生的 querySelector你可能可以直接用 # inner_element driver.execute_script(return document.querySelector(my-app #settings button.confirm)) # 将返回的DOM元素对象转换为Selenium的WebElement # 通常需要再次执行脚本或者库可能提供了更好的集成方式 inner_web_element driver.execute_script(return arguments[0], inner_element) inner_web_element.click()注意或/deep/已废弃是CSS Shadow Piercing组合器的旧提案并非所有库都使用。具体语法需查看所用库的文档。优点书写选择器的方式最直观接近传统CSS选择器。逻辑完全由注入的JS库处理测试脚本更清晰。缺点需要管理第三方JS库的版本和来源。注入脚本可能对页面原有环境产生未知影响虽然概率低。多了一层依赖调试问题可能更复杂是库的问题还是你的选择器问题。3.4 方法四升级到支持Shadow DOM的现代工具如Playwright当你被Shadow DOM问题折磨得够呛并且项目有技术栈升级空间时不妨考虑一下“终极解决方案”换用更现代的浏览器自动化工具比如Playwright或Cypress。以Playwright为例它原生内置了对Shadow DOM的穿透支持。在编写选择器时你几乎可以忽略Shadow Root的存在Playwright的定位引擎会自动处理。Playwright示例Pythonfrom playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch(headlessFalse) page browser.new_page() page.goto(your_page_url) # 直接定位Playwright的定位器会自动穿透Shadow DOM page.locator(my-app #settings button.confirm).click() # 或者使用更精确的定位方式 page.locator(my-app).locator(#settings).locator(button.confirm).click() browser.close()为什么Playwright可以Playwright使用了一个更高级的定位引擎它不仅仅依赖DOM序列化而是与浏览器内核有更深的集成能够理解页面的实际渲染树结构从而自然“看到”Shadow DOM内部的内容。它的选择器语法在特定情况下也用于表示“穿透”但很多时候连这个都不需要。优点开发体验极佳无需关心Shadow DOM编码效率大幅提升。功能强大Playwright在等待策略、自动重试、网络拦截、移动端模拟等方面都比Selenium有显著优势。官方维护由微软团队维护紧跟浏览器标准。缺点迁移成本如果已有大量基于Selenium的测试用例重写成本高。生态差异需要学习新的API和生态工具。4. 实战演练处理一个多层嵌套的复杂案例光说不练假把式。我们假设一个真实的复杂场景一个任务管理应用其主框架task-app是一个Shadow Host内部包含一个task-list组件也是Shadow Host列表中的每个task-item还是Shadow Host里有一个复杂的操作区里面有一个more-actions菜单猜对了也是Shadow Host我们最终要点击菜单里的“删除”按钮。HTML结构模拟task-app #shadow-root div classapp-container task-list #shadow-root ul task-item># 代码会非常冗长 driver.get(app_url) # 1. 定位到task-app宿主 task_app driver.find_element(By.TAG_NAME, task-app) # 2. 进入其shadow root定位task-list task_list_shadow driver.execute_script(return arguments[0].shadowRoot, task_app) task_list_host driver.execute_script(return arguments[0].querySelector(task-list), task_list_shadow) # 3. 进入task-list的shadow root定位第一个task-item task_list_shadow_inner driver.execute_script(return arguments[0].shadowRoot, task_list_host) task_item_host driver.execute_script(return arguments[0].querySelector(task-item), task_list_shadow_inner) # 4. 进入task-item的shadow root定位more-actions task_item_shadow driver.execute_script(return arguments[0].shadowRoot, task_item_host) more_actions_host driver.execute_script(return arguments[0].querySelector(more-actions), task_item_shadow) # 5. 进入more-actions的shadow root定位并点击删除按钮 more_actions_shadow driver.execute_script(return arguments[0].shadowRoot, more_actions_host) delete_btn driver.execute_script(return arguments[0].querySelector(button.delete-btn), more_actions_shadow) driver.execute_script(arguments[0].click();, delete_btn)这段代码不仅长而且极其脆弱。任何一层DOM结构变化都会导致失败。使用封装函数方法二 假设我们有一个增强版的find_element_in_shadow它支持混合路径部分在Shadow外部分在Shadow内。selector_chain [ task-app, # 第一层宿主 task-list, # 在task-app的shadow root内 task-item, # 在task-list的shadow root内 more-actions, # 在task-item的shadow root内 button.delete-btn # 在more-actions的shadow root内 ] delete_btn find_element_in_shadow(driver, selector_chain) delete_btn.click()代码简洁多了但函数的内部实现必须足够健壮。使用Playwright方法四# 假设页面已加载 page.locator(task-app task-list task-item more-actions button.delete-btn).click() # 或者如果定位器需要更精确 page.locator(task-item, haspage.locator(span, has_text买咖啡)).locator(more-actions button.delete-btn).click()简洁、直观、强大。这就是现代工具带来的生产力提升。5. 避坑指南与最佳实践在长期与Shadow DOM斗争的过程中我积累了一些血泪教训和实用技巧。5.1 定位策略选择与优先级优先与开发沟通在动手写复杂的穿透代码前先问问前端同事目标组件是否提供了易于测试的“钩子”。例如能否为关键的内部元素添加稳定的>from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 错误只等待了宿主 host WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.TAG_NAME, my-element))) # 立即穿透可能失败因为内部Shadow内容可能还没渲染完 # inner driver.execute_script(return arguments[0].shadowRoot.querySelector(button), host) # 正确封装一个自定义的Expected Condition来等待Shadow内部元素 def shadow_element_located(shadow_host_locator, inner_css_selector): def _predicate(driver): host driver.find_element(*shadow_host_locator) shadow_root driver.execute_script(return arguments[0].shadowRoot, host) if shadow_root: element driver.execute_script(return arguments[0].querySelector(arguments[1]), shadow_root, inner_css_selector) if element: return element return False return _predicate # 使用自定义等待条件 inner_btn WebDriverWait(driver, 10).until( shadow_element_located((By.TAG_NAME, my-element), button.primary) ) inner_btn.click()5.3 调试技巧当你的穿透脚本失败时如何快速定位问题在浏览器控制台手动验证路径这是第一步。打开开发者工具在Console中逐层执行你的JavaScript定位代码看哪一层返回了null或报错。这能帮你确认是选择器写错了还是渲染时机问题。检查Shadow Root的打开模式Shadow Root有两种模式open和closed。open模式可以通过.shadowRoot属性访问这也是我们所有方法的前提。如果是closed模式那么从外部JavaScript包括Selenium执行的脚本将无法访问其内部内容.shadowRoot会返回null。遇到closed模式基本上只能寻求开发人员的帮助或者看看组件是否提供了访问内部元素的API。使用debugger关键字在你的穿透JavaScript字符串中插入debugger;语句然后以非无头模式运行测试。当浏览器执行到该处时会自动暂停你可以像调试普通前端代码一样检查当时的DOM状态。js_code let host document.querySelector(my-element); debugger; // 浏览器会在这里停下来 let root host.shadowRoot; return root.querySelector(button); driver.execute_script(js_code)5.4 维护性建议抽象成Page Object模式将复杂的Shadow DOM定位逻辑封装在Page Object的属性和方法里。测试用例只调用像task_page.delete_task(“买咖啡”)这样的高级语义隐藏底层穿透细节。统一选择器管理将所有CSS选择器、XPath甚至穿透路径集中管理如放在一个locators.py文件或配置中而不是硬编码在测试脚本里。当UI变更时只需修改一处。添加详尽的注释在复杂的穿透代码旁注释上目标元素的完整路径和上下文方便后续维护者理解。6. 总结与抉择处理Selenium中的Shadow DOM元素定位本质上是一场与前端组件化、封装化趋势的博弈。没有一种“银弹”方法适用于所有场景。对于简单、偶发的Shadow DOM使用原生JavaScript方法一快速解决问题成本最低。对于中型项目有较多Shadow DOM组件投入时间封装健壮的辅助函数方法二是平衡可维护性和开发成本的选择。对于追求极致效率和开发体验或启动新项目认真考虑迁移到Playwright方法四。它不仅是解决Shadow DOM的问题更是将整个自动化测试体验提升了一个世代。第三方JS库方法三是一个折中方案但引入了外部依赖需团队评估。我个人在近两年的新项目中已经全面转向Playwright。对于老项目的维护则是用一个精心编写的ShadowDOMHelper类来统一处理穿透逻辑让测试用例代码尽可能干净。前端技术在不断演进我们的测试技术栈也需要与时俱进。理解原理掌握工具选择最适合当前团队和项目的方案才是应对诸如Shadow DOM这类挑战的根本之道。

相关新闻

Windows系统OpenJDK安装配置全攻略:从发行版选择到多版本管理

Windows系统OpenJDK安装配置全攻略:从发行版选择到多版本管理

1. 为什么在Windows上选择OpenJDK?如果你是一名Java开发者,或者需要运行基于Java的应用程序,那么在你的Windows机器上安装一个Java开发工具包(JDK)是绕不开的第一步。过去,很多人会下意识地选择Oracle JDK&…

2026/8/3 19:44:16 阅读更多 →
解锁Photoshop的WebP格式能力:WebPShop插件完全指南

解锁Photoshop的WebP格式能力:WebPShop插件完全指南

解锁Photoshop的WebP格式能力:WebPShop插件完全指南 【免费下载链接】WebPShop Photoshop plug-in for opening and saving WebP images 项目地址: https://gitcode.com/gh_mirrors/we/WebPShop 还在为Photoshop无法直接处理现代Web图像格式而烦恼吗&#xf…

2026/8/3 19:44:16 阅读更多 →
5步彻底清除BlackHole音频驱动:解决macOS音频问题的完整方案

5步彻底清除BlackHole音频驱动:解决macOS音频问题的完整方案

5步彻底清除BlackHole音频驱动:解决macOS音频问题的完整方案 【免费下载链接】BlackHole BlackHole is a modern macOS audio loopback driver that allows applications to pass audio to other applications with zero additional latency. 项目地址: https://g…

2026/8/3 19:43:16 阅读更多 →

最新新闻

阿里妈妈技术年刊精读指南:从大模型落地到推荐系统演进的工程实践

阿里妈妈技术年刊精读指南:从大模型落地到推荐系统演进的工程实践

1. 项目概述:一份技术年刊的诞生与价值 又到了一年一度技术圈“开盲盒”的时候了。我说的不是哪个新发布的框架,而是那份很多技术人每年都会下意识去关注、去下载的“年度总结”——阿里妈妈技术年刊。今年,这份名为《2025阿里妈妈技术年刊》…

2026/8/3 23:06:13 阅读更多 →
vtools Dex2oat编译优化实战:解锁Android应用性能新高度

vtools Dex2oat编译优化实战:解锁Android应用性能新高度

vtools Dex2oat编译优化实战:解锁Android应用性能新高度 【免费下载链接】vtools 一个集高级重启、应用安装自动点击、CPU调频等多项功能于一体的工具箱。 项目地址: https://gitcode.com/gh_mirrors/vt/vtools vtools是一款面向Android设备的高级工具箱&…

2026/8/3 23:06:13 阅读更多 →
如何在5分钟内为你的网站添加GitHub贡献日历:完整实现指南

如何在5分钟内为你的网站添加GitHub贡献日历:完整实现指南

如何在5分钟内为你的网站添加GitHub贡献日历:完整实现指南 【免费下载链接】github-calendar :bar_chart: Embed your GitHub calendar everywhere. 项目地址: https://gitcode.com/gh_mirrors/gi/github-calendar GitHub贡献日历是展示开发者编程活跃度的最…

2026/8/3 23:06:13 阅读更多 →
Seraphine英雄联盟助手:免费战绩查询与智能BP辅助完整指南

Seraphine英雄联盟助手:免费战绩查询与智能BP辅助完整指南

Seraphine英雄联盟助手:免费战绩查询与智能BP辅助完整指南 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine Seraphine是一款基于英雄联盟官方LCU API开发的免费开源智能助手,专为英雄联…

2026/8/3 23:06:13 阅读更多 →
Cap开源录屏工具:3分钟学会专业屏幕录制,免费替代Loom的终极选择

Cap开源录屏工具:3分钟学会专业屏幕录制,免费替代Loom的终极选择

Cap开源录屏工具:3分钟学会专业屏幕录制,免费替代Loom的终极选择 【免费下载链接】Cap Open source Loom alternative. Beautiful, shareable screen recordings. 项目地址: https://gitcode.com/GitHub_Trending/cap1/Cap 在数字协作日益重要的今…

2026/8/3 23:06:13 阅读更多 →
如何免费快速获取国家教育平台电子课本?这款智能工具让你轻松下载PDF教材!

如何免费快速获取国家教育平台电子课本?这款智能工具让你轻松下载PDF教材!

如何免费快速获取国家教育平台电子课本?这款智能工具让你轻松下载PDF教材! 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方…

2026/8/3 23:04:55 阅读更多 →

日新闻

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南

3个让你工作效率翻倍的Umi-OCR实战技巧:免费离线文字识别完全指南 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描/生成二维码。…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

[具身智能-181]:PC+服务器+具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构

PC服务器具身机器人:构建具身智能从仿真到量产的闭环迭代混合架构一、前言:具身智能需要“混合算力闭环系统”传统人工智能依赖云端静态数据集训练,不具备物理交互能力,无法适应真实世界的不确定性。具身智能(Embodied…

2026/8/3 0:00:47 阅读更多 →
[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

[具身智能-181]:大分布式通信模型对比:看懂为什么 DDS 是 ROS2 底层通信最优解

前言构建机器人、具身智能这类分布式实时系统,通信底座直接决定整套系统的实时性、容错性、组网能力。分布式领域长期存在 4 类经典通信架构:点对点模式、Broker 中间代理模式、广播模式、以数据为中心(DDS)模式。很多开发者疑惑&…

2026/8/3 0:00:47 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/3 4:58:13 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/3 1:53:31 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/3 4:36:35 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/3 13:07:03 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/3 5:19:38 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/3 8:27:36 阅读更多 →