QQ农场自动化挂机:WebSocket协议逆向与Nodejs客户端实战
简介QQ经典农场自动化挂机脚本项目是一套基于Node.js技术栈的完整工程源码面向希望实现QQ/微信双平台农场游戏自动托管的中高级开发者。项目通过深度逆向分析WebSocket通信协议模拟真实客户端与服务器交互实现自动登录、种植、收获、好友互动等全流程管理。压缩包共37个文件含15个JavaScript脚本、10个Protocol Buffers定义文件、6个JSON配置及说明文档等其中proto文件用于解析游戏协议JSON配置涵盖作物等级、道具与商店数据JS代码则负责任务调度和网络通信整体仅122KB结构紧凑。已有6263人学习下载。除可直接运行的Node.js源码外资源还提供原理解读的说明文件与附赠文档帮助读者掌握WebSocket帧结构、握手机制及游戏指令构造方法适合用作实时通信逆向与自动化脚本开发的实践参考。1. QQ经典农场自动化挂机脚本一场 WebSocket 协议逆向战QQ经典农场自动化挂机脚本解决的是你人不在线、农场却还在运转的问题种菜、收菜、偷菜、施肥、卖仓这一整套循环得自己跑下去。多数人第一反应是图像识别加模拟点击但真跑三天就会发现又慢又不稳——作物熟没熟靠截图判断页面一卡就翻车。这个项目走的是协议层路线把小程序背后的 WebSocket 通信协议逆向清楚用 Nodejs 直接连游戏网关所有操作走消息不做界面模拟。路线听起来硬核但它恰恰是这类游戏自动化里最可靠的一种也适合所有想研究小程序协议逆向、Nodejs 长连接开发的从业者。这里有个容易被低估的前提农场游戏不是简单请求应答作物成熟、好友偷菜、收益结算是服务端主动推给客户端的所以整个项目的地基是 WebSocket而不是 HTTP。逆向产物就是标题里那个 ProtocolB.zip它承载的是从抓包到可调用代码之间的全部协议定义。接下来按实际落地顺序讲清楚怎么逆向、怎么用 Nodejs 跑起来、怎么调度、怎么适配双平台、以及踩过的那些坑。2. 逆向分析WebSocket协议从小程序抓包到还原可重放的消息序列2.1 先抓包再说Charles配置与微信/QQ小程序流量捕获做协议逆向我习惯先用 Charles 抓一轮完整的交互而不是直接翻代码找逻辑。原因很简单小程序是编译后的包代码可读性差但网络层不会骗人——一次种菜客户端往服务端发了什么、收了什么全部一目了然。Charles 在 WebSocket 消息展示上比同类工具直观能按域名过滤、能逐帧看文本和二进制内容手机端配置也成熟适合做第一轮摸底。配置步骤通常是固定的电脑上启动 Charles 的 HTTP 代理默认监听 8888 端口。手机和电脑连同一个 Wi-Fi手机代理指向电脑 IP:8888。手机浏览器访问 Charles 的证书下载页安装并信任 SSL 证书Android 7 以上建议把证书装进系统证书区否则小程序层的请求可能不被解密。打开 QQ 或微信里的农场小程序随便做一次种菜动作然后回 Charles 按ws过滤就能看到 WebSocket 握手和后续帧。QQ 和微信是两个入口网关域名和鉴权头大概率不同所以过滤时分开处理微信入口看wx开头的域名QQ 入口看qq开头的域名。两者连的是同一套业务逻辑但握手带的 Cookie 和自定义头不一样后面做适配时用得到。抓到 WebSocket 帧之后第一件事是确认消息长相。这一步不要急着上工具先用肉眼看十来条消息是 JSON 还是纯二进制有没有明显的 cmd 字段时间戳长什么样只要消息里有 JSON后续分析会轻松一半。2.2 拆帧文本帧和二进制帧分别怎么解小程序游戏网关的 WebSocket 消息常见两种形态一种是全 JSON 封装可读性好cmd、body、seq 都裸露在文本里另一种是二进制协议消息头固定几个字节后面跟着变长的字段。农场类游戏我遇到的多数是 JSON 外壳混合二进制内容比如头像数据、地图配置走二进制业务指令走 JSON。判断一条消息能不能直接解析我一般用一段很短的 Nodejs 探针脚本在本地把抓到的帧重新解析一遍// frame-decoder.js本地帧解析探针 function tryDecodeFrame(data) { const buf Buffer.isBuffer(data) ? data : Buffer.from(data); const text buf.toString(utf8); // 先按 JSON 尝试农场业务的指令消息基本都是 JSON 外壳 if (text.startsWith({) || text.startsWith([)) { try { return { kind: json, payload: JSON.parse(text) }; } catch (_) { // 有些 JSON 被截断或加密落到底层 hex 处理 } } // 二进制消息只打印前 64 字节的 hex用于人工比对 return { kind: binary, preview: buf.slice(0, 64).toString(hex) }; }这段脚本的思路是先用 JSON 解析试探失败再落回 hex。二进制的 hex 比对有固定套路——同一个动作多触发两次把两次 hex 逐字节对比不变的部分就是消息头和固定字段变的部分是时间戳、自增序号和数值字段。slice(0, 64)限制在前 64 字节是因为消息头通常在头部再往后的内容不是包体就是加密数据打印出来也没有比对意义。参数上的注意点Buffer.from(data)要处理 data 可能已经是 Buffer 的情况utf8解码对纯二进制会出乱码所以 JSON 解析失败后不要继续做字符串加工直接转 hex避免二次污染。2.3 还原关键动作种菜、收菜、偷菜在协议里长什么样抓到消息并确认格式后接下来的工作是把业务动作还原成协议消息。拿种菜举例一次完整动作往往不是单条消息而是一个序列先farm.sync拉当前农场全量状态再farm.plant下发种植指令服务端回farm.plant.resp确认最后推送一条farm.update把新状态广播回来。所以还原时不要只看一条消息要看一组消息的先后关系。动作请求 cmd 示例核心字段服务端响应种菜farm.plantlandId, seedId, tsfarm.plant.resp farm.update收菜farm.harvestlandId, matureAtfarm.harvest.resp reward.notify偷菜farm.stealfriendId, landId, stealCountfarm.steal.resp farm.update施肥farm.fertilizelandId, fertilizerIdfarm.fertilize.resp字段的含义要结合服务端响应来猜然后做最小验证用测试账号把还原出来的消息手动回放一次看服务端是否返回成功码。回放验证这里有一个关键纪律——不要把抓到的登录态原样拿去生产环境重放登录态属于账号凭据自己测试账号上验证即可。很多人忽略这一点直接用大号抓包重放结果触发风控被限制登录这是最容易翻车的地方。当一组动作能稳定复现成功响应后ProtocolB 的骨架就有了每个 cmd 对应一组字段定义每个字段有类型和取值范围。把这些整理成一份 JSON 定义文件逆向阶段就算告一段落后面 Nodejs 客户端就是照着这份定义写的。3. Nodejs实现协议客户端握手、心跳、重连一次跑通3.1 环境准备npm.ps1执行策略报错与国内镜像源Nodejs 环境准备时Windows 上最常见的坑就是 npm 命令直接报错npm : 无法加载文件 ... npm.ps1因为在此系统上禁止运行脚本。这是 PowerShell 默认执行策略限制脚本运行导致的不是 Nodejs 装坏了。解决方式是在当前用户维度放开执行策略不需要动系统级设置# 以当前用户维度放开 PS 脚本执行避免每次开终端都报 npm.ps1 错误 Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # 顺手把 npm 源切到国内镜像包安装失败率会低很多 npm config set registry https://registry.npmmirror.com两个命令分开看RemoteSigned表示本地脚本可以运行下载的脚本需要签名比Unrestricted安全既解决了 npm.ps1 的报错又不至于放开所有脚本npm config set registry切的是依赖下载源ws这类包在默认源下也很快但如果你在公司网络或某些网络环境下默认源经常超时切国内镜像能省掉很多重试。验证方式就是npm config get registry看到输出的地址是自己设置的那个就成了。3.2 用ws模块建立第一条连接依赖装好之后核心工作就是用ws模块建立一条真实的 WebSocket 连接。这一步的关键不在连接本身而在握手时的伪装——小程序网关会校验 UA、Cookie 和自定义头缺一个都可能被拒。所以建连时要带上抓包阶段拿到的客户端头信息const WebSocket require(ws); let seq 0; // 业务序列号服务端用它做乱序检测 const authToken process.env.AUTH_TOKEN; // 来自抓包阶段的登录态 const ws new WebSocket(wss://farm-gw.example.com/gateway, { headers: { User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 Mobile/15E148 QQ/8.9.0, Cookie: authToken, }, handshakeTimeout: 10000, }); ws.on(open, () { // 登录态校验具体字段以第2章逆向结果为准 ws.send(JSON.stringify({ cmd: auth.login, seq: seq, body: { platform: qq } })); }); ws.on(message, (data) { const frame tryDecodeFrame(data); // 先打日志确认链路通后续再替换成业务分发 console.log(frame); });这里有几个容易被忽略的点。UA 里写 iPhone 端是因为我抓包时用的就是手机端小程序PC 端 UA 很容易被网关视为异常设备直接拒绝连接Cookie直接用抓包拿到的登录态串这是最快跑通的方式但要注意登录态会过期后面第 4 章会讲怎么自动续期handshakeTimeout: 10000表示 10 秒内 WebSocket 握手没完成就主动报错这个参数在生产里非常有用不然网络异常时连接会一直悬着。seq的自增也重要。很多网关会校验业务序号是否连续乱序或跳跃会直接判定为异常客户端。所以这里 seq 千万不要每帧都从 0 开始全局递增即可断线重连后也要继续不能重置。3.3 心跳与断线重连参数怎么设才不会掉线连接建立后第二件必做的事是心跳。农场类游戏的网关普遍有连接空闲回收策略我逆向过的几个例子服务端大约 90 秒没有收到任何数据就会主动断开客户端毫无预兆地被 close。而游戏本身不是时刻都有消息所以你必须主动发心跳证明自己还活着。这里的心跳优先走 WebSocket 协议层的 ping 帧而不是业务层发一条{cmd:heartbeat}的 JSON。原因有两条一是协议层 ping/pong 不经过业务逻辑服务端处理成本低响应也快二是很多网关会对业务心跳单独做频控你发得太勤反而触发风控。实现时可以这样设计let lastPongAt Date.now(); let retryCount 0; const HEARTBEAT_INTERVAL 45000; // 服务端空闲超时的一半留足余量 const PONG_TIMEOUT 60000; // 超过60秒没收到pong就认定连接异常 function startHeartbeat(client) { const timer setInterval(() { if (Date.now() - lastPongAt PONG_TIMEOUT) { client.terminate(); // 主动掐断触发重连逻辑 clearInterval(timer); reconnect(); return; } client.ping(); }, HEARTBEAT_INTERVAL); } function reconnect() { const delay Math.min(30000, 1000 * Math.pow(2, retryCount)); retryCount; setTimeout(createClient, delay); }参数设计上45 秒发一次心跳是基于 90 秒服务端阈值的一半来定的留了双倍余量网络抖动也不至于被掐60 秒没收到 pong 才判定异常是因为偶发丢包时 pong 可能延迟几秒到十几秒判定太紧容易误杀正常连接。重连用指数退避——第一次 1 秒、第二次 2 秒、第三次 4 秒上限 30 秒避免服务端还没恢复时你这边高频重连把自己搞成攻击流量。注意retryCount在成功连接后要重置为 0否则断一次线之后重连间隔会永远停留在高位。3.4 接入ProtocolB.zip把逆向产出整理成可调用模块连接和心跳跑通后接下来的工作就是把第 2 章的逆向产出固化成一个可调用模块。ProtocolB.zip 这类包解压后常见的样子是消息类型枚举、字段定义文件、以及统一的编解码入口三者分离。我一般会把它整理成这样的结构protocol-b/ ├── index.js # encode/decode 统一出口 ├── message-types.json # cmd 名称与数值的映射表 └── codec/ ├── index.js # 按类型分发编解码 ├── varint.js # 消息头里的变长整数解析 └── farm.fields.json # 每个 cmd 的字段顺序与类型定义接入时不要直接在业务代码里散写协议字段而是全部走 ProtocolB 的出口。拿种菜来说应该是这样const ProtocolB require(./protocol-b); // 用消息名代替数字 cmd避免业务代码里到处是裸数字 const MSG ProtocolB.messageTypes; ws.send(ProtocolB.encode(MSG.FARM_PLANT, { landId: 3, seedId: 1024, ts: Date.now() }));这样做的理由很实际一旦服务端调整协议字段顺序你只需要改farm.fields.json里的定义业务层代码一行不用动。ts字段统一用毫秒时间戳不要用本地时间字符串服务端通常按时间戳做校验字符串格式容易解析失败。这里需要提醒的是ProtocolB 里的编解码逻辑一定要和抓包时的帧格式完全对应——如果是 JSON 外壳encode 就是普通序列化如果是二进制encode 就要按字段类型拼 Buffer处理不好就是辛辛苦苦逆向完跑起来全是乱码。4. 经典农场全自动管理调度策略与多账号并发4.1 把农场动作映射成协议消息序列协议客户端能收发消息后剩下的问题就是怎么组织业务逻辑。农场的每个动作都不是独立消息而是一组消息的编排。以收菜为例正确的消息序列是先farm.sync同步状态确认哪些土地成熟然后逐块地发farm.harvest收完再拉一次farm.sync确认状态落库。偷菜则是先friend.sync拉好友列表再friend.farm.list拿好友农场详情找出成熟但未被收的地发farm.steal。这个序列不能反。有些写挂机脚本的人图省事直接每隔几分钟暴力发一遍farm.harvest结果服务端返回无成熟作物不算严重严重的是这种无脑轮询会被网关的频控捕捉判定为脚本行为。正确的做法是把状态同步放在最前面用服务端推回来的数据做决策依据。4.2 调度时间窗成熟时间、偷菜窗口与随机延时调度器的核心逻辑是围绕时间窗设计的。作物有成熟时间服务端会在成熟前后推farm.update消息所以你的脚本不需要定时轮询只要在收到更新消息后判断当前时间与matureAt的关系即可。判断时留一个合理的提前量因为从判断到消息送达有网络延迟async function runRound(api) { const state await api.farmState(); for (const land of state.lands) { const now Date.now(); // 成熟判定带2秒提前量补偿网络耗时避免刚好卡在成熟瞬间丢消息 if (land.state growing land.matureAt now 2000) { await api.harvest(land.id); await sleep(rand(300, 800)); // 随机休息300~800ms避免连发 } // 空地和未锁定的土地自动补种 if (land.seedId 0 land.lock false) { await api.plant(land.id, chooseSeed(land)); } } }这里的随机延时非常重要。如果你的脚本每次收菜间隔都是精确的 500ms人眼都能看出是机器行为。rand(300, 800)把间隔控制在 300 到 800 毫秒之间随机浮动一方面不会太慢影响收菜效率另一方面让操作节奏接近真人手速。补种逻辑里的land.lock是服务端返回的土地状态有些地解锁需要条件等级或金币判断时不加这个字段脚本会反复尝试种不了的地白白触发错误日志。偷菜窗口又是另一套逻辑好友作物成熟后的前几秒是竞争最激烈的窗口手速慢了就被别人偷走。这里我会把偷菜延时压在 600ms 以内优先偷成熟时间最近的地因为那些地还没被其他好友扫过。4.3 多账号并发与 token 失效的自恢复挂机脚本跑上几天就会遇到一个现实问题token 过期。小程序的登录态不是永久的通常是几小时到几天。token 失效的特征很典型——连接仍然正常但第一条auth.login就返回错误码或者中途开始频繁掉线重连。处理方案是定时预刷新而不是等报错再处理let token loadToken(account); // 剩余有效期低于5分钟就提前刷新避免正在收菜时突然断链 if (token.expireAt - Date.now() 5 * 60 * 1000) { token await refreshToken(account, token.refreshToken); saveToken(account, token); }刷新令牌一般来自第一轮登录时服务端下发的refreshToken它与业务 token 不同专门用于续期。如果连refreshToken都过期了就需要重新走一次小程序登录流程——这个环节只能半自动因为涉及验证码或手机号验证不做全自动是刻意为之否则账号风控风险会急剧上升。多账号并发时我习惯一个账号一条独立连接业务逻辑里用账号 ID 做路由。Nodejs 单线程处理这些长连接没有压力真正要注意的是不要用同步阻塞操作处理消息回调比如大规模 JSON 解析或日志写盘这些会卡住事件循环导致其他账号的心跳发不出去。遇到重负载的响应解析把它扔进setImmediate或丢给子线程保证心跳永远不受影响。5. QQ与微信双平台适配同一套协议两套登录态5.1 平台差异排查网关、消息头与渠道号同一个农场游戏在 QQ 小程序和微信小程序里跑的是同一套业务逻辑但网关层有明显差异。QQ 端的登录鉴权走的是 QQ 的 skey 体系微信端走的是 code2session 换取的 ticket 体系。这意味着你在第 2 章抓包时必须两个平台各抓一遍不能指望一套 headers 通吃。维度QQ 小程序微信小程序登录鉴权Cookie 里的 skey / p_skeycode2session 换取的 ticket自定义头通常带 qq-ext 渠道头通常带 x-wx-ticket 请求头消息体同一 cmd字段名偶尔不同同一 cmd字段名偶尔不同实际适配中字段名的差异最坑人。同一个farm.plant微信端叫landIdQQ 端可能叫land_index值一样但名字不同。这个只能在抓包对比阶段就发现好在 ProtocolB 的farm.fields.json设计成按平台分目录就能解决const platform process.env.PLATFORM || qq; const fields require(./protocol-b/codec/${platform}.farm.fields.json);5.2 登录态管理token刷新与设备指纹双平台的 token 生命周期差异也大。微信小程序的 ticket 时效比 QQ 的短如果你的脚本同时跑两个平台微信端明显更容易掉线。所以登录态管理要按平台分别配置刷新策略不要用同一个定时任务处理。设备指纹是另一个容易踩坑的地方。QQ 和微信的网关都会校验设备信息常见做法是读取手机型号、系统版本、网络类型上报。脚本如果完全不带这些字段握手阶段就会被拒。我在适配时会把抓包抓到的设备信息固化到配置文件里不随意改动因为同一个账号频繁更换设备指纹比不换设备更容易触发风控。5.3 配置分离按平台、账号、模式拆开环境变量双平台跑起来之后配置就变得复杂了不能再在一份代码里写死。我一般按三个维度拆分配置平台qq/wx、账号多账号时每个账号一套、运行模式演示/正式。用环境变量做入口# .env 示例 PLATFORMwx ACCOUNT_IDfarm_001 MODEproduction LOG_LEVELinfo配置加载后用config[platform]访问对应参数比如心跳间隔、token 刷新阈值、偷菜延迟窗口都可以按平台给不同值。这样做的价值在于换平台跑的时候改环境变量就能切不用改代码多账号场景下每个账号的登录态、调度参数天然隔离不会互相污染。6. 避坑宝典掉线、封号、协议升级的三类高发事故6.1 一个现象背后的三类坑挂机脚本跑起来之后真正的问题才会浮出来。这里列几个最典型的事件。第一个高发事故是早晨起来发现脚本全部离线日志里全是 socket closed。现象是连接悄无声息地断掉断之前没有任何异常。原因几乎都是服务端空闲超时90 秒没收到任何数据就回收连接。解决方式就是第 3 章讲的 45 秒心跳机制间隔必须小于服务端阈值的一半留足网络抖动余量。第二个高发事故是微信端频繁报 1006 错误码。现象是 QQ 端运行正常同一套代码切到微信端就反复断连。原因不是 WebSocket 本身的问题而是请求头里少了微信网关要求的x-wx-ticket头。解决方式是回到抓包阶段把微信端的握手 headers 完整比对一遍缺哪个补哪个不要只盯着消息体外层。第三个高发事故是操作频繁触发行为异常提示。现象是脚本收菜收得好好的突然账号被限制操作几小时。原因是操作节奏太固定每次收菜间隔 500ms凌晨 3 点也在线行为特征完全不像真人。解决方式是调度里加随机延时、设置夜间休息窗口、不要对同一个好友连续偷菜。这个坑最难排查因为不是代码逻辑问题而是行为模式问题。6.2 判断脚本健康度的三个检查点我自己巡检脚本时只看三个东西连接层看 ping/pong 延迟是否稳定、消息层看 seq 序号是否连续、数据层看本地时间戳与服务端下发的时间戳偏差。任何一个指标异常都可能是协议升级的前兆。协议升级时decode 出来的消息会突然出现乱码或未知字段此时要先停脚本重新抓包对比消息头而不是盲目改解析逻辑。做这种项目久了我最大的感受是协议逆向本身不难难的是敬畏心。不要拿主账号直接上先用小号跑一周确认调度节奏、token 续期、双平台适配都稳定了再考虑正式使用。这套流程我反复验证过每一步都有明确的失败信号只要按顺序排查基本不会有玄学问题。希望你在自己的接入过程中少踩几个坑早点跑通。本文还有配套的精品资源点击获取

相关新闻

重读《重构》:小步重构与代码坏味道落地实践

重读《重构》:小步重构与代码坏味道落地实践

1. 为什么我隔了十年又读了一遍重构入行前几年,我一度觉得《重构:改善既有代码的设计》这书被神化了。提炼函数、以多态取代条件表达式,这些手法看起来平平无奇,不就是拆代码吗?直到我接手了一个跑了五年的老系统&…

2026/10/7 12:25:26 阅读更多 →
RAG知识库权限隔离全链路设计:从入库到生成的企业级实践

RAG知识库权限隔离全链路设计:从入库到生成的企业级实践

1. 权限隔离为什么是 RAG 知识库落地的第一道生死线做 RAG 知识库的人,十个里有八个把精力砸在召回率、重排模型、切片策略上,等到真正要交付给一个多部门使用的企业环境时,才发现最致命的问题根本不是"答不准",而是&qu…

2026/10/7 12:25:26 阅读更多 →
Java数组核心详解:内存模型、初始化、工具类与同构判断

Java数组核心详解:内存模型、初始化、工具类与同构判断

数组这个知识点,我在带新人和当面试官的时候,几乎每次都会聊到。它不是Java独有的概念,但Java里的数组却有很多跟C语言、Python不一样的地方——一旦没搞清楚,刷题和写业务代码都会踩坑。这篇就把JAVA数组从内存模型到经典练习题完…

2026/10/7 12:25:26 阅读更多 →

最新新闻

90DaysOfDevOps 实践笔记:使用 Docker Compose 本地部署 ELK Stack 并完成日志可视化

90DaysOfDevOps 实践笔记:使用 Docker Compose 本地部署 ELK Stack 并完成日志可视化

文档/教程 【免费下载链接】90DaysOfDevOps This repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Pri…

2026/10/7 14:13:09 阅读更多 →
【Agent Harness实战】继“紧箍咒”之后,我又给AI Agent装了一套“进化系统”:用TaoToken统一Key打通多工具链路

【Agent Harness实战】继“紧箍咒”之后,我又给AI Agent装了一套“进化系统”:用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/7 14:13:09 阅读更多 →
ADODB 无连接 RecordSet 实战:用 TaoToken 统一 Key 打通离线数据校验

ADODB 无连接 RecordSet 实战:用 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/7 14:13:09 阅读更多 →
利用AI Agent开发AI新闻分析生产级项目(三):把Codex auth.json改到TaoToken

利用AI Agent开发AI新闻分析生产级项目(三):把Codex auth.json改到TaoToken

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

2026/10/7 14:13:09 阅读更多 →
用 PyPDF2 + reportlab 批量给多份装修合同 PDF 加骑缝水印和页码(附完整代码)

用 PyPDF2 + reportlab 批量给多份装修合同 PDF 加骑缝水印和页码(附完整代码)

做装修项目最怕两件事:合同版本混乱、纸质件被调包。把多份合同 PDF 统一加上"骑缝水印 连续页码",既能防篡改,又能让归档一目了然。本文用一个纯 Python 脚本,读完即可跑。 为什么不用在线工具 装修合同含业主姓名、电…

2026/10/7 14:13:09 阅读更多 →
深挖 Harness Engineering:从 Codex 到 Agent 的工程化落地全解析

深挖 Harness Engineering:从 Codex 到 Agent 的工程化落地全解析

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

2026/10/7 14:12:09 阅读更多 →

日新闻

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

ROS2机械臂仿真与运动控制:从URDF建模到Gazebo实战全解析

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

2026/10/7 1:01:58 阅读更多 →
用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

用浏览器直接改ESP32的WiFi密码:NVS键值配置工具设计与实现

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

2026/10/7 1:02:00 阅读更多 →
芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

芯片封装缺陷检测:扫描声学显微镜(SAT)原理与实操指南

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

2026/10/7 1:02:00 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/6 7:15:40 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/6 5:29:09 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/7 9:29:10 阅读更多 →

月新闻

我发现了一个新思路:用 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/6 8:21:32 阅读更多 →
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/7 11:43:46 阅读更多 →
黑夜航拍船只数据集训练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/7 13:34:55 阅读更多 →