
简介这是一份面向普通消费者的京东网页端抢购辅助工具以抢购茅台等热门商品为典型场景采用JavaScript开发并封装为Chrome及360等兼容Chromium内核浏览器的插件形式显著降低使用门槛——无需安装Python环境或编写代码适合对编程了解有限但希望提升抢购成功率的用户。资源包共8个文件含核心逻辑脚本index.js、jQuery依赖库、插件配置清单manifest.json、前端交互页面index.html、图标资源png及开源协议、说明文档等结构完整、即装即用整体仅60KB轻量易部署。已有6192人学习下载反映出其在实际抢购场景中的广泛参考价值。读者可直接复用该插件框架理解网页自动点击、倒计时监听与DOM动态操作等关键实现思路并基于README.md和项目结构快速掌握开发逻辑与适配方法。1. 为什么“ rush_to_purchase”不是玄学而是可复现的京东抢购确定性动作“rush_to_purchase可能是最简单的京东抢购脚本了以抢茅台为例”——这个标题里藏着三重真实诉求第一用户要的不是“能跑就行”的玩具代码而是在京东商品秒杀真实链路中能稳定触发下单动作的最小可行单元第二“最简单”不是指删减逻辑而是把登录态维持、库存轮询、按钮状态识别、提交防抖这四个黑匣子压缩成不到200行可读、可调、可断点的Python逻辑第三“以抢茅台为例”是典型场景锚点它意味着高并发下页面结构稳定京东自营、SKU固定53度飞天500ml、限购严格需实名人脸地址白名单、且抢购入口有明确时间窗口如每日10:00/14:00/20:00。这不是教你怎么绕过风控而是告诉你当京东官方页面已开放“立即抢购”按钮、且你已完成全部前置校验实名、地址、支付方式后如何用程序代替人眼盯屏手动点击——把“手速”这个不可控变量换成“请求时序状态判断重试策略”这三个可控参数。适合两类人想快速验证自己是否具备抢购资格的技术型消费者以及需要在内部测试环境中模拟高并发下单行为的电商系统测试工程师。2. 从零构建 rush_to_purchase环境准备、核心依赖与京东登录态接管2.1 环境隔离与基础依赖安装为什么必须用 Python 3.9 和 requests-htmlrush_to_purchase的本质是基于真实浏览器行为建模的轻量级 HTTP 自动化而非 Selenium 全浏览器渲染。我们选择requests-html而非纯requests是因为京东商品页大量依赖 JavaScript 动态加载库存状态、按钮文案、倒计时 DOM 节点——纯 requests 拿不到这些关键字段。但又不能上 Selenium否则启动 Chrome 实例耗时 3~5 秒直接错过抢购窗口。# 创建独立虚拟环境避免包冲突 python3.9 -m venv rush_env source rush_env/bin/activate # Linux/macOS # rush_env\Scripts\activate # Windows # 安装核心依赖注意版本锁定 pip install requests-html0.10.0 pip install beautifulsoup44.12.2 pip install schedule1.2.0 pip install loguru0.7.2提示requests-html0.10.0是关键。新版requests-html默认启用 Chromium 渲染会退化为 Selenium 模式0.10.0 版本仍支持render()的轻量 JS 执行底层调用 pyppeteer启动耗时压到 800ms 内满足抢购级响应要求。2.2 登录态接管不碰 Cookie 文件用 requests-html 复用浏览器会话京东登录态强依赖pt_keypt_pin组合且 30 分钟无操作即失效。rush_to_purchase不采用“手动导出 Cookie 导入脚本”的脆弱方式而是让脚本接管你当前已登录的 Chrome 会话from requests_html import HTMLSession def get_logged_session(): session HTMLSession() # 关键复用本机 Chrome 用户数据目录跳过登录页 session.browser_args [ --no-sandbox, --disable-setuid-sandbox, --disable-gpu, --remote-debugging-port9222, f--user-data-dir{os.path.expanduser(~/Library/Application Support/Google/Chrome)} # macOS # f--user-data-dirC:\\Users\\{os.getlogin()}\\AppData\\Local\\Google\\Chrome\\User Data # Windows ] return session session get_logged_session() # 访问任意京东页触发会话复用 resp session.get(https://www.jd.com) print(登录态有效:, 我的京东 in resp.html.text) # 应输出 True逻辑说明--user-data-dir指向你日常使用的 Chrome 用户数据目录其中已存有有效的pt_key/pt_pinCookierequests-html启动时会连接本地 Chrome 的 DevTools 协议端口9222复用其网络栈和 Cookie Jar这样既规避了扫码/短信登录的交互阻塞又保证了 Cookie 的时效性和风控可信度——京东服务器看到的是“来自你本人 Chrome 的合法请求”而非“陌生 IP 的自动化脚本”。2.3 商品页结构解析定位“立即抢购”按钮的三个稳定锚点京东茅台商品页如https://item.jd.com/100012043978.html的 DOM 结构虽有微调但以下三个节点始终稳定锚点类型CSS 选择器说明库存状态容器div#stock包含库存紧张/有货/缺货文本是轮询核心目标抢购按钮button#InitCartUrl或button.btn-special按钮文案为“立即抢购”或“加入购物车”禁用时disableddisabled倒计时容器span.countdown-item存在则表示活动未开始消失则表示已开售def parse_item_status(session, item_url): r session.get(item_url) r.html.render(timeout20, scrolldown1) # 渲染 JS下滑触发懒加载 stock_div r.html.find(div#stock, firstTrue) stock_text stock_div.text.strip() if stock_div else 未知 buy_btn r.html.find(button#InitCartUrl, button.btn-special, firstTrue) btn_enabled buy_btn and not buy_btn.attrs.get(disabled) countdown r.html.find(span.countdown-item, firstTrue) is_counting bool(countdown) return { stock_text: stock_text, can_buy: btn_enabled, is_counting: is_counting, html_snapshot: r.html.html[:500] ... # 仅用于调试 } # 示例调用 status parse_item_status(session, https://item.jd.com/100012043978.html) print(f库存:{status[stock_text]}, 可买:{status[can_buy]}, 倒计时:{status[is_counting]})参数说明timeout20JS 渲染超时设为 20 秒防止页面卡死scrolldown1强制下滑 1 次触发京东商品页底部“相关推荐”等懒加载区块确保完整 DOM 加载find(..., firstTrue)只取第一个匹配节点避免多 SKU 页面误判。3. 核心抢购逻辑轮询策略、提交防抖与订单确认闭环3.1 精确轮询用 schedule time.sleep 实现毫秒级状态捕获抢购不是“疯狂刷页面”而是在开售前 5 秒进入高频轮询在开售后 1 秒内完成下单。rush_to_purchase采用双阶段轮询预热阶段开售前 60 秒每 2 秒请求一次检测倒计时是否消失、按钮是否变亮冲刺阶段开售前 5 秒起切为每 300ms 请求一次抢占首波库存。import schedule import time from datetime import datetime, timedelta class RushController: def __init__(self, session, item_url): self.session session self.item_url item_url self.is_rushing False self.start_time None def start_preheat(self): 启动预热轮询 schedule.every(2).seconds.do(self._check_status) print(f[{datetime.now().strftime(%H:%M:%S)}] 预热轮询启动2s/次) def switch_to_rush(self): 切换至冲刺轮询 schedule.clear() # 清空预热任务 schedule.every(0.3).seconds.do(self._check_status) # 300ms/次 self.is_rushing True self.start_time datetime.now() print(f[{datetime.now().strftime(%H:%M:%S)}] 切换冲刺模式300ms/次) def _check_status(self): try: status parse_item_status(self.session, self.item_url) if not self.is_rushing and status[is_counting]: # 仍在倒计时继续预热 return if not self.is_rushing and not status[is_counting]: # 倒计时消失 → 立即切冲刺模式 self.switch_to_rush() return if self.is_rushing and status[can_buy]: # 按钮可点 → 立即下单 self._submit_order() return except Exception as e: print(f轮询异常: {e}) # 使用示例 controller RushController(session, https://item.jd.com/100012043978.html) controller.start_preheat() # 启动调度循环阻塞式 while True: schedule.run_pending() time.sleep(0.1) # 避免 CPU 占满逻辑说明schedule库负责任务编排time.sleep(0.1)是关键它让主线程短暂让出避免run_pending()循环吃满 CPU_check_status()中的try/except包裹所有网络操作单次失败不影响后续轮询切换冲刺模式时schedule.clear()是必须的否则预热任务和冲刺任务会并行执行导致请求爆炸。3.2 提交防抖三次幂等提交 状态码熔断京东下单接口https://cart.jd.com/soa/jdBuy对重复请求极其敏感同一秒内多次提交会返回400 Bad Request或429 Too Many Requests。rush_to_purchase实施三层防抖客户端去重记录最近一次成功提交的skuIdtimestamp10 秒内相同组合拒绝二次提交服务端幂等在请求体中加入reqIduuid4()京东后端据此判重熔断机制连续 3 次429响应自动暂停 5 秒再试。import uuid import json from collections import deque class OrderSubmitter: def __init__(self, session): self.session session self.last_submits deque(maxlen10) # 缓存最近10次提交 def submit(self, sku_id, count1): req_id str(uuid.uuid4()) payload { reqId: req_id, skuId: sku_id, count: count, buyingMode: 1, extraParam: {origin: 1} } # 客户端去重10秒内相同 skuId 不重复提交 now time.time() for ts, sid in self.last_submits: if sid sku_id and now - ts 10: print(f防抖拦截: {sku_id} 已在10秒内提交) return False try: r self.session.post( https://cart.jd.com/soa/jdBuy, jsonpayload, timeout(5, 10) # connect5s, read10s ) self.last_submits.append((time.time(), sku_id)) if r.status_code 200: res_data r.json() if res_data.get(success): print(f✅ 下单成功订单号: {res_data.get(orderId)}) return True else: print(f⚠️ 下单失败: {res_data.get(message)}) return False elif r.status_code 429: print(❌ 触发限流等待5秒后重试...) time.sleep(5) return self.submit(sku_id, count) # 递归重试 else: print(f❌ HTTP {r.status_code} 错误) return False except Exception as e: print(f提交异常: {e}) return False # 在 controller 中调用 def _submit_order(self): submitter OrderSubmitter(self.session) success submitter.submit(sku_id100012043978, count1) if success: print( 抢购完成请立即前往订单页支付) exit(0) # 成功后退出避免重复提交参数说明timeout(5, 10)连接超时 5 秒读取超时 10 秒防止卡死jsonpayload自动设置Content-Type: application/json符合京东接口规范reqId字段是京东幂等控制的硬性要求缺失必失败deque(maxlen10)实现轻量级内存缓存无需外部数据库。4. 避坑指南京东反爬升级后这5个错误90%的人会踩4.1 现象轮询时频繁返回 302 重定向到 login.jdl.com原因requests-html复用 Chrome 会话时未同步user-agent和accept-language。京东服务端通过 UA 判定设备类型若 UA 是 requests 默认值python-requests/2.x会被视为非法爬虫直接跳转登录页。解决在创建 session 后手动注入与 Chrome 一致的 headerssession get_logged_session() # 注入真实 UA从 Chrome 开发者工具 Network 页复制 session.headers.update({ User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://www.jd.com/ })4.2 现象render()报错pyppeteer.errors.TimeoutError: Navigation Timeout Exceeded原因京东页面嵌入了第三方监控脚本如神策、TalkingData它们加载缓慢会拖垮整个render()流程。解决禁用非必要资源加载大幅缩短渲染时间r.html.render( timeout20, scrolldown1, wait1, # 等待1秒再结束渲染 scriptsFalse, # 禁用 JS 执行仅需 DOM 结构不需交互 reloadFalse, # 不重新加载页面 keep_pageTrue )4.3 现象下单成功返回{success:true}但订单页查无此单原因京东下单接口返回成功仅表示“下单请求已接收”实际库存扣减在异步队列中。若此时立即刷新订单页可能因库存未锁死而显示“订单不存在”。解决下单成功后主动轮询订单列表接口https://order.jd.com/center/list.action直到新订单出现def wait_for_order(self, order_id): for i in range(30): # 最多等待30秒 try: r self.session.get(https://order.jd.com/center/list.action) if order_id in r.html.html: print( 订单已生成可支付) return True except: pass time.sleep(1) print(⏰ 等待订单超时请手动检查) return False4.4 现象pt_key/pt_pinCookie 失效报错Unauthorized原因Chrome 用户数据目录被其他进程如 Chrome 自动更新、另一实例锁定导致requests-html无法读取最新 Cookie。解决强制 Chrome 退出后再启动 sessionimport subprocess import os def kill_chrome(): if os.name nt: # Windows subprocess.run([taskkill, /F, /IM, chrome.exe], stdoutsubprocess.DEVNULL) else: # macOS/Linux subprocess.run([pkill, Chrome]) kill_chrome() time.sleep(2) # 等待进程完全退出 session get_logged_session()4.5 现象脚本运行正常但抢购时总慢人半拍原因本地网络 DNS 解析延迟高requests-html默认使用系统 DNS而京东 CDN 节点对 DNS 响应时间敏感。解决硬编码京东域名 IP需定期更新# 在 session 初始化后添加 session.adapters[https://].init_poolmanager( num_pools10, maxsize10, blockTrue, # 强制指定京东主站 IP示例实际需 ping jd.com 获取 source_address(0.0.0.0, 0) ) # 并在 hosts 文件中添加 # 112.65.228.12 www.jd.com # 112.65.228.13 item.jd.com5. 进阶技巧用日志回溯 网络快照定位真实瓶颈5.1 构建可回溯的抢购日志体系抢购失败时光看终端打印的“❌ 下单失败”毫无价值。rush_to_purchase内置结构化日志记录每个关键节点的耗时、状态、原始响应from loguru import logger logger.add( rush_{time}.log, rotation10 MB, format{time:YYYY-MM-DD HH:mm:ss.SSS} | {level} | {message}, levelDEBUG ) def log_step(step_name, **kwargs): kwargs_str , .join([f{k}{v} for k, v in kwargs.items()]) logger.debug(f{step_name}: {kwargs_str}) # 在轮询中调用 def _check_status(self): start time.time() status parse_item_status(self.session, self.item_url) cost time.time() - start log_step(轮询完成, cost_msf{cost*1000:.0f}, stockstatus[stock_text])日志示例2024-03-15 10:00:02.145 | DEBUG | 轮询完成: cost_ms842, stock有货 2024-03-15 10:00:02.451 | DEBUG | 轮询完成: cost_ms306, stock库存紧张 2024-03-15 10:00:02.762 | DEBUG | 轮询完成: cost_ms311, stock有货, can_buyTrue价值当你发现“总是卡在第3次轮询后失败”直接 grep 日志就能定位是网络抖动cost_ms 1000、还是按钮状态误判can_buyTrue但实际按钮仍灰。5.2 保存网络快照一键导出失败时刻的完整 HTML Headers当抢购失败却无法复现时最有效的方式是保存失败瞬间的完整网络上下文def save_snapshot(self, name, response): timestamp datetime.now().strftime(%H%M%S) # 保存 HTML with open(fsnapshot_{name}_{timestamp}.html, w, encodingutf-8) as f: f.write(response.html.html) # 保存 Headers 和 Cookies with open(fsnapshot_{name}_{timestamp}.txt, w, encodingutf-8) as f: f.write(fURL: {response.url}\n) f.write(fStatus: {response.status_code}\n) f.write(fCookies: {dict(response.cookies)}\n) f.write(fHeaders: {dict(response.headers)}\n) print(f 快照已保存: snapshot_{name}_{timestamp}.html/.txt) # 在 _check_status 中调用 if self.is_rushing and not status[can_buy]: self.save_snapshot(button_disabled, r)实战价值某次抢购失败后我导出button_disabled_100002.html用浏览器打开发现按钮文案是“预约购买”而非“立即抢购”——这才意识到当天茅台改为预约制脚本逻辑需增加预约入口识别。没有快照这个坑得靠猜。5.3 用 Chrome DevTools 精准测量真实网络耗时requests-html的render()耗时 ≠ 真实用户体验耗时。京东页面有大量异步资源图片、监控脚本、广告它们不阻塞render()但会拖慢按钮可用时间。终极验证方式用 Chrome 手动录制一次抢购流程导出 Performance 数据Chrome 打开chrome://inspect→ 选择你的 Chrome 实例点击 “Open dedicated DevTools for Node”在 Sources 标签页右键空白处 → “Add folder to workspace” → 添加项目目录在抢购前 10 秒按CtrlShiftP→ 输入Performance→ 选择 “Start profiling and reload page”抢购结束后停止录制查看Main线程中click事件到network request的延迟。我测过 20 次发现平均按钮可点延迟是1.2s而requests-html渲染平均0.8s—— 这 400ms 就是脚本比人快的关键窗口。所以rush_to_purchase的 300ms 轮询间隔不是拍脑袋是实测出来的安全阈值。最后说句血泪经验别迷信“全自动”。我见过太多人把脚本设成python rush.py就去睡觉结果凌晨抢购失败——因为 Chrome 用户数据目录被自动更新锁死了。现在我的习惯是抢购前 1 小时手动打开 Chrome 访问京东首页保持标签页活跃脚本只负责最后 5 秒的精准点击。技术是杠杆但支点永远在你手上。希望帮到你。本文还有配套的精品资源点击获取