简介:这是一份基于 Node.js 实现的京东商品到货监控与自动下单轻量级爬虫工具,面向具备 JavaScript 基础的前端或全栈开发者,适用于学习电商接口逆向、扫码登录流程、库存轮询与自动化下单逻辑等实战场景。资源包共11个文件,含5个核心 JS 脚本(如 index.js 入口、utils.js 工具函数、log.js 日志模块)、README.md 说明文档、LICENSE 协议文件、.gitignore 与 package.json 等工程配置,以及展示扫码登录与下单流程的 jd-happy.gif 动图,整体压缩包仅1.7MB,结构简洁、依赖明确,便于快速阅读与本地调试。已有819人学习下载,读者可完整获取从浏览器初始化、页面参数提取、库存检测到模拟下单的全流程代码实现,尤其适合理解 Node 环境下 Puppeteer 驱动浏览器的典型用法、京东登录态缓存机制及抢购类脚本的设计边界与局限性。
1. 为什么京东商品“秒没”后,你总在刷新页面?这个 Node 爬虫+下单服务不是玩具,而是可落地的库存感知闭环
你有没有过这种经历:盯了三天的某款显卡,页面上明明写着“有货”,一点“立即购买”却跳转到缺货页;或者凌晨抢购时,倒计时归零的瞬间,购物车里商品突然变灰、提示“库存不足”——不是网络卡,是页面状态和真实库存之间存在毫秒级的感知断层。jd-happy这个项目标题里的[DEPRECATED]并不意味着技术失效,而是它所依赖的京东前端交互逻辑已迭代多次,但其底层设计思想——用轻量 Node.js 实现“状态监听 → 变化捕获 → 行动触发”闭环——至今仍是电商自动化监控中最务实的路径之一。它不依赖逆向 App 协议、不硬啃加密参数、不模拟完整浏览器环境,而是聚焦在“什么时候该点‘提交订单’”这个最痛的决策点上。适合正在做比价系统、自营仓配预警、小批量囤货策略验证的开发者,也适合想把“爬虫”从“数据采集”升级为“行为触发器”的进阶学习者。它不是黑盒脚本,而是一套可调试、可插拔、可嵌入你现有 Node 工作流的状态驱动模型。
2. 从页面 DOM 到下单动作:Node 环境下如何稳定抓取京东商品实时状态
京东商品页的库存状态并非全靠后端 API 返回,大量信息藏在 HTML 的>npm install cheerio got
// snapshot.js const got = require('got'); const cheerio = require('cheerio'); async function getJdProductSnapshot(url) { const headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', 'Referer': 'https://www.jd.com/', // 必须携带 Cookie,否则返回空库存页 'Cookie': 'shshshfpa=xxx; shshshfpb=yyy; __jda=zzz; ...' // 从浏览器复制,有效期约7天 }; try { const response = await got(url, { headers, timeout: { request: 10000 } }); const $ = cheerio.load(response.body); // 提取关键状态字段 const snapshot = { url, timestamp: Date.now(), stockState: null, buyButtonDisabled: null, stockText: null, skuId: url.match(/product\/(\d+)\.html/)?.[1] || 'unknown' }; // 1. 尝试从 hidden input 获取 stockState const stockInput = $('input[id="InitCartUrl"], input[name="stockState"], input[data-stock-state]'); if (stockInput.length) { const value = stockInput.attr('value') || ''; const match = value.match(/stockState=(\d+)/); if (match) snapshot.stockState = parseInt(match[1], 10); } // 2. 检查立即购买按钮 const buyBtn = $('.btn-buy, .trigger-btn-buy'); if (buyBtn.length) { snapshot.buyButtonDisabled = buyBtn.attr('disabled') !== undefined; snapshot.buyButtonText = buyBtn.text().trim(); } // 3. 辅助库存文本 const stockDiv = $('.item-stock, .stock-prompt'); if (stockDiv.length) { snapshot.stockText = stockDiv.text().trim().replace(/\s+/g, ' '); } return snapshot; } catch (err) { console.error(`[SNAPSHOT] Failed to fetch ${url}:`, err.message); return null; } } module.exports = getJdProductSnapshot;参数说明:
timeout.request: 10000:设为 10 秒,京东首屏 TTFB 通常在 800ms–3s,超时过短易误判,过长拖慢轮询节奏;Cookie字段必须手动更新:打开京东商品页 → F12 → Application → Cookies → 复制全部name=value对,拼成一行字符串(注意 URL 编码字符需保留);skuId提取正则/product\/(\d+)\.html/是京东 PC 端标准格式,若监控的是item.jd.com/123456.html需调整为/item\.jd\.com\/(\d+)\.html/。
此函数返回的是一个结构化快照对象,而非原始 HTML。后续所有逻辑(变化检测、下单触发)都基于该对象字段运算,这是jd-happy可维护性的根基。
3. 状态变化 ≠ 可下单:如何用哈希指纹精准识别“真库存释放”
很多开发者卡在“明明看到按钮变亮了,但点击还是失败”。根本原因在于:京东的“页面可点击”只是前端乐观渲染,真实下单资格需通过submitOrder接口的二次校验。jd-happy的设计聪明之处,在于它不把“DOM 变化”直接等同于“可以下单”,而是构建了一个多层状态机:idle → suspect → confirm → action。其中suspect(疑似可购)阶段,就是用哈希指纹识别“真变化”的关键。
3.1 为什么不能只比对stockState数值?
实测发现,京东部分 SKU 的stockState在无货时返回1,有货时返回3,但中间会短暂出现2(“补货中”)、4(“仅限PLUS会员”)等状态。若只监控stockState === 3,可能错过2→3的窗口;若监控stockState > 1,又会把4(不可购)误判为可购。更糟的是,stockState字段本身可能被 CDN 缓存,导致连续两次请求返回相同值,但实际库存已变。
3.2 构建抗干扰的 DOM 状态指纹
解决方案:对影响下单决策的所有 DOM 片段提取内容哈希,而非单个字段。我们选取三个不可伪造、不易缓存、且与下单强相关的片段: