简介:这是一套面向Python学习者与电商自动化爱好者的京东抢购助手完整源码,包含自动登录、定时预约、补货监控、自动加购物车与自动下单等核心功能,适合作为课程设计、期末大作业或毕设的参考项目,也便于具备一定Python基础者研读调试。资源包共86个文件,以30个py源码文件为主体,辅以37个txt说明、4个md文档、3个html与3个js前端页面及少量css、图片等静态资源,压缩包约1009KB,目录按Core、GUI、Server、Scheduler、Config、Logger等模块划分,结构清晰。项目提供Windows开箱即用软件与跨平台Web操作界面,支持扫码登录、cookies保存加载、地址与商品ID查询库存价格、购物车增删与订单结算提交等操作。目前已有1075人学习下载,读者可借此理解抢购流程的模块拆分与接口调用思路,并在此基础上自行扩展功能。
1. 京东自动下单工具源码拆解:从自动登录到补货监控,一套能跑通的工程化方案
大促前夜盯着商品页面等补货,手动刷新到手指发酸,结果刚看到“有货”两个字,点进去已经排队了——这是很多人想自己写一套京东自动下单工具的起点。标题里这份源码包覆盖了自动登录、指定时间预约商品、商品补货监控、自动加购物车、自动下单五个环节,本质上是一条从“会话维持”到“库存感知”再到“订单提交”的完整链路。它适合有 Python 基础、想理解电商自动化下单底层逻辑的开发者,也适合想把这套流程改造成自己监控脚本的运维同学。需要先说明:这类工具的核心难点不在“下单”那一下,而在登录态维持和库存变化感知的实时性,源码里大部分工程量都花在这两处。下面按实际落地顺序,把每个模块拆开讲清楚。
2. 自动登录与会话维持:京东 h5st 签名和 Cookie 保活怎么做
自动登录是整个工具的地基。京东的登录态不是简单存个 Cookie 就能长期用,它涉及扫码登录、短信验证、滑块验证,以及请求签名参数 h5st 的动态生成。源码里通常把登录拆成“首次人工登录拿 Cookie”和“后续自动复用 Cookie”两段,前者需要处理验证码,后者靠定时刷新维持会话。
2.1 首次登录:扫码与滑块验证的处理边界
首次登录建议用扫码方式,因为账号密码登录触发滑块的概率更高。源码里一般会启动一个本地浏览器实例(Playwright 或 Selenium),打开京东登录页,截取二维码图片保存到本地,人工扫码后监听页面跳转,跳转成功即把 Cookie 导出成 JSON 文件。
# 用 Playwright 打开京东登录页并导出 Cookie from playwright.sync_api import sync_playwright import json, time with sync_playwright() as p: browser = p.chromium.launch(headless=False) # 首次登录必须显示浏览器 context = browser.new_context() page = context.new_page() page.goto("https://passport.jd.com/new/login.aspx") # 等待人工扫码,检测到跳转到首页即认为登录成功 page.wait_for_url("https://www.jd.com/**", timeout=120000) cookies = context.cookies() with open("jd_cookies.json", "w", encoding="utf-8") as f: json.dump(cookies, f, ensure_ascii=False, indent=2) browser.close()这段代码的关键参数是headless=False,首次登录必须可见,否则无法扫码。wait_for_url的超时设成 120 秒,给扫码留足时间。导出的 Cookie 里包含pt_key、pt_pin等字段,后续请求带上它们就能维持登录态。注意:Cookie 有有效期,通常几天到几周不等,过期后需要重新扫码。
2.2 Cookie 保活与 h5st 签名参数
Cookie 保活的做法是定时访问一个轻量接口(比如京东首页或订单列表页),检查返回状态码。如果返回 200 且页面包含用户昵称,说明登录态有效;如果跳转到登录页,说明 Cookie 失效,需要重新扫码。
h5st 是京东接口的签名参数,出现在商品详情、库存查询、下单等请求里。它由时间戳、随机数、请求路径等字段经过特定算法生成,算法会更新。源码里常见的处理方式是:不自己实现签名算法,而是用浏览器环境执行页面上的 JS 函数来生成 h5st。具体做法是在 Playwright 里打开目标页面,通过page.evaluate调用页面暴露的签名函数,拿到 h5st 后再拼接到请求里。
# 在浏览器上下文里调用页面 JS 生成 h5st def get_h5st(page, api_path, body): # 页面加载后,京东会把签名函数挂到 window 上 h5st = page.evaluate( """([path, body]) => { return window._jd_sign ? window._jd_sign(path, body) : null; }""", [api_path, body] ) return h5st这里要注意:签名函数名和挂载位置会变,不能写死。稳妥做法是每次先加载页面,再动态查找可用的签名函数。如果页面没有暴露,就需要回退到逆向 JS 的方式,但那个维护成本很高。我一般会优先用浏览器环境生成,稳定性和可维护性都更好。
2.3 登录态失效的排查顺序
登录态失效时,按这个顺序排查:先看 Cookie 文件是否为空或字段缺失;再看请求返回码,401 或跳转登录页说明失效;然后检查 h5st 是否生成成功,生成失败会导致接口拒绝;最后确认账号是否被风控,比如频繁登录会触发短信验证。源码里通常会加一个check_login()函数,每次下单前先调一次,避免跑到一半才发现登录掉了。
3. 商品补货监控与指定时间预约:轮询策略和库存接口怎么选
补货监控的核心是“在库存变化的第一时间知道”。京东商品页有“有货/无货”状态,但页面刷新有延迟,直接轮询页面效率低。更可靠的做法是调用库存查询接口,传入商品 ID 和地区编码,返回库存数量。源码里一般用轮询方式,间隔从 1 秒到 10 秒不等,具体看商品热度。
3.1 库存查询接口的参数与地区编码
库存接口通常需要skuId、area、num三个参数。skuId是商品编号,从商品链接里提取;area是地区编码,格式如1_72_2799_0,代表省_市_区_镇;num是购买数量。地区编码可以通过京东的地址接口获取,也可以从已登录账号的默认地址里读。
# 查询商品库存 import requests def check_stock(sku_id, area, cookies): url = "https://c0.3.cn/stock" params = { "skuId": sku_id, "area": area, "num": 1, "callback": "jQuery123456" } headers = {"User-Agent": "Mozilla/5.0", "Referer": f"https://item.jd.com/{sku_id}.html"} resp = requests.get(url, params=params, cookies=cookies, headers=headers, timeout=5) # 返回是 JSONP,需要去掉回调函数名再解析 text = resp.text json_str = text[text.index("(")+1 : text.rindex(")")] data = json.loads(json_str) return data.get("stock", {}).get("StockState", 0) # 33 表示有货StockState为 33 时表示有货,34 表示无货,36 表示采购中。轮询间隔建议设 2 到 5 秒,太短容易触发风控,太长会错过库存。源码里通常会把轮询和下单放在两个线程里,监控线程发现库存后立即通知下单线程。
3.2 指定时间预约商品的定时触发
“指定时间预约”指的是在某个时间点(比如 10:00:00)准时发起下单请求。实现方式有两种:一种是用schedule库在本地定时;另一种是提前把请求准备好,到点直接发送。源码里常见的是第二种,因为网络延迟不可控,提前 100 到 200 毫秒发送反而更容易抢到。
# 定时触发下单 import time, threading def schedule_order(target_time, order_func): while True: now = time.time() if now >= target_time - 0.15: # 提前 150ms 触发 order_func() break time.sleep(0.01) # 10ms 精度轮询这里的关键是time.sleep(0.01),用 10 毫秒精度轮询,避免睡过头。提前 150 毫秒是经验值,具体看网络 RTT。如果服务器时间有偏差,可以先用一个请求测出时间差,再校准本地触发时间。
3.3 补货监控的轮询频率与风控边界
轮询频率不是越高越好。实测 1 秒一次连续跑 10 分钟,大概率会触发京东的访问频率限制,表现为返回 403 或要求验证。稳妥做法是:日常监控用 5 秒间隔,大促前 10 分钟切换到 2 秒,同时给请求加随机延迟(比如 0.5 到 1.5 秒之间随机)。源码里如果没做这个随机化,跑一段时间就会被限流。
4. 自动加购物车与下单:请求构造和参数校验的完整链路
加购物车和下单是两个独立接口,但通常连着调用。加购物车接口需要skuId、num、area等参数,下单接口还需要收货地址 ID、支付方式、发票信息等。源码里一般把这两步封装成一个buy()函数,内部先加购再下单,任一步失败就重试。
4.1 加购物车接口的请求体构造
加购物车接口是 POST 请求,请求体是 JSON 格式。关键字段包括skuId、num、area、canBuyNum。其中canBuyNum是限购数量,从库存接口返回的数据里取。
# 加入购物车 def add_to_cart(sku_id, num, area, cookies): url = "https://cart.jd.com/gate.action" data = { "pid": sku_id, "pcount": num, "ptype": 1, "area": area } headers = { "User-Agent": "Mozilla/5.0", "Referer": f"https://item.jd.com/{sku_id}.html", "Content-Type": "application/x-www-form-urlencoded" } resp = requests.post(url, data=data, cookies=cookies, headers=headers, timeout=5) return "成功" in resp.text or resp.status_code == 200ptype=1表示普通商品。返回内容里如果包含“成功”或状态码 200,说明加购成功。注意:加购接口也会校验登录态和 h5st,如果返回“请先登录”,说明 Cookie 失效。
4.2 下单接口的收货地址与支付参数
下单接口需要更多参数:addressId(收货地址 ID)、payType(支付方式,如 4 表示在线支付)、invoiceInfo(发票信息)、token(防重放令牌)。addressId可以从账号的地址列表接口获取,token通常在下单页面里。
# 提交订单 def submit_order(sku_id, num, address_id, cookies): url = "https://trade.jd.com/shopping/order/submitOrder.action" data = { "overseaPurchaseCookies": "", "vendorRemarks": "[]", "submitOrderParam.skuIds": f"{sku_id},{num}", "submitOrderParam.addressId": address_id, "submitOrderParam.payType4": 1, "submitOrderParam.btSupport": 0, "submitOrderParam.trackId": "test_track" } headers = { "User-Agent": "Mozilla/5.0", "Referer": "https://trade.jd.com/shopping/order/getOrderInfo.action" } resp = requests.post(url, data=data, cookies=cookies, headers=headers, timeout=5) return resp.json()返回 JSON 里success为 true 表示下单成功,orderId是订单号。如果返回“库存不足”,说明下单瞬间库存被抢完,需要重新监控。如果返回“请勿重复提交”,说明 token 失效或请求重复。
4.3 下单失败的重试与幂等处理
下单失败分两类:可重试的(网络超时、库存瞬时不足)和不可重试的(地址无效、账号被限制)。源码里一般对可重试错误做 3 次重试,间隔 200 毫秒。但要注意幂等:同一商品重复下单会生成多个订单,所以重试前要先查一次订单列表,确认没有已生成的订单。
# 带幂等检查的重试 def safe_order(sku_id, num, address_id, cookies, max_retry=3): for i in range(max_retry): result = submit_order(sku_id, num, address_id, cookies) if result.get("success"): return result if "重复" in result.get("message", ""): return result # 已下单,不再重试 time.sleep(0.2) return {"success": False, "message": "重试耗尽"}5. 避坑与排查:自动下单工具最容易翻车的 5 个地方
这套工具跑起来不难,难的是稳定跑。下面 5 个坑是我在实际调试里反复遇到的,每个都按“现象 → 原因 → 解决”写清楚。
坑一:Cookie 突然失效,所有请求跳登录页。现象是监控还在跑,但加购和下单全部返回“请先登录”。原因是京东对 Cookie 有有效期,且异地登录或频繁请求会提前失效。解决方法是加一个定时检查,每 30 分钟调一次用户信息接口,失效就重新扫码,并把新 Cookie 写回文件。
坑二:h5st 生成失败,接口返回 403。现象是请求头里带了 h5st,但接口仍然拒绝。原因是签名函数名变了,或者页面没加载完就调用了。解决方法是先page.wait_for_load_state("networkidle")再取签名,并且每次请求前重新生成,不要缓存。
坑三:轮询太频繁被限流,返回 403 或验证码。现象是监控跑了几分钟后,库存接口开始返回 403。原因是请求频率超过风控阈值。解决方法是在轮询里加随机延迟,间隔从 2 秒到 5 秒随机,并且每 100 次请求后暂停 10 秒。
坑四:下单成功但没付款,订单超时取消。现象是submitOrder返回成功,但订单列表里显示“待付款”,一段时间后自动取消。原因是下单接口只创建订单,不完成支付。解决方法是在下单成功后,立即调用支付接口或跳转收银台,至少要在超时前完成支付。
坑五:多线程同时下单,生成重复订单。现象是监控线程发现库存后,多个下单线程同时提交,生成两笔订单。原因是没有加锁。解决方法是用threading.Lock()包住下单逻辑,确保同一商品同一时间只有一个线程在提交。
6. 进阶技巧:用青龙面板做定时任务与多账号隔离
如果想让这套工具长期跑,不建议在本地开个终端挂着。更稳的做法是放到青龙面板里,用它的定时任务和环境变量管理多账号。青龙面板支持 Python 脚本,可以把 Cookie 存成环境变量,每个账号一个变量名,脚本启动时读取。
具体做法:把源码里的 Cookie 文件读取改成从环境变量读,变量名格式如JD_COOKIE_1、JD_COOKIE_2。然后在青龙面板里创建定时任务,比如0 9 * * *表示每天 9 点执行一次补货监控。多账号之间用不同的area和addressId,避免下单时地址冲突。
# 从环境变量读取多账号 Cookie import os def load_cookies(): cookies_list = [] for key, value in os.environ.items(): if key.startswith("JD_COOKIE_"): cookies_list.append(value) return cookies_list青龙面板的好处是任务隔离和日志集中,哪个账号失效了一眼能看到。但要注意:面板本身不解决 h5st 和风控问题,它只是调度器。签名和登录态还是得靠浏览器环境或逆向方案。
最后说个我自己的习惯:每次改完脚本,先拿一个不重要的商品跑一遍全流程,确认登录、监控、加购、下单都通了,再切到目标商品。这样翻车成本最低。希望帮到你。
本文还有配套的精品资源,点击获取