【Python】京东自动下单抢购脚本——双十一购物小技巧

最近种草一款富士📷已久,但限于富士产能,一直都没有等到开放购买,在尝试几次定闹钟到点准时抢购后,果断放弃,于是花了一个周末时间写了一个简易脚本,终于成为一名合格的“富家子弟”。

1 问题背景

经过无数次抢购失败后,发现商家会不定时的放出少量货源,目测每次会有几台。如果我们编写一个脚本程序24小时不间断监听商品库存,一旦查询到货源便开始尝试自动下单,这样就可以极大提高我们的成功概率。
在这里插入图片描述

2 设计思路

京东对于商品的抢购主要分为两种:

  • 预约抢购:到点开放购买,和普通商品下单流程一致;
  • 秒杀商品:单独的抢购接口和下单流程。

当然本次针对的预约抢购类或无货订购类,即整体下单流程和购买普通商品时一样:

登录账号 → 进入购物车 → 选择抢购商品 → 点击去结算 → 点击提交订单 → 选择付款方式并付款

3 具体实现

由于笔者本人没有一个可以抓包的客户端,决定采用京东 WEB 端接口实现我们的脚本程序。

于是经过对京东网页下单流程的分析,将我们的脚本程序分为四个模块:账号登录模块库存监听模块购物车管理模块订单管理模块。

3.1 账号登录

由于使用账号密码时有验证码限制,此处采用扫码登录方式绕过。

如对扫码登录不熟悉或感兴趣的同学可以查看周周之前的博文 扫码登录原理和实现

本次只要针对京东登录页进行抓包分析,找到几个有用接口:

  • 获取登录二维码
def getQRcode(self):
    url = 'https://qr.m.jd.com/show'
    payload = {
        'appid': 133,
        'size': 147,
        't': str(int(time.time() * 1000)),
    }
    headers = {
        'User-Agent': self.userAgent,
        'Referer': 'https://passport.jd.com/new/login.aspx',
    }
    resp = self.sess.get(url=url, headers=headers, params=payload)

    if not self.respStatus(resp):
        return None

    return resp.content
  • 获取Ticket
def getQRcodeTicket(self):
    url = 'https://qr.m.jd.com/check'
    payload = {
        'appid': '133',
        'callback': 'jQuery{}'.format(random.randint(1000000, 9999999)),
        'token': self.sess.cookies.get('wlfstk_smdl'),
        '_': str(int(time.time() * 1000)),
    }
    headers = {
        'User-Agent': self.userAgent,
        'Referer': 'https://passport.jd.com/new/login.aspx',
    }
    resp = self.sess.get(url=url, headers=headers, params=payload)

    if not self.respStatus(resp):
        return False

    respJson = self.parseJson(resp.text)
    if respJson['code'] != 200:
        return None
    else:
        return respJson['ticket']
  • 验证 Ticket
def validateQRcodeTicket(self, ticket):
    url = 'https://passport.jd.com/uc/qrCodeTicketValidation'
    headers = {
        'User-Agent': self.userAgent,
        'Referer': 'https://passport.jd.com/uc/login?ltype=logout',
    }
    resp = self.sess.get(url=url, headers=headers, params={'t': ticket})

    if not self.respStatus(resp):
        return False

    respJson = json.loads(resp.text)
    if respJson['returnCode'] == 0:
        return True
    else:
        return False

此时验证 Ticket 有效后使用 pickle 库将程序会话中的 cookie 保存到本地以便下次使用。

3.2 库存监听

库存监听较为简单,分析商品详情页,获取店铺ID以及商品分类属性:

  • 获取商品详情信息
def getItemDetail(self, skuId):
    url = 'https://item.jd.com/{}.html'.format(skuId)
    page = requests.get(url=url, headers=self.headers)

    html = etree.HTML(page.text)
    vender = html.xpath(
        '//div[@class="follow J-follow-shop"]/@data-vid')[0]
    cat = html.xpath('//a[@clstag="shangpin|keycount|product|mbNav-3"]/@href')[
        0].replace('//list.jd.com/list.html?cat=', '')

    if not vender or not cat:
        raise Exception('获取商品信息失败,请检查SKU是否正确')

    detail = dict(catId=cat, venderId=vender)
    return detail
  • 查询库存
def getItemStock(self, skuId, num, areaId):

    item = self.itemDetails.get(skuId)

    if not item:
        return False

    url = 'https://c0.3.cn/stock'
    payload = {
        'skuId': skuId,
        'buyNum': num,
        'area': areaId,
        'ch': 1,
        '_': str(int(time.time() * 1000)),
        'callback': 'jQuery{}'.format(random.randint(1000000, 9999999)),
        # get error stock state without this param
        'extraParam': '{"originid":"1"}',
        # get 403 Forbidden without this param (obtained from the detail page)
        'cat': item.get('catId'),
        # return seller information with this param (can't be ignored)
        'venderId': item.get('venderId')
    }
    headers = {
        'User-Agent': self.userAgent,
        'Referer': 'https://item.jd.com/{}.html'.format(skuId),
    }

    respText = ''
    try:
        respText = requests.get(
            url=url, params=payload, headers=headers, timeout=self.timeout).text
        respJson = self.parseJson(respText)
        stockInfo = respJson.get('stock')
        skuState = stockInfo.get('skuState')  # 商品是否上架
        # 商品库存状态:33 -- 现货  0,34 -- 无货  36 -- 采购中  40 -- 可配货
        stockState = stockInfo.get('StockState')
        return skuState == 1 and stockState in (33, 40)

3.3 购物车操作

无货商品加入到购物车我们是无法通过页面操作的,我们这边可以使用其他有货商品进行尝试,主要查看购物车的增删改查接口:

  • 取消所有选中商品
def uncheckCartAll(self):
    """ 取消所有选中商品
    return 购物车信息
    """
    url = 'https://api.m.jd.com/api'

    headers = {
        'User-Agent': self.userAgent,
        'Content-Type': 'application/x-www-form-urlencoded',
        'origin': 'https://cart.jd.com',
        'referer': 'https://cart.jd.com'
    }

    data = {
        'functionId': 'pcCart_jc_cartUnCheckAll',
        'appid': 'JDC_mall_cart',
        'body': '{"serInfo":{"area":"","user-key":""}}',
        'loginType': 3
    }

    resp = self.sess.post(url=url, headers=headers, data=data)

    # return self.respStatus(resp) and resp.json()['success']
    return resp
  • 加入购入车
def addCartSku(self, skuId, skuNum):
    """ 加入购入车
    skuId 商品sku
    skuNum 购买数量
    retrun 是否成功
    """
    url = 'https://api.m.jd.com/api'
    headers = {
        'User-Agent': self.userAgent,
        'Content-Type': 'application/x-www-form-urlencoded',
        'origin': 'https://cart.jd.com',
        'referer': 'https://cart.jd.com'
    }
    data = {
        'functionId': 'pcCart_jc_cartAdd',
        'appid': 'JDC_mall_cart',
        'body': '{\"operations\":[{\"carttype\":1,\"TheSkus\":[{\"Id\":\"' + skuId + '\",\"num\":' + str(skuNum) + '}]}]}',
        'loginType': 3
    }
    resp = self.sess.post(url=url, headers=headers, data=data)
    return self.respStatus(resp) and resp.json()['success']
  • 修改购物车商品数量
def changeCartSkuCount(self, skuId, skuUid, skuNum, areaId):
    """ 修改购物车商品数量
    skuId 商品sku
    skuUid 商品用户关系
    skuNum 购买数量
    retrun 是否成功
    """
    url = 'https://api.m.jd.com/api'
    headers = {
        'User-Agent': self.userAgent,
        'Content-Type': 'application/x-www-form-urlencoded',
        'origin': 'https://cart.jd.com',
        'referer': 'https://cart.jd.com'
    }
    body = '{\"operations\":[{\"TheSkus\":[{\"Id\":\"'+skuId+'\",\"num\":'+str(
        skuNum)+',\"skuUuid\":\"'+skuUid+'\",\"useUuid\":false}]}],\"serInfo\":{\"area\":\"'+areaId+'\"}}'
    data = {
        'functionId': 'pcCart_jc_changeSkuNum',
        'appid': 'JDC_mall_cart',
        'body': body,
        'loginType': 3
    }
    resp = self.sess.post(url=url, headers=headers, data=data)
    return self.respStatus(resp) and resp.json()['success']

以上是我们一次购买需要用到的最少接口,为了不破坏账户购物车中已有数据,采用一下步骤准备好购物车:

  1. 取消全部勾选(返回购物车信息);
  2. 已在购物车则修改商品数量;
  3. 不在购物车则加入购物车。

3.4 订单操作

当我们准备好购物车之后(选中购买商品以及调整购买数量),就可以进行下一步订单相关操作:

  • 获取结算单
def getCheckoutPage(self):
    """获取订单结算页面信息
    :return: 结算信息 dict
    """
    url = 'http://trade.jd.com/shopping/order/getOrderInfo.action'
    # url = 'https://cart.jd.com/gotoOrder.action'
    payload = {
        'rid': str(int(time.time() * 1000)),
    }
    headers = {
        'User-Agent': self.userAgent,
        'Referer': 'https://cart.jd.com/cart',
    }
  • 提交订单
def submitOrder(self):
    """提交订单
    :return: True/False 订单提交结果
    """
    url = 'https://trade.jd.com/shopping/order/submitOrder.action'
    # js function of submit order is included in https://trade.jd.com/shopping/misc/js/order.js?r=2018070403091

    data = {
        'overseaPurchaseCookies': '',
        'vendorRemarks': '[]',
        'submitOrderParam.sopNotPutInvoice': 'false',
        'submitOrderParam.trackID': 'TestTrackId',
        'submitOrderParam.ignorePriceChange': '0',
        'submitOrderParam.btSupport': '0',
        'riskControl': self.risk_control,
        'submitOrderParam.isBestCoupon': 1,
        'submitOrderParam.jxj': 1,
        'submitOrderParam.trackId': self.track_id,
        'submitOrderParam.eid': self.eid,
        'submitOrderParam.fp': self.fp,
        'submitOrderParam.needCheck': 1,
    }

4 完整代码

项目完整源码请看:https://github.com/zas023/JdBuyer

在这里插入图片描述

目前完成度较高,可以直接使用:

  • 并提供 Windows 和 macOS 两种客户端;
  • 支持下单后微信通知触达。

5 总结

脚本自动化操作确实可以实现抢购商品,相比手动操作有较高的下单成功率,但仅靠上述代码想与某些专业抢购的服务器进行比较还是相去甚远。

在这里插入图片描述

  • 43
    点赞
  • 314
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 46
    评论
【资源说明】 基于python实现的京东预约商品自动下单源码.zip 京东预约商品抢购 借鉴了https://github.com/Lasx/jd_mask的代码 十分感谢原作者! 本来其实是准备直接下载下来用的, 但是跑了一下, 失败了, 因为送货地址取不到。然后自己改了一下代码。 在2022/12/26晚上用来抢了一单抗原,它能自动下单成功, 下单成功后需要你去点开订单手动支付。 2022-12-26 20:15:00,335 INFO: 时间到达,开始执行…… 2022-12-26 20:15:00,534 INFO: 抢购链接获取失败,%s不是抢购商品或抢购页面暂未刷新,1秒后重试 2022-12-26 20:15:01,735 INFO: 抢购链接获取成功: https://marathon.jd.com/captcha.html?skuId=xxxxx 2022-12-26 20:15:01,735 INFO: 访问商品的抢购连接... 2022-12-26 20:15:01,980 INFO: 访问抢购订单结算页面... 2022-12-26 20:15:02,064 INFO: 生成提交抢购订单所需参数... 2022-12-26 20:15:02,064 INFO: 获取秒杀初始化信息... 2022-12-26 20:15:02,254 INFO: 提交抢购订单... 2022-12-26 20:15:02,505 INFO: 抢购成功,订单号:***, 总价:**.90, 电脑端付款链接:https://sko.jd.com/success/success.action?orderId=xx 主要功能 登陆京东商城(www.jd.com) cookies登录 (需要自己手动获取) 预约商品 定时自动预约 秒杀预约后等待抢购的商品 定时开始自动抢购 运行环境 Python 3 第三方库 Requests 使用教程 程序主入口在 main.py 在config.ini文件填入config里面对应的内容 eid,和fp找个普通商品随便下单,然后抓包就能看到,这两个值可以填固定的(在京东订单结算页面,F12 console里面输入_JdTdudfp就会返回一个json对象,里面就有) cookies_string,sku_id,DEFAULT_USER_AGENT(和cookie获取同一个地方就会看到.直接复制进去就可以了),以上都是必填的. 启动时按照提示操作输入需要的功能即可 更新记录 备注 使用的时候需要注意一下本机的时间是否和标准时间是一致的,一开始我用的wsl来跑, 结果发现wsl和windows的时间不同步,贼尴尬。 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
Golang京东抢购是指使用Golang编程语言来实现京东网站商品的抢购功能。Golang是一种强大的编程语言,具有高效的并发处理能力,非常适合用于编写抢购程序。 在实现Golang京东抢购时,首先需要使用Golang的网络请求库来模拟用户登录京东账号以及访问商品页面的过程。可以使用京东的登录接口获取用户的登录凭证,并将其保存在请求头中。然后可以通过访问商品页面接口获取商品的详细信息,包括售价、库存等。 在抢购过程中,需要使用Golang的并发处理能力同时发起多个网络请求,以增加抢购的成功率。可以通过设置协程来同时抢购多个商品,从而提高并发能力。在抢购时,需要将抢购请求发送给京东服务器,并监听返回信息,判断是否抢购成功。 为了增加抢购成功的概率,可以在程序中添加一些延迟措施,比如加入随机延迟,或者在请求时添加一些冗余数据,以避免被京东服务器判断为机器人行为。 另外,为了保证程序的高效性和稳定性,在实现过程中可以加入一些异常处理机制,比如网络连接超时、访问频率限制等情况的处理。同时,可以使用日志记录程序运行过程中的关键信息,便于排查问题和优化程序性能。 总之,使用Golang来实现京东抢购功能可以提高抢购的效率和成功率,同时保证程序的可靠性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿周周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值