简介:一套基于Python开发的京东平台茅台酒抢购自动化脚本,主要面向对秒杀抢购、电商自动化控制感兴趣的Python开发者,用于解决手动抢购操作繁琐、响应慢、易错过时机等痛点。脚本完整覆盖网络请求、JSON接口解析、定时触发、网页内容解析、模拟点击、多线程/异步并发、异常处理、配置信息管理、日志记录等关键模块,并从登录到提交订单演示了一条龙自动化链路,代码结构清晰,便于二次开发。资源为zip压缩包,共1940个文件,大小约11.26MB,以860个py源码与859个pyc编译类文件为主,另含exe/pyd可执行与扩展文件、h头文件、txt/xml说明配置及License等,适合直接运行或深入研读。目前已有12214人学习下载,可作为Python网络编程、定时任务及GUI自动化的实战案例。需特别提醒:此类脚本可能违反电商平台用户协议,应仅在合规前提下作技术学习使用。
1. 京东抢茅台Python脚本的本质:一场毫秒级竞速里的登录态战争
先说一个反直觉的结论:京东抢茅台Python脚本里,真正决定成败的往往不是抢购那一刻的代码有多快,而是你的登录态在那一瞬间是否还活着、是否被风控放行。很多人把精力全花在构造请求、压测QPS上,结果开售时发现接口返回“请重新登录”或者商品ID早已失效,那一刻你会明白,Cookie新鲜度比并发技巧值钱得多。
这篇内容围绕“京东抢茅台Python脚本”展开,覆盖从Python安装环境、抓包取Cookie、下单请求构造、本地时间校准到多线程并发与规避风控的完整链路。无论你是第一次听说抢购脚本,还是已经跑通过但经常抢不到,里面都会有可复现的命令和可调参数。前提是:先接受一个现实——任何脚本都无法保证必中,这个标题要解决的是把“能不能抢”变成“有没有资格抢、有没有准时抢、有没有被误伤”。
2. 环境准备:用Python把登录态从浏览器搬到requests会话
抢购脚本的本质是一个带上你登录Cookie的HTTP客户端,在开售瞬间向京东的下单接口发起请求。这一章先把最容易卡住新手的“Python装不上、Cookie取不到、登录态过期”三个问题一次性解决。
2.1 先装Python:Windows/macOS/Linux三平台要点
常见做法是装Python 3.8到3.11之间的版本,太新的3.12有时会遇到个别依赖库还没发预编译包的情况,太老则没必要。Windows直接去python.org下载安装包,安装第一步务必勾选“Add Python to PATH”,否则后续在终端执行python会提示无法识别。macOS推荐用Homebrew安装,Linux则用系统包管理器,比如Ubuntu执行sudo apt install python3 python3-pip。
装好后打开一个新的终端窗口验证:
python --version pip --version注意“新开窗口”这四个字。Windows上很多人刚装完Python就在旧窗口里敲python,报错“无法将‘python’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”,这是PATH没有刷新,不是安装失败。同理,npm、git这类命令如果之前也报过类似错误,基本都是同一个原因。
如果你更习惯Visual Studio Code,装好Python解释器后在VSCode里安装官方Python插件,再在命令面板里执行“Python: Select Interpreter”选中刚装好的版本,vscode python环境配置就算完成。接下来创建项目目录,安装本脚本唯一必要的第三方库requests:
mkdir jd_maotai cd jd_maotai pip install requestsrequests负责维持会话、携带Cookie和发起HTTP请求。整个脚本不依赖Selenium或Playwright这类浏览器自动化框架,因为模拟浏览器去点击页面既慢又容易被识别,直接调接口才是最快路径。
2.2 抓包取Cookie:比无头浏览器更省时间的登录态获取法
抢京东需要用已登录的账号身份去请求,Cookie就是你的身份凭证。获取方式不是去Cookie文件里翻,而是从浏览器开发者工具里直接复制。
打开Chrome或Edge,登录京东网页版,按F12进入开发者工具,切到Network(网络)面板,勾选Preserve log(保留日志),然后刷新页面。在请求列表里随便点一个请求,找到Request Headers区域,把Cookie这一整段值复制出来,保存到一个文本文件备用。这段Cookie通常有几百个字符,包含pt_key、pt_pin等京东关键登录字段,也是后续脚本的核心入参。
这一步本质上就是一次浏览器抓包,和写python爬虫时获取会话Cookie的思路完全一致。不要用无头浏览器去自动登录,因为登录往往要过滑块验证,自动化登录很容易被风控标记,手动登录一次、Cookie有效期通常能维持数天,性价比高得多。
2.3 用一段15行的Python验证登录态是否有效
拿到Cookie后不要直接写抢购逻辑,先写一段最小验证脚本,确认这个Cookie真的登录了。京东有一个返回用户信息的轻量接口,用它来探测登录态:
import requests cookie_str = "这里粘贴你的Cookie" headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Cookie": cookie_str, "Referer": "https://www.jd.com/" } url = "https://passport.jd.com/user/petName/getUserInfoForMini498.action" resp = requests.get(url, headers=headers, timeout=5) print(resp.status_code) print(resp.text)这段代码的逻辑很简单:构造一个带Cookie的请求头,请求京东的昵称查询接口,返回200且包含昵称说明登录态有效。如果不带Cookie或者Cookie过期,返回内容里会提示未登录。timeout=5防止网络异常时脚本无响应地挂着。
Cookie复制后要检查的一件事是别带换行符,整段要是一行。另外每次运行脚本前先用这个接口探一次,请求失败就直接退出,不要等到开售那一刻才发现 “提前” 词:这个探测是整条链路的地基,宁可多花一次请求也要确保登录态是活的。
2.4 三个必改参数:Cookie、skuId与User-Agent
验证登录态有效后,把所有可能变化的值集中到配置区,不要散落在请求代码里。最常见的配置项就三个:
| 参数 | 作用 | 获取方式 |
|---|---|---|
| Cookie | 登录身份凭证 | 从浏览器开发者工具复制 |
| skuId | 商品编号,决定买的是哪款茅台 | 商品详情页URL中最后一段数字 |
| User-Agent | 标识客户端类型 | 开发者工具里直接复制浏览器的UA |
User-Agent没改对不会马上报错,但缺失或太假会拉高被风控识别的概率。这里常用写法是伪造一个和真实浏览器一致的UA,顺便把Referer也带上,Referer可以填商品详情页地址。Cookie、skuId、UA这三个参数,每次运行前都要人工确认一遍,尤其是Cookie过期后脚本会静默失败而不是报错,这是排查时最容易忽略的点。
3. 抢购请求够快才行:京东抢茅台Python脚本的核心请求构造与时间校准
先把结论放前面:京东抢茅台的正确请求路径不是开售瞬间才去加购物车,而是提前把商品加购好、提前进入结算页,开售那一刻只提交订单。这个思路决定了脚本的性能上限。
3.1 先理解京东的下单接口:为什么不能只打秒杀链接
京东的下单链路大致是:商品详情→加购物车→订单结算页→提交订单。很多新手脚本把“抢”理解为疯狂请求秒杀URL,这是误区。茅台这类商品在详情页模型下需要经过加购校验,如果直接从提交订单开始,服务端会返回“请先加购”之类的错误。
正确的做法是分两步:第一步提前执行加购请求,让购物车里始终有这个商品;第二步在开售瞬间请求提交订单接口。所有请求都走同一个requests.Session对象,Session会自动维持Cookie和底层TCP连接,避免每次请求都重新建立连接,HTTP层面的连接复用能省下几十毫秒。
3.2 本地时间为什么要先校准:NTP协议与time模块
脚本必须精确知道什么时候是“开售瞬间”,但本地电脑时间往往和京东服务器时间有几秒偏差。你本地10:00:00.000发起请求,京东那边可能已经是10:00:03,这种偏差在茅台抢购里就是致命的。
解决思路是让脚本开跑前先从NTP服务器同步一次时间。直接用Python标准库不好做NTP,常见做法是安装ntplib这个轻量库:
pip install ntplib然后写一个时间校准函数,从公共NTP服务器获取标准时间:
import ntplib from datetime import datetime def get_ntp_time(): client = ntplib.NTPClient() response = client.request("ntp.aliyun.com", timeout=3) return datetime.fromtimestamp(response.tx_time) print("本地时间:", datetime.now()) print("NTP时间:", get_ntp_time())NTP返回的tx_time是服务器发送响应的时间戳,把它转成本地时区的datetime后和本地时间对比,得到时间偏移量。抢购时在目标时刻上叠加这个偏移量,就能和服务器同步。注意ntplib请求要设置timeout,防止NTP服务不可达时阻塞太久,一些公共NTP服务器偶尔会超时,按经验优先使用阿里的ntp.aliyun.com。
3.3 核心请求:先加购物车还是直接提交订单?
这个问题的答案是:都要,但时机不同。加购提前做,开售只做提交订单。先提前把商品加入购物车:
session = requests.Session() session.headers.update(headers) # 提前加购,调用移动端加购接口 cart_url = "https://api.m.jd.com/client.action" cart_params = { "functionId": "genShoppingCart", "body": '{"skuId":"100012043978","num":1}', "appid": "jd_shop_member" } resp = session.get(cart_url, params=cart_params, timeout=3)这里body里的skuId要替换成目标茅台商品的真实ID,num固定为1,因为绝大多数平台规则限购一瓶。添加购物车后可以调用结算页接口拿到订单信息,把支付相关字段缓存下来,不过这个过程正常情况下返回内容很长,日常调试时只检查status code和返回是否包含特定业务码即可。
到了开售时刻,提交订单的核心代码长这样:
submit_url = "https://api.m.jd.com/client.action" submit_params = { "functionId": "submitOrder", "body": '{"skuId":"100012043978","num":1,"payType":4}', "appid": "jd_shop_member" } resp = session.get(submit_url, params=submit_params, timeout=3) result = resp.json() if result.get("success"): print("下单成功,订单号:", result.get("orderId")) else: print("下单失败,错误码:", result.get("code"), result.get("message"))payType表示支付方式,4是京东支付。下单返回的JSON结构里success为true且带orderId才算成功,其余都是业务失败。不要依赖status_code判断,接口通常返回200但data里带错误,必须解析业务字段。
3.4 高频请求和Requests Session的坑:Keep-Alive与Cookie失效
requests.Session默认启用连接池(urllib3的HTTPConnectionPool),默认连接数是10,对单账号抢购完全够用。但有一个坑:Session对象如果在抢购前闲置时间过长,底层连接可能被京东服务端断开,第一次提交订单请求时会触发重连,白白损失一次RTT。避免方法很简单,在开售前30秒先向京东任一接口发送一次轻量请求,把连接“热起来”。
另一个坑是重试机制。requests不会自动重试,而抢购请求恰恰不能盲目重试。如果提交订单接口返回“排队中”或“系统繁忙”,应该稍等再试,但只能用很快的间隔试有限几次。每一次失败后重新请求前,建议先检查登录态是否失效——如果Cookie被踢下线,重试再多次都是空转。
4. 定时启动与误差补偿:让脚本踩准系统开售时刻
抢购脚本的启动策略直接决定成败。上一章的请求构造保证的是“请求有效”,这一章解决的是“请求准时”。很多人的脚本败在启动过早或过晚,而不是请求本身有问题。
4.1 定时器的粒度:sleep与while轮询的误差累积
新手常见写法是计算到开售时刻的秒数,然后time.sleep(秒数),睡醒后发起请求。这个方案有致命缺陷:sleep结束后正好错过目标时间点。因为线程被唤醒需要时间,加上Python解释器的GIL调度,误差通常有几十到几百毫秒,在茅台抢购场景里几乎等于失败。
正确的做法是“提前启动,实时轮询”。设定一个提前量,比如提前0.5秒进入循环,循环里不断读取当前时间,直到当前时间大于等于目标时间后立即发起请求:
import time from datetime import datetime target_time = datetime(2025, 1, 1, 10, 0, 0, 0) # 改成你的开售时间 offset = get_ntp_time() - datetime.now() # NTP校准得到的偏移量 while True: now = datetime.now() + offset if now >= target_time: submit_order() # 执行抢购请求 break time.sleep(0.001) # 1ms轮询每秒循环1000次对CPU有压力,但只持续几百毫秒,完全可以接受。很多人习惯把这类脚本挂到定时任务面板里做例行刷新,但像青龙这类基于cron的面板,最小粒度通常是一分钟,刷新间隔太粗,根本赶不上毫秒级的抢购窗口。所以抢购脚本不应该依赖任何外部定时器,自己循环等待是最可靠的做法。
4.2 本地时间与服务器时间的偏差补偿
NTP校准得到的时间偏移量在运行期间会缓慢漂移,不过对一场几十秒的抢购来说,漂移量微乎其微。真正要注意的是时区问题:你写的target_time是本地时间还是服务器时间。京东服务器用的是北京时间(UTC+8),如果你的电脑在UTC+8时区,NTP校准后得到的datetime直接和target_time比较即可;如果电脑不在东八区,需要先做一次时间转换,否则脚本可能差了一整个时区的秒数。
判断基准也很简单:在验证登录态那一步,同时打印NTP服务器给出的时间,自己肉眼确认它和本地时间在同一个时区概念下。这条校对逻辑建议做成独立函数,抢购前单独打印一次校准结果,别等到全流程跑完才发现时间对不上。
4.3 单线程与多账号并发:GIL和线程数
单账号抢购用单线程就够了,因为同一个账号在开售瞬间发几次请求意义不大,而多个请求之间还要共享同一个Session,多线程反而容易引发Cookie状态问题。多账号场景下,常见做法是一个账号分配一个线程,每个线程持有各自的Session和Cookie,互不干扰:
import threading accounts = [ {"cookie": "账号1的Cookie", "skuId": "100012043978"}, {"cookie": "账号2的Cookie", "skuId": "100012043978"}, ] def worker(account): session = build_session(account["cookie"]) wait_and_submit(session, account["skuId"], target_time) for account in accounts: t = threading.Thread(target=worker, args=(account,)) t.start()每个线程各跑各的时间校准和循环轮询,线程数量控制在10个以内即可。如果账号数量很大,可以考虑用asyncio协程来替代线程,减少线程切换开销,不过协程在抢购这种短时爆发场景下的收益并不明显,线程方案已经够用。
4.4 日志与结果判定:不要用print一句了事
抢购过程中你会频繁遇到“排队中”“已售罄”“系统繁忙”等业务状态,建议把所有返回结果按时间戳记录到日志文件,方便事后复盘。最小可用方案是Python标准库logging:
import logging logging.basicConfig( filename="jd_maotai.log", level=logging.INFO, format="%(asctime)s %(message)s" ) def submit_order(): result = do_submit() if result.get("success"): logging.info("SUCCESS orderId=%s", result.get("orderId")) else: logging.error("FAIL code=%s msg=%s", result.get("code"), result.get("message"))记录下每一次请求的精确时间戳、错误码和返回消息,之后可以根据日志分析“差多少毫秒没抢到”“是请求没发出还是被风控拒了”。这比对着屏幕反复刷新终端输出要高效得多。
5. 规避风控与安全边界:京东抢茅台Python脚本的合规用法与防封号
到了最后一章,说明白哪些坑不能踩,以及脚本的正确使用姿势。自动抢购天然处在平台规则边缘,这篇文章只能讲技术实现,但有几条红线必须清楚。
5.1 别踩的风控红线:请求频率与账号权重
京东对抢购场景有专门的风控策略:异常请求频率、无操作习惯的深夜登录、短时间内多个新设备登录同一账号,都可能触发账号受限。常见做法是把请求间隔控制在200毫秒以上,不要每次失败后立刻疯狂重试。提交订单失败后最多重试三次,每次间隔随机化,避免固定的间隔被识别成机器特征。
另外要理解“账号权重”这个概念。正常购物频次高、已实名认证、账号年龄大于一年的老号,通过风控的概率远高于刚注册的新号。脚本只能保证“请求有效到达”,账号本身的健康度是买不来也改变不了的。
5.2 结果校验与售后:抢到了怎么确认是“真茅台”
脚本返回“下单成功”不代表购买完成。京东抢购茅台通常有“锁单”机制,即下单成功后需要在限定时间内完成支付,支付超时订单自动取消。所以脚本跑完后的第一件事是打开京东App查看“待付款”订单,确认商品名称、规格(常见是53度500ml飞天茅台)和价格没问题再付款。
不要跳过了支付环节就以为万事大吉,付款限时通常是30分钟以内,具体以订单页倒计时为准。如果多个账号同时抢到,先付掉你自己要的那个,其余订单只要不付款会自行取消,不会产生违约记录,但不要帮别人代付或代下单——这属于账号共享行为,容易触发风控。
5.3 六个运行期问题速查
| 现象 | 原因 | 处理方式 |
|---|---|---|
| 接口返回“请先登录” | Cookie过期 | 重新抓取最新Cookie |
| 返回“商品已下架” | skuId错误或已售罄 | 核对商品URL的skuId |
| 返回“排队中” | 请求过早或风控拦截 | 调整提前量,放慢重试间隔 |
| 下单成功但订单没了 | 未在时限内支付 | 支付环节仍需人工操作 |
| 本地时间不准 | 未做NTP校准 | 校准后把offset打日志确认 |
| 脚本爆出乱码 | 控制台编码问题 | Windows下执行chcp 65001切UTF-8 |
最后的实战建议:把抢购动作拆成“手动预加购+半自动提交”的组合。脚本负责在目标时刻发出提交订单请求,你同时用手机或电脑手动刷新结算页作为兜底。两种方式并行,就算脚本因为某种原因没跑起来,手动操作还有机会补上。这个混合方案,也是身边还在坚持跑这类脚本的人普遍采用的做法。
本文还有配套的精品资源,点击获取