发布时间:2026/6/23 4:59:32
Selenium Grid节点浏览器标识配置详解:解决自动化测试集群资源错配
1. 项目概述当你的自动化测试集群“脸盲”了在分布式自动化测试的战场上Selenium Grid 是我们调度浏览器、并行执行用例的得力指挥官。但你是否遇到过这样的场景你向 Grid Hub 请求一个 Chrome 浏览器Hub 却把一个 Firefox 节点分配给了你导致测试脚本因为浏览器不兼容而直接崩溃或者你的集群里明明有 10 个 Chrome 节点但任务队列却总是堆积在少数几个节点上其他节点却在“摸鱼”这背后的问题往往不是 Grid 的 Bug而是节点的“自我介绍”出了问题——也就是我们今天要深入探讨的浏览器类型标识配置。简单来说浏览器类型标识就像是每个 Grid Node 向 Hub 报到时递上的“名片”。这张名片上需要清晰地写明“我是谁”浏览器名称如 chrome, firefox、“我是什么版本”browserVersion以及“我能做什么”平台 platformName。如果这张名片印错了或者信息模糊不清Hub 这个“调度中心”就会产生误判导致资源匹配错误整个测试流程的稳定性和效率都会大打折扣。尤其是在混合了多种浏览器、多个版本的复杂测试环境中精确的标识配置是保障测试任务被正确路由和执行的基石。本指南将从一个资深测试开发的角度带你彻底拆解 Selenium Grid 节点注册与识别的核心机制。我们不仅会告诉你配置文件里那几个参数怎么写更重要的是我会分享在实际大规模集群运维中如何通过精准配置来规避那些令人头疼的“识别难题”提升整个自动化测试基础设施的健壮性。无论你是刚开始搭建 Grid 的新手还是正在被节点管理问题困扰的老兵这篇文章都能给你带来可以直接落地的解决方案和深度思考。2. 核心原理Grid Hub 如何“认识”一个节点要解决问题必须先理解问题是如何产生的。Selenium Grid 采用了一种基于能力匹配的调度模型。整个过程就像一场招聘会Node求职者向 Hub招聘官注册递交自己的简历Capabilities当测试脚本招聘需求发起一个会话请求时会附带一份职位描述Desired CapabilitiesHub 的工作就是在所有已注册的 Node 中找到那份与职位描述最匹配的简历。2.1 Capabilities节点的“能力简历”Capabilities 是一个 JSON 对象是 WebDriver 协议中定义会话的核心元数据。对于 Grid Node 而言它在启动时通过-nodeConfig参数指定的 JSON 配置文件或者在命令行中直接通过-capabilities参数来声明自己的这份“简历”。其中与浏览器识别最相关的几个关键字段包括browserName: 这是最核心的标识。值必须是标准的小写字符串如“chrome”,“firefox”,“MicrosoftEdge”,“safari”。Hub 主要依据这个字段进行第一轮筛选。browserVersion: 浏览器的具体版本号例如“120.0.6099.217”。这个字段对于需要特定版本进行兼容性测试的场景至关重要。如果未指定Node 通常会注册自己安装的默认或最高版本。platformName: 节点运行的操作系统平台如“WINDOWS”,“MAC”,“LINUX”。这确保了测试脚本对特定平台如字体渲染、文件路径的依赖能得到满足。一个典型的 Node 能力声明在配置文件中看起来是这样的{ “capabilities”: [ { “browserName”: “chrome”, “browserVersion”: “120.0.6099.217”, “platformName”: “LINUX”, “se:options”: { “nodename”: “linux-chrome-120-node-01” } } ] }2.2 注册与匹配流程节点注册Node 启动后会周期性地向 Hub 发送心跳和注册信息其中就包含了它的 Capabilities。Hub 维护注册表Hub 在内存中维护一个所有活动节点的注册表记录每个节点的 ID、URL 和其声明的 Capabilities。会话请求客户端测试脚本使用 WebDriver 库如 Selenium WebDriver创建一个新的会话请求这个请求中包含了DesiredCapabilities对象。能力匹配Hub 收到请求后会遍历节点注册表寻找一个其 Capabilities 与DesiredCapabilities完全匹配或超集匹配的节点。匹配规则通常是browserName必须相等browserVersion如果指定则必须相等或符合语义化版本范围platformName如果指定则必须相等。会话创建找到匹配节点后Hub 将请求代理到该节点节点启动浏览器实例并建立 WebDriver 会话将会话 ID 返回给客户端。关键陷阱这里最常见的“识别难题”就出在匹配失败。例如Node 注册时browserName写成了“Google Chrome”带空格和品牌名而客户端请求的是“chrome”Hub 会认为这是两种不同的浏览器导致匹配失败客户端收到“No matching node found for the request.”的错误。3. 精准配置从基础到高级的节点标识实战理解了原理我们就可以动手解决配置问题了。配置节点标识主要有两种方式JSON 配置文件推荐和命令行参数。我们将以最常用的 Chrome 和 Firefox 为例详细讲解。3.1 基础配置使用 JSON 配置文件这是最清晰、最易于维护的方式。创建一个node-config.json文件。单浏览器类型节点配置{ “capabilities”: [ { “browserName”: “chrome”, “browserVersion”: “stable”, // 或具体版本号 “120.0.6099.217” “platformName”: “WINDOWS”, “se:options”: { “nodename”: “win-chrome-stable-node-01”, // 自定义节点名便于在Grid UI中识别 “maxSessions”: 5, // 该节点最大并发会话数 “sessionTimeout”: “300” // 会话超时时间秒 } } ], “proxy”: “org.openqa.grid.selenium.proxy.DefaultRemoteProxy”, “maxSession”: 5, “port”: 5555, “register”: true, “registerCycle”: 5000, “hub”: “http://hub-host:4444”, “nodeStatusCheckTimeout”: 5000, “downPollingLimit”: 2 }启动命令java -jar selenium-server-version.jar node --config node-config.json多浏览器类型节点配置单机多浏览器如果你想在一台机器上同时注册 Chrome 和 Firefox 节点能力可以在capabilities数组中添加多个对象。{ “capabilities”: [ { “browserName”: “chrome”, “browserVersion”: “121.0.6167.184”, “platformName”: “LINUX”, “se:options”: { “nodename”: “linux-chrome-121” } }, { “browserName”: “firefox”, “browserVersion”: “122.0.1”, “platformName”: “LINUX”, “se:options”: { “nodename”: “linux-firefox-122” } } ], ... // 其他配置同上 }注意这种配置意味着同一个 Node 进程可以承载两种浏览器的会话。maxSession配置是针对整个节点的例如设为 5那么 Chrome 和 Firefox 会话加起来不能超过 5 个。你需要根据机器资源合理分配。3.2 命令行参数配置快速验证对于快速测试或简单环境可以直接通过命令行参数指定能力。java -jar selenium-server-version.jar node \ --hub http://hub-host:4444 \ --port 5555 \ --max-sessions 5 \ --browser-name chrome \ --browser-version “120” \ --platform-name “WINDOWS”实操心得命令行方式虽然快捷但在管理多个节点、复杂能力时非常容易出错且不利于版本控制和批量部署。强烈建议在生产环境或任何严肃的测试环境中使用 JSON 配置文件。3.3 高级配置解决特定识别难题难题一浏览器版本号“漂移”或未指定有时我们可能不关心非常精确的补丁版本只关心主版本如 Chrome 120。或者Node 上安装了多个 Chrome 版本。我们可以利用browserVersion的灵活性。指定主版本“browserVersion”: “120”。Hub 会匹配所有 120.x.x.x 版本的节点。使用版本范围部分Grid版本支持“browserVersion”: “119..121”匹配119到121之间的版本。最佳实践在配置文件中始终明确指定你测试所依赖的浏览器版本号而不是依赖“stable”或“latest”。这能保证测试环境的确定性避免因为浏览器自动升级导致测试行为不一致。难题二自定义节点名与Grid UI管理se:options中的nodename字段是你的救命稻草。给它起一个有意义的名字例如“region-us-west2-chrome-120-linux-large”。这样当你在 Grid 控制台http://hub-host:4444/ui查看节点时可以一目了然地知道每个节点的地理位置、浏览器类型、版本、系统和规模极大提升了运维排查效率。难题三Docker 化 Grid 节点的标识配置在使用官方 Selenium Docker 镜像如selenium/node-chrome时标识是通过环境变量传递的。docker run -d -p 5555:5555 \ -e SE_EVENT_BUS_HOSThub-host \ -e SE_EVENT_BUS_PUBLISH_PORT4442 \ -e SE_EVENT_BUS_SUBSCRIBE_PORT4443 \ -e SE_NODE_MAX_SESSIONS5 \ -e SE_NODE_OVERRIDE_MAX_SESSIONStrue \ -e SE_NODE_BROWSER_NAMEchrome \ -e SE_NODE_BROWSER_VERSION“120” \ -e SE_NODE_PLATFORM_NAME“LINUX” \ -e SE_NODE_GRID_URL“http://hub-host:4444” \ --shm-size“2g” \ selenium/node-chrome:120.0踩坑记录Docker 方式下SE_NODE_BROWSER_VERSION环境变量必须与镜像标签版本如:120.0大致对应否则节点可能启动失败或注册错误版本。建议保持两者一致。4. 客户端测试脚本侧的匹配策略节点配置得再完美如果客户端请求的能力不匹配也是徒劳。在测试脚本中我们通过DesiredCapabilities或其现代替代品Options类来声明需求。传统方式已逐渐淘汰但需了解from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities cap DesiredCapabilities.CHROME.copy() # 获取一个CHROME的默认能力模板 cap[‘browserVersion’] ‘120’ # 指定版本 cap[‘platformName’] ‘LINUX’ # 指定平台 driver webdriver.Remote( command_executor‘http://hub-host:4444/wd/hub’, desired_capabilitiescap )现代推荐方式使用Options类这是 Selenium 4 及以后更推荐的方式类型安全且与 W3C WebDriver 标准对齐。from selenium import webdriver from selenium.webdriver.chrome.options import Options as ChromeOptions options ChromeOptions() options.browser_version ‘120’ # 设置版本 options.platform_name ‘LINUX’ # 设置平台 # 可以添加其他任何ChromeOptions支持的特性 options.add_argument(‘--headlessnew’) driver webdriver.Remote( command_executor‘http://hub-host:4444/wd/hub’, optionsoptions # 这里传入的是options对象 )对于 Firefox 或 Edge只需替换对应的Options类即可。这种方式生成的 Capabilities 字典是标准化的能最大程度避免因格式问题导致的匹配失败。5. 诊断与排查当识别失败时该怎么办即使配置看似正确问题仍可能发生。下面是一个系统性的排查流程和常见问题速查表。5.1 排查流程检查 Grid 控制台首先访问http://hub-host:4444/ui。这是你的第一现场。节点是否在线在 “Nodes” 标签页查看你的节点是否显示为绿色可用。节点能力是否正确点击节点查看其 “Configuration” 中注册的browserName,browserVersion是否与你预期的一致。查看节点日志在节点启动的命令行或日志文件中搜索 “Registered” 或 “Capabilities” 关键词确认它向 Hub 发送了哪些能力信息。查看 Hub 日志当客户端请求失败时Hub 日志会记录详细的匹配过程。查找 “No matching node found” 错误并查看其前后的日志看 Hub 收到了什么请求能力以及当时有哪些节点可用。检查客户端请求在测试脚本中可以在创建Remote WebDriver之前打印出options.to_capabilities()Python或类似方法生成的能力字典确认发送给 Hub 的Desired Capabilities到底是什么。使用curl直接调试模拟一个客户端请求这是最直接的诊断方法。curl -X POST http://hub-host:4444/wd/hub/session \ -H “Content-Type: application/json” \ -d ‘{ “capabilities”: { “alwaysMatch”: { “browserName”: “chrome”, “browserVersion”: “120” } } }’观察返回的错误信息通常非常具体。5.2 常见问题速查表问题现象可能原因解决方案No matching node found for the request1.browserName大小写或拼写不一致。2. 请求的browserVersion在所有在线节点中不存在。3. 请求的platformName不匹配。4. 节点maxSession已满无空闲槽位。1. 统一使用小写标准名chrome, firefox。2. 核对节点注册版本和客户端请求版本。在Grid UI中确认。3. 检查平台标识或尝试在客户端不指定platformName。4. 增加节点maxSession或增加节点数量。节点在Grid UI中显示能力为unknown或为空1. 节点启动参数或配置文件有误未能正确声明能力。2. 节点与Hub网络不通注册信息未同步。1. 检查节点启动命令和配置文件语法确保capabilities数组格式正确。2. 检查防火墙和网络确保节点能访问Hub的4444端口Hub能访问节点的注册端口。会话被创建在错误的节点上多个节点注册了相同或高度相似的能力Hub 使用了非预期的负载均衡策略。1. 为每个节点在se:options中设置独特的nodename。2. 在客户端请求中通过se:options添加更具体的匹配条件如特定节点名。3. 考虑使用--grid-model为节点打上自定义标签进行分组筛选。Docker节点频繁断开或注册失败1. 共享内存 (shm-size) 不足导致浏览器崩溃。2. 容器时区、语言环境与Hub/测试预期不符。3. 镜像版本与声明的browserVersion不兼容。1. 确保docker run时设置了--shm-size“2g”或更大。2. 在Dockerfile或docker run命令中设置-e TZUTC等环境变量。3. 确保SE_NODE_BROWSER_VERSION与镜像标签主版本一致。5.3 一个真实的排查案例我们曾遇到一个诡异的问题在 Kubernetes 中部署的 Grid 集群部分 Chrome 节点会间歇性地被识别为 Firefox。通过分析 Hub 日志发现当节点负载过高、响应注册心跳超时时Hub 会错误地更新该节点的能力缓存。根本原因是节点 JVM 内存配置不足在高压下 Full GC 导致进程暂停错过了心跳。解决方案不仅仅是调整标识配置而是优化了节点的 JVM 参数-Xmx和-Xms并设置了合理的nodeStatusCheckTimeout和downPollingLimit给了节点更宽松的容错空间。这个案例告诉我们识别问题有时是更深层次系统问题的表象。6. 最佳实践与配置模板根据多年运维经验我总结出以下几条黄金法则配置文件至上放弃命令行参数对所有节点使用 JSON 配置文件进行管理。将配置文件纳入版本控制系统如 Git。命名规范化为每个节点配置清晰、唯一的nodename建议包含环境-地区-浏览器-版本-系统-序列号等信息。版本固定化在配置中明确指定browserVersion不要使用“latest”或“stable”。使用 Docker 镜像时固定镜像标签的版本号。客户端使用 Options 类在新代码中统一使用各浏览器的Options类来设置能力避免手动构造易错的字典。实施健康检查为 Grid Hub 和 Node 设置活跃度Liveness和就绪度Readiness探针特别是在 K8s 环境中确保不可用的节点能被及时隔离。集中化日志将 Hub 和所有 Node 的日志收集到 ELK 或类似平台方便全局搜索和关联分析。附一个生产级的多浏览器节点配置模板// node-config-production.json { “capabilities”: [ { “browserName”: “chrome”, “browserVersion”: “121.0.6167.184”, “platformName”: “LINUX”, “acceptInsecureCerts”: true, “se:options”: { “nodename”: “prod-eu-chrome-121-linux-01”, “maxSessions”: 4, “sessionTimeout”: “600”, “custom-tag”: “high-memory”, // 自定义标签用于高级路由 “enableVNC”: true // 如果集成NoVNC进行实时查看 } }, { “browserName”: “firefox”, “browserVersion”: “122.0.1”, “platformName”: “LINUX”, “acceptInsecureCerts”: true, “se:options”: { “nodename”: “prod-eu-firefox-122-linux-01”, “maxSessions”: 4, “sessionTimeout”: “600”, “custom-tag”: “high-memory” } } ], “proxy”: “org.openqa.grid.selenium.proxy.DefaultRemoteProxy”, “maxSession”: 8, // 整机总会话数等于两个浏览器maxSessions之和 “port”: 5566, “register”: true, “registerCycle”: 10000, “hub”: “http://selenium-hub.prod.svc:4444”, “nodeStatusCheckTimeout”: 10000, “downPollingLimit”: 3, “unregisterIfStillDownAfter”: 120000, “enablePlatformVerification”: false // 在某些混合平台集群中可关闭严格平台验证 }最后我想分享的一点个人体会是Selenium Grid 的节点识别问题本质上是一个“元数据管理”问题。把它当作一个微服务注册与发现的场景来对待——确保服务Node注册的信息准确、消费方Client请求的信息明确、注册中心Hub的匹配策略可靠很多问题就迎刃而解了。定期审计你的 Grid 集群中所有节点的注册信息就像定期盘点你的测试资产一样是保持自动化测试流水线稳定运行的一个简单却极其有效的习惯。

相关新闻

Crypto++文件加密实践:AES-CBC流式处理与安全存储方案
2026/6/23 4:59:32

Crypto++文件加密实践:AES-CBC流式处理与安全存储方案

1. 项目概述:为什么我们需要Crypto来操作文件?在数据处理和存储的日常开发中,文件操作是基础中的基础。但当你需要处理敏感信息——比如用户隐私数据、配置密钥或是商业交易记录时,简单的读写操作就远远不够了。一个未加密的配置文…

阅读更多
Vela Jr.超新星遗迹的伽马射线辐射机制研究
2026/6/23 4:59:32

Vela Jr.超新星遗迹的伽马射线辐射机制研究

1. 项目概述:Vela Jr.超新星遗迹的伽马射线研究在距离地球约1.41千秒差距处,有一个被称为Vela Jr.(RX J0852.0-4622)的神秘天体。这个直径约2度的环状结构,实际上是银河系中最年轻的超新星遗迹之一。2005年&#xff0c…

阅读更多
OpenClaw进阶实践:智能体操作系统级工程化落地指南
2026/6/23 4:59:32

OpenClaw进阶实践:智能体操作系统级工程化落地指南

1. OpenClaw 不是玩具,是可调度的智能体操作系统:从“能跑起来”到“能管得住”的认知跃迁 OpenClaw 这个名字在最近三个月里,几乎以每天新增200 GitHub Star 的速度冲进开发者视野。但翻遍它的官方文档、社区讨论和早期教程,你会…

阅读更多
Selenium与Pytest结合构建高效Web自动化测试框架
2026/6/23 6:59:33

Selenium与Pytest结合构建高效Web自动化测试框架

1. 项目概述:当Selenium遇上Pytest如果你正在做Web自动化测试,或者正准备踏入这个领域,那你一定绕不开Selenium和Pytest这两个名字。Selenium是模拟用户操作浏览器的利器,而Pytest则是Python世界里最优雅、最强大的测试框架之一。…

阅读更多
Google Nav Bar 高级技巧:实现平滑过渡动画与交互效果的终极指南
2026/6/23 6:59:33

Google Nav Bar 高级技巧:实现平滑过渡动画与交互效果的终极指南

Google Nav Bar 高级技巧:实现平滑过渡动画与交互效果的终极指南 【免费下载链接】google_nav_bar A modern google style nav bar for flutter. 项目地址: https://gitcode.com/gh_mirrors/go/google_nav_bar 在 Flutter 应用开发中,一个优秀的底…

阅读更多
如何用 Formsnap + Superforms 构建完整的用户设置表单
2026/6/23 6:59:33

如何用 Formsnap + Superforms 构建完整的用户设置表单

如何用 Formsnap Superforms 构建完整的用户设置表单 【免费下载链接】formsnap Functional, accessible, and powerful form components for Svelte. 🫰 项目地址: https://gitcode.com/gh_mirrors/for/formsnap Formsnap 是一个功能强大、可访问且高效的…

阅读更多
Spraykatz核心组件详解:Engine、ParseDump与Connection模块分析
2026/6/23 6:59:33

Spraykatz核心组件详解:Engine、ParseDump与Connection模块分析

Spraykatz核心组件详解:Engine、ParseDump与Connection模块分析 【免费下载链接】spraykatz Credentials gathering tool automating remote procdump and parse of lsass process. 项目地址: https://gitcode.com/gh_mirrors/sp/spraykatz Spraykatz是一款强…

阅读更多
console-powers终极指南:如何创建优雅的浏览器控制台输出
2026/6/23 6:59:33

console-powers终极指南:如何创建优雅的浏览器控制台输出

console-powers终极指南:如何创建优雅的浏览器控制台输出 【免费下载链接】console-powers Craft beautiful browser console messages. Debug & inspect data with elegant outputs. Small & tree-shakable. 项目地址: https://gitcode.com/gh_mirrors/c…

阅读更多
终极音频转换解决方案:fre:ac免费音频转换器完全指南
2026/6/23 5:59:32

终极音频转换解决方案:fre:ac免费音频转换器完全指南

终极音频转换解决方案:fre:ac免费音频转换器完全指南 【免费下载链接】freac The fre:ac audio converter project 项目地址: https://gitcode.com/gh_mirrors/fr/freac 你是否曾经遇到过这样的烦恼:手机里的音乐格式电脑打不开,收藏的…

阅读更多
嵌入式语音编解码实战:G.726 ADPCM库集成与优化指南
2026/6/23 3:25:21

嵌入式语音编解码实战:G.726 ADPCM库集成与优化指南

1. 项目概述与G.726 ADPCM技术背景在嵌入式语音处理领域,带宽和存储资源往往是寸土寸金的。如果你做过对讲机、VoIP网关或者早期的数字录音设备,一定对如何在有限的比特率下保住语音可懂度这件事深有感触。我当年接手一个车载调度系统的项目,…

阅读更多
ITU656格式化器寄存器配置实战:VBI数据处理与VCR特技播放兼容性
2026/6/23 4:51:28

ITU656格式化器寄存器配置实战:VBI数据处理与VCR特技播放兼容性

1. 项目概述与核心挑战在数字视频处理领域,将原始的视频数据、同步时序以及各种辅助信息打包成一个标准、稳定的串行数据流,是确保设备间互联互通的基础。ITU-R BT.656标准(常简称为ITU656)正是为此而生的一套“交通规则”。它定义…

阅读更多
嵌入式GUI开发实战:emWin环境搭建、配置优化与性能调优指南
2026/6/23 0:40:11

嵌入式GUI开发实战:emWin环境搭建、配置优化与性能调优指南

1. 项目概述与emWin核心价值解析在嵌入式系统开发领域,人机交互(HMI)的设计正从简单的LED指示灯和按键,快速向全彩图形化界面演进。无论是智能家电上的触摸屏、工业PLC的操作面板,还是医疗设备的参数显示,一…

阅读更多
3分钟快速上手:Qwen3大语言模型本地部署完全指南
2026/6/23 0:59:31

3分钟快速上手:Qwen3大语言模型本地部署完全指南

3分钟快速上手:Qwen3大语言模型本地部署完全指南 【免费下载链接】Qwen1.5 Qwen3 is the large language model series developed by Qwen team, Alibaba Cloud. 项目地址: https://gitcode.com/GitHub_Trending/qw/Qwen1.5 阿里巴巴Qwen3大语言模型系列以其…

阅读更多
微信聊天记录备份指南:使用WeChatExporter轻松保存您的珍贵回忆
2026/6/23 0:59:31

微信聊天记录备份指南:使用WeChatExporter轻松保存您的珍贵回忆

微信聊天记录备份指南:使用WeChatExporter轻松保存您的珍贵回忆 【免费下载链接】WeChatExporter 一个可以快速导出、查看你的微信聊天记录的工具 项目地址: https://gitcode.com/gh_mirrors/wec/WeChatExporter 在数字时代,微信聊天记录承载着我…

阅读更多
Cortex-M指令集深度解析:饱和运算、位域操作与分支控制实战
2026/6/23 0:59:31

Cortex-M指令集深度解析:饱和运算、位域操作与分支控制实战

1. 从指令到效率:为什么Cortex-M指令集值得深挖如果你在嵌入式领域摸爬滚打了一段时间,尤其是跟ARM Cortex-M系列单片机打交道,那你肯定对“写寄存器”、“调库函数”这套流程熟得不能再熟了。但不知道你有没有过这样的感觉:项目代…

阅读更多
GIT修改用户名
2026/6/22 5:10:42

GIT修改用户名

在GIT中修改用户名可按以下步骤操作: 查看当前git的用户名,使用命令git config --list或git config user.name。修改git用户名,使用命令git config --global user.name "xxx(新的用户名)",将其中…

阅读更多
Win11Debloat:让你的Windows系统重获新生的终极优化工具
2026/6/22 10:07:50

Win11Debloat:让你的Windows系统重获新生的终极优化工具

Win11Debloat:让你的Windows系统重获新生的终极优化工具 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to declutter and …

阅读更多
技术深度解析:m4s-converter实现原理与B站缓存视频转换最佳实践
2026/6/23 6:37:14

技术深度解析:m4s-converter实现原理与B站缓存视频转换最佳实践

技术深度解析:m4s-converter实现原理与B站缓存视频转换最佳实践 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter m4s-converter是一个…

阅读更多