Home  >  Article  >  Backend Development  >  How to use Python to write an automatic JD ordering script?

How to use Python to write an automatic JD ordering script?

WBOY
WBOYforward
2023-05-06 19:52:174444browse

1 Background of the problem

After countless failed rush-buying attempts, I found that merchants would release a small amount of supply from time to time, and I visually estimated how many units there would be at each time. If we write a script to monitor product inventory 24 hours a day, and once the source of goods is queried, we will try to place orders automatically, which can greatly increase our probability of success.

2 Design Ideas

Jingdong’s rush buying of goods is mainly divided into two types:

Appointment rush buying: open to purchase at the point, the same as the ordering process for ordinary goods; flash sale goods : Separate snap-up interface and ordering process.

Of course, this time we are targeting reservation rush purchases or out-of-stock orders, that is, the overall ordering process is the same as when purchasing ordinary goods:

Log in to your account→ Enter the shopping cart→ Select the product to snap up→ Click to checkout→ Click to submit the order→ Select the payment method and make the payment.

3 Specific implementation

Since the author does not have a client that can capture packets, I decided to use JD.com’s WEB interface to implement our script program.

So after analyzing the ordering process on Jingdong’s webpage, our script program was divided into four modules: Account login module, Inventory monitoring module, Shopping Cart Management Module, Order Management Module.

3.1 Account login

Since there are verification code restrictions when using account passwords, scan the QR code to log in to bypass it.

For students who are not familiar with or are interested in scanning code login, you can check Zhou Zhou’s previous blog post on the principle and implementation of scanning code login.

This time I only need to perform packet capture analysis on the JD login page and find several useful interfaces:

Get the login QR code
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
Get 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']
Verify 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']

After verifying that the Ticket is valid, use the pickle library to save the cookie in the program session to local area for next time use.

3.2 Inventory monitoring

Inventory monitoring is relatively simple. Analyze the product details page and obtain the store ID and product classification attributes:

Get product details information
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
Check inventory
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 Shopping cart operation

We cannot add out-of-stock items to the shopping cart through the page operation, but we can here Try using other in-stock products, mainly check the add, delete, modify and check interface of the shopping cart:

Cancel all selected products
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
Add to purchase cart
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']
Modify the number of items in the shopping cart
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']

The above is the minimum interface we need to use for one purchase. In order not to destroy the existing data in the account shopping cart, use Prepare the shopping cart in the following steps:

Cancel all checks (return to the shopping cart information); modify the quantity of items if they are already in the shopping cart; add to the shopping cart if they are not in the shopping cart. 3.4 Order operations

After we prepare the shopping cart (select the items to purchase and adjust the purchase quantity), we can proceed to the next order-related operations:

Get the settlement form
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',
    }
Submit order
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,
    }

The above is the detailed content of How to use Python to write an automatic JD ordering script?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete