文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-09-03 09:16

关注

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

文章目录

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
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']
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

在这里插入图片描述

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

5 总结

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

在这里插入图片描述

来源地址:https://blog.csdn.net/adminpd/article/details/127188898

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯