某红书x-s加密算法补环境全解析:从环境检测到稳定生成

简介:针对某红书x-s签名参数生成的补环境版本算法包,主要面向爬虫逆向、JavaScript加密分析与Python服务端调试人员;资源采用Python execjs调用JavaScript实现,并附完整可用的接口调用Demo,便于直接复现x-s参数生成逻辑并接入自身项目。压缩包共2个文件,包含一个Python脚本与一个独立JS文件,整体约59KB,结构精简,适合快速部署与二次修改。已有1892人学习下载,说明该算法方案经较多开发者验证可用,具有一定参考价值。实际部署后,读者可获得直接运行的加密生成示例、Python与JS联调思路,以及补环境操作的关键铺垫,省去自行分析混淆代码的时间;资源适合两类场景:一类是需要临时绕过某红书签名校验的爬虫工程,另一类是希望理解x-s生成过程中DOM、浏览器对象等补环境细节的安全研究人员。

1. 某红书x-s加密算法补环境版本:一段能跑通的签名JS,到底补了什么

某红书x-s加密算法补环境版本(8.28更新)是我最近调试某红书web接口时最顺手的工具。它解决了一个很反直觉的问题:一段原本依赖真实浏览器才能运行的签名JS,在Node.js环境里只要把缺失的宿主对象按“能被检测代码认出是浏览器”的方式补齐,就能连续稳定地生成x-s参数,而不是一进去就报“window is not defined”。很多人把补环境当成玄学,其实它就是在模拟浏览器暴露给脚本的那几个全局对象:window、navigator、document、location等。这个版本适合熟悉抓包、想自己控制签名生成流程的开发者,也适合需要批量验证签名逻辑、做接口自动化的测试同学。

2. 拆解x-s签名链路:为什么脱离浏览器环境会失败,补环境补的是哪一层

2.1 签名前的“宿主探测”:算法先认环境,再算签名

某红书web端的x-s参数不是简单的输入输出运算。签名JS在真正计算签名之前,会先做一轮宿主环境检查,读取navigator.userAgent、window.chrome、document.readyState这类浏览器特征,用来确认自己是否跑在真实的浏览器页面里。把它直接扔进Node.js的global上下文,第一步就会遇到未定义对象。这个报错不是因为算法需要绘制页面,而是代码开头做了类似“检测不到window就抛异常”的防御。

补环境版本要做的,就是把这些对象按浏览器里的形态造出来。注意补环境不是简单创建一堆空对象。平台的环境检测会使用Object.getOwnPropertyDescriptor查看属性描述符,用Object.keys统计属性个数,还会触发getter校验返回值类型。空对象和真实浏览器对象在这些维度上差异很大。所以补环境版本里大量使用Object.defineProperty去模拟getter/setter,而不是直接给对象赋值。这也是为什么网上随手下的补环境脚本经常翻车:只补了属性名,没有补属性行为。我拆这个8.28版本时发现,它对navigator.webdriver的模拟就用了defineProperty把值固定为undefined,而不是简单赋值false,因为某些检测分支用“属性是否存在”来判断。

2.2 最小补环境清单:navigator、window、document 缺一不可

一份能稳定跑过环境检测的补环境脚本,至少要覆盖下面这些对象。以这个8.28版本为例,它并不是把整个浏览器搬过来,而是按“签名脚本实际访问清单”逐个补齐。下面是我对照源码整理的表格:

对象关键属性用途常见漏补点
windowchrome, DeviceOrientationEvent, AudioContext判定Chromium内核chrome对象里的属性顺序
navigatoruserAgent, platform, webdriver, languages浏览器身份webdriver必须为false或undefined
documentcookie, readyState, createElement环境噪音createElement返回的DOM对象
locationhref, hostname, origin页面地址origin与href要能对得上
screenwidth, height, colorDepth屏幕指纹部分版本会读取devicePixelRatio
canvasgetContext生成canvas指纹toDataURL返回值被检测

实际执行时,检测代码可能还会访问表外的属性。我一般会保留一份“属性访问日志”,运行一遍签名脚本后,把所有被读取过的属性导出来,缺哪些就补哪些。这个思路在第6章会演示一个具体的日志化方法。补环境对象不能只建一次,不同Node版本对原生对象的toString结果有差异,也会间接影响检测结果。

2.3 从补环境脚本到签名函数:一次调用的内部顺序

某红书这个补环境版本的入口文件是main.js,里面把补环境和签名逻辑放在同一个vm上下文里,执行顺序很关键:

  1. 注入基础对象:window、navigator、document等。
  2. 执行原始签名JS,让签名逻辑挂到window上。
  3. 捕获window上暴露出来的签名函数,例如window._sign。
  4. 对外导出一个封装函数,接收url、method、data、deviceId、cookie,返回x-s和x-t。

下面是我常用的Node.js调用方式:

const vm = require('vm'); const fs = require('fs'); const envCode = fs.readFileSync('./env_min.js', 'utf8'); // 补环境脚本 const signCode = fs.readFileSync('./core/sign.js', 'utf8'); // 原始签名JS const code = envCode + '\n' + signCode + '\n' + 'window.__getSigner();'; const sandbox = { console, setTimeout, clearTimeout, setInterval, clearInterval, }; vm.createContext(sandbox); const signer = vm.runInContext(code, sandbox); const result = signer({ url: '/api/some/endpoint', method: 'POST', data: {}, deviceId: 'device_test_001', cookie: 'a=b;c=d' }); console.log(result);

逻辑说明:先执行envCode,把window放进当前vm上下文;再执行signCode,让签名逻辑挂到window上。vm.createContext会把sandbox变成独立执行环境,避免污染外层Node进程。如果签名函数不是挂到window而是模块导出的,可以在代码末尾加一行捕获逻辑,但这个版本已经预留了__getSigner入口。

参数说明:setTimeout这些定时器是环境检测脚本经常访问的原生对象,直接注入即可;注意不要注入fs、child_process这类非浏览器对象,否则反而会被检测出异常。每次调用前都要重新创建sandbox,防止上一次运行的全局变量残留。

2.4 选型对比:为什么不用jsdom/happy-dom,而用手写补环境

虽然jsdom能在Node里模拟出window和document,但它在这个场景有两个明显问题。第一,jsdom的指纹特征太明显,检测脚本可以通过window.document.createElement返回的对象构造来识别,并且jsdom默认的navigator属性和真实浏览器差距较大;第二,jsdom加载慢、内存占用高,如果要做批量签名,几秒钟一次的速度根本扛不住。手写补环境只保留签名算法会访问到的属性和方法,体量小、可控性强。网上那些“纯补环境版”基本都是这个思路,只是每个人补的颗粒度不一样。

这个8.28版本在补环境脚本中使用了大量懒加载getter。也就是说,属性在被读取时才计算值,既减少了初始化成本,又能保证每次访问返回相同类型。比如navigator.userAgent在一次运行中必须保持恒定,如果用了random去生成,反而会触发环境检测的“多次读取一致性”校验。

2.5 一个最典型的检测点:navigator.webdriver

很多补环境脚本失效都坏在navigator.webdriver。这个属性在真实浏览器无自动化工具时是undefined,在有自动化工具时是true。有些检测代码不会直接读这个值,而是用“属性是否存在”来判断。所以补环境时不能简单地设置为false,而要保证属性本身存在,且读取返回undefined。下面是我在这份资源里常用的写法:

Object.defineProperty(navigator, 'webdriver', { get: () => undefined, configurable: true, });

如果直接用“navigator.webdriver = false”,在部分Chrome版本里反而会因为属性描述符与预期不符而暴露。补环境版本把这类细节都处理过了,这也是它当前可用(8.28更新)的原因之一。理解这个检测点后,遇到后续版本失效,你就知道先查哪里了。

3. 在Node.js和Python中跑通资源:目录结构、执行方式与参数说明

3.1 资源目录结构:核心文件与加载顺序

拿到这份资源,第一件事是先看目录结构,别一上来就运行。我拆的版本大致是这样的:

xhs-sign-env/ ├── env/ │ ├── window.js # window、location、screen等 │ ├── navigator.js # navigator及UA信息 │ ├── document.js # document、cookie │ └── index.js # 组装所有补环境对象 ├── core/ │ ├── sign.js # 原始签名JS(已改写为可挂载) │ └── signer.js # 封装后的签名函数 ├── run.js # Node.js入口 ├── test.py # Python调用示例 └── package.json

加载顺序是:window -> navigator -> document -> 原始签名JS。这里最容易犯的错是先加载sign.js再补环境,导致签名JS里第一个全局判断就挂了。在run.js里我也踩过这个坑,后来把顺序固定成上面这个后一次通过。README里写得很清楚,但建议自己手里也留一份加载顺序说明,避免换机器后重新踩坑。

3.2 用Node.js加载补环境脚本并生成x-s

run.js是整个Node入口,参考代码如下:

const fs = require('fs'); const vm = require('vm'); const files = [ './env/window.js', './env/navigator.js', './env/document.js', './env/index.js', './core/sign.js', ]; function createRuntime() { const sandbox = { console, setTimeout, clearTimeout, setInterval, clearInterval }; vm.createContext(sandbox); for (const file of files) { const code = fs.readFileSync(file, 'utf8'); vm.runInContext(code, sandbox); } return sandbox; } function sign(url, method, data, deviceId, cookie) { const sandbox = createRuntime(); const getSign = sandbox.__getSigner; if (!getSign) throw new Error('未找到签名入口'); const signer = getSign(); return signer({ url, method, data, deviceId, cookie }); } console.log(sign('/api/some/endpoint', 'POST', {}, 'device_test_001', 'a=b;c=d'));

逻辑说明:createRuntime每次生成全新的沙箱,避免签名之间内存串味;__getSigner是在sign.js末尾由补环境版本额外注入的,不是原始签名JS自带的字段。注意每次调用都会重新加载全部文件,性能不是最优,但稳定性优先,后面封装服务时可以用常驻进程优化。

参数说明:deviceId不能每次随机,否则签名虽然能生成,但后续带同一个设备指纹去请求时,服务端会认为“设备指纹变化频率异常”。cookie一般传浏览器里的完整cookie字符串,也可以在资源里固定一组仅供测试的cookie。

3.3 用Python的execjs调用同一套脚本

虽然资源里有Node入口,但实际项目里更多是用Python做调度。常见做法是让Python调用本地Node.js来执行JS,推荐使用execjs库。示例代码:

import execjs with open('./core/signer.js', 'r', encoding='utf-8') as f: js_code = f.read() ctx = execjs.compile(js_code) result = ctx.call( 'signForPython', '/api/some/endpoint', 'POST', {}, 'device_test_001', 'a=b;c=d' ) print(result)

逻辑说明:signer.js是从run.js里抽出来的CommonJS模块,但execjs环境里不能直接require,所以在末尾加了一个全局函数signForPython,把所有参数透传给内部签名函数。execjs默认使用系统里的node作为JS运行时,因此需要先确保node命令可用,否则会报“RuntimeError: Could not find any JavaScript runtime”。

参数说明:execjs的ctx.call每次调用都会执行一次编译后的上下文,但不会清除全局状态。多线程同时调用同一个ctx时,需要注意加锁或每线程单独compile,否则可能产生签名串号。我一般每个线程单独compile一次,或者用5.1节里的HTTP接口去串行化。

3.4 请求参数对照:x-s、x-t、device_id 和 cookie 谁在参与签名

把常见参数列一个表,便于照着抓包结果填写:

参数名是否参与签名说明
url是一般指path+query,不含域名
method是GET/POST,大小写敏感
data是POST body或query参数,需要按特定格式序列化
device_id是设备指纹,由前端生成或服务端下发
cookie是至少要包含关键会话字段,缺失会导致签名与请求头不一致
x-t是毫秒时间戳,通常由签名函数内部生成
x-s结果最终签名值

注意:不同版本的算法对url取值是否带query有差异,建议直接用抓包里DevTools请求的完整URL,先不要手动拼接。尤其是GET请求,query参数顺序也会影响签名结果。

3.5 跨语言调用时的常见误用

我在给别人演示这个资源时,发现有几个误用很常见。第一个是直接读取x-s而不传cookie,导致服务端判定签名缺失。第二个是把签名服务的返回值当成永久有效,实际上x-s和x-t的时效一般在几分钟内,过期后需要重新生成。第三个是在Python里反复用同一个ctx,导致VM上下文里的临时变量不断累积。如果发现运行几十次后第一次输出变慢,多半就是上下文被撑大了。建议定期重启进程或按需创建新ctx。理解这些误用,能少踩很多坑。

4. 避坑:补环境版本最常见的五个翻车场景与排查路径

4.1 现象:直接运行报“window is not defined”

原因:加载顺序错了。补环境脚本没有在原始sign.js之前执行,或者window.js只是声明了一个变量,没有把它挂到全局上下文里。在Node的vm中,window需要显式挂到sandbox上,普通变量声明不会成为全局属性。解决:确认window.js里使用的是“globalThis.window = ...”或“var window = ...”,并且在加载sign.js前先运行env/index.js。我试过把env/index.js放在sign.js后面,结果一路抛错,改回顺序后就好了。

4.2 现象:脚本执行起来就死循环,CPU直接拉满

原因:签名脚本中有类似“while (typeof window === 'undefined')”的重试逻辑,或者补环境的某个对象用Proxy拦截时出现递归调用。常见于把window赋值为一个Proxy,但get trap里又去读自身属性,比如return obj[prop]中的obj指向了Proxy自身,就会无限递归。解决:为Proxy的get设置白名单,只对“未定义属性”打日志,已定义属性直接返回;检查补环境脚本里是否有setTimeout循环,必要时临时注释掉环境检测里的大循环,先跑通签名那一层。

4.3 现象:签名生成成功但接口返回“签名校验失败”

原因:签名时使用的device_id或cookie与请求头不一致。补环境版本默认带一组演示参数,如果直接用确定目标接口去请求,需要把抓包得到的cookie和deviceId传入签名接口。解决:在签名前打印参与签名的原始字符串,与浏览器抓包里实际的请求头做对照,重点看x-t是否与当前时间戳一致。很多时候问题不是算法不对,而是参数被调用方传错了。

4.4 现象:8.28更新版本隔天又失效

原因:某红书web端会不定期更换签名算法或环境检测策略。补环境版本只能针对当前检测规则打补丁,一旦检测点变化,比如新增了对screen.orientation或navigator.deviceMemory的读取,原本的补环境脚本就会漏项,导致签名逻辑进入错误分支。解决:保留上一版本的补环境脚本和签名JS,出新版本时做diff,多数情况是新增了某个属性检测。用第6章的属性访问日志能最快定位漏项。

4.5 现象:多线程调用后签名偶尔为空

原因:Node.js的vm上下文不是线程安全的,多个worker共享同一个sandbox时,全局变量会被互相覆盖。尤其是__getSigner这个入口,可能在A线程运行后B线程读取到同一个函数指针,但状态已经错乱。解决:每个worker线程独立加载一份完整环境,或者把签名操作收敛到单进程HTTP接口,由队列串行化处理。这个坑我排查了快半小时,最后发现是context被复用导致的。

这些坑都记录在资源的README里,但我建议自己再走一遍,因为换Node版本或操作系统后,表现会有细微差别。尤其是Windows下,console对象的一些方法在vm沙箱里不可用,需要手动注入空实现。

5. 把补环境版本封装成稳定签名服务:接口化、验证与失效监控

5.1 封装成HTTP签名接口:让Python、Java或其他端复用

把补环境版本变成服务,可以避免每个语言都去编译JS。我用Express做了一层薄封装:

const express = require('express'); const { createRuntime } = require('./run'); const app = express(); app.use(express.json()); app.post('/sign', (req, res) => { const { url, method = 'GET', data = {}, deviceId, cookie } = req.body; if (!url || !deviceId) { return res.status(400).json({ code: 1, message: '缺少参数' }); } try { const sandbox = createRuntime(); const signer = sandbox.__getSigner(); const result = signer({ url, method, data, deviceId, cookie }); res.json({ code: 0, data: result }); } catch (e) { res.status(500).json({ code: 500, message: e.message }); } }); app.listen(3000, () => console.log('sign service on :3000'));

逻辑说明:每次请求调用createRuntime生成沙箱,虽然慢一点但很干净,适合低频内部使用。如果QPS高,可以做一个池子存放预热好的sandbox,但要处理串号问题。接口只接收必要参数,不信任外部传入的header,避免被绕过。这个接口只负责生成签名,不负责发起请求,职责分离后方便排查问题。

5.2 验证签名是否正确:一组固定参数 + 真实回包检查

签名生成后怎么判断它对不对?靠肉眼看不靠谱。我给自己定了一套验证流程:

  1. 用抓包工具拿到一条真实请求的url、method、data、deviceId、cookie。
  2. 把这组参数传给签名接口,得到x-s、x-t。
  3. 用同样的url、cookie和x-s/x-t重新发起一次HTTP请求,看返回状态。
  4. 如果返回验证码或签名错误,则说明签名和当前请求头不匹配。

资源里附了一个test_sign.py,会把返回的状态码和body前200个字符打出来。执行完后对比抓包记录,基本能定位是参数问题还是补环境漏项。验证签名最重要的是“固定参数”,不要每次随机生成deviceId,否则无法判断是不是签名算法本身的问题。

5.3 失效监控:定时拨打签名探针,第一时间发现版本过期

补环境版本是动态维护的,不能上线后就不管。我一般会在服务器上挂一个定时任务,每30分钟跑一次探针:

*/30 * * * * cd /opt/xhs-sign && python3 probe.py >> probe.log 2>&1

probe.py里做的事很简单:用固定的测试账号参数生成x-s,再请求一次公开接口,判断是否返回200。如果连续3次失败,就发一条告警到工作群。这样算法失效时,我能第一时间切到新补丁,而不是等到用户反馈出问题。探针里的cookie和deviceId要单独准备,不要影响正式业务数据。监控日志要保留最近7天,方便回溯失效时间点和补丁更新周期的对照。

6. 最后一个技巧:用属性访问日志定位补环境漏项

补环境版本最磨人的不是计算逻辑,而是环境检测漏项。很多失效看起来像算法变了,实际只是检测脚本多读了一个属性。我养成了一个习惯:给window和navigator外层包一层Proxy,记录所有属性访问,把漏掉的属性打出来。

function accessLogProxy(target, label) { return new Proxy(target, { get(obj, prop) { if (!(prop in obj)) { console.log(`[${label} miss] ${String(prop)}`); } return obj[prop]; } }); }

把这层Proxy包在现有补环境对象外,再运行签名脚本。日志中出现的所有[window miss]或[navigator miss],就是接下来要补的位置。不要一股脑全补,先看哪些属性参与了分支判断,优先补那种返回布尔值或对象类型的属性。比如发现漏了navigator.deviceMemory,就可以补一个数字;漏了screen.orientation,就补一个包含angle属性的对象。

相比一遍遍搜索补环境补丁,这个日志化的方法能帮你把漏项收敛到具体属性名。从那以后,我每次遇到版本失效都强制走一遍这个流程:跑一次带日志的签名,收集漏项,补完清空日志再跑,直到一通到底。希望这个思路也能帮到你。

本文还有配套的精品资源,点击获取

相关新闻

NTP部署后的时间同步监控:健康度指标与告警实践

NTP部署后的时间同步监控:健康度指标与告警实践

NTP部署完之后,很多团队的第一反应是“终于搞定时间同步了,后面不用管了”。但真正的运维工作恰恰是从这里开始的。我自己就经历过一个挺典型的场景:某个业务模块突然出现大量订单时间错乱,排查了半天才发现是NTP服务早在一个月前…

2026/10/20 11:34:31 阅读更多 →
VS2019快速集成wxWidgets二进制包实战指南

VS2019快速集成wxWidgets二进制包实战指南

1. 项目概述:为什么“直接使用二进制文件”是wxWidgets开发中最常被卡住的第一关 在Visual Studio 2019环境下配置wxWidgets,绝大多数人踩进的第一个坑,不是代码写错,也不是逻辑出问题,而是——连编译都过不去。你下载…

2026/10/20 11:33:30 阅读更多 →
AI芯片设计黑盒困局:从不可解释到可控黑盒的工程实践

AI芯片设计黑盒困局:从不可解释到可控黑盒的工程实践

“AI 在芯片领域依然是个黑盒。”这句话不是我从某篇报告里抄来的,是我在上一个流片项目的复盘会上,被自己的算法同事一句一句追问出来的。当时我们上线了一个辅助布局优化的AI模型,指标提升很漂亮,可一旦被问到“为什么这几百个标…

2026/10/20 11:33:30 阅读更多 →

最新新闻

AI精准改图完全指南:从局部重绘到参数调优,告别熬夜修图

AI精准改图完全指南:从局部重绘到参数调优,告别熬夜修图

熬过夜的都知道,改图这事有多磨人。一张图抠半天、修到凌晨两三点,最后甲方一句“感觉不对”,所有努力直接归零。以前朋友圈里做设计的、做电商的、搞自媒体的,几乎人人电脑里都躺着几个修图软件,可真正能把“改图”这…

2026/10/20 12:24:14 阅读更多 →
AI Agent实战指南:从任务拆解到稳定运行的完整方法

AI Agent实战指南:从任务拆解到稳定运行的完整方法

别的不说,“AI Agent”这三个字,最近两年是真的被聊烂了。从各种编程圈的分享到产品经理的需求文档,好像不沾点 Agent 就不够前沿。但等到自己真正上手,把一个大模型接上工具、丢给它一个目标,让它自己去跑&#xff0c…

2026/10/20 12:24:14 阅读更多 →
FreeRTOS中断管理:BASEPRI寄存器如何实现选择性临界区保护

FreeRTOS中断管理:BASEPRI寄存器如何实现选择性临界区保护

嵌入式系统里做中断管理,最怕的不是中断多,而是你以为关了中断、临界区就安全了,结果系统跑着跑着就“死”给你看。我之前在一块基于Cortex-M3内核的MCU上调试 FreeRTOS 项目,就撞上过这种诡异问题:主循环和定时器中断…

2026/10/20 12:24:14 阅读更多 →
从零训练64M大模型:3块钱2小时跑通MiniMind全流程

从零训练64M大模型:3块钱2小时跑通MiniMind全流程

凌晨一点多,我盯着云GPU控制台上的费用曲线,结束训练按钮点下去那一刻,账单数字定格在几块钱。过去这两个小时,我跑完了一个叫 MiniMind 的开源项目,亲手把一个64M参数的大语言模型从随机初始化一路训练到能和我正常对…

2026/10/20 12:24:14 阅读更多 →
OpenCV二值化从入门到实战:固定阈值、大津法与自适应阈值详解

OpenCV二值化从入门到实战:固定阈值、大津法与自适应阈值详解

1. 从像素到黑白:二值化的本质与应用场景1.1 二值化到底把图像变成了什么一上来先别急着敲代码,先把“二值化”这三个字拆开。二值化本质上是对灰度图像做一次像素级分类:每个像素点的值只要大于某个阈值,就归到一类,小…

2026/10/20 12:24:14 阅读更多 →
MATLAB小波分析实战手册:EEG/ECG/振动信号降噪与特征提取

MATLAB小波分析实战手册:EEG/ECG/振动信号降噪与特征提取

简介:本资源是《MATLAB小波分析超级学习手册》配套的完整程序代码包,面向信号处理、图像分析及科研工程领域的MATLAB初学者与进阶用户,聚焦小波理论落地与工程实践能力提升。压缩包含119个文件(113个.m函数脚本、4个.wav测试音频、…

2026/10/20 12:23:13 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/20 10:02:08 阅读更多 →
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/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练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/20 9:50:45 阅读更多 →