>  기사  >  백엔드 개발  >  Python을 사용하여 자동 JD 주문 스크립트를 작성하는 방법은 무엇입니까?

Python을 사용하여 자동 JD 주문 스크립트를 작성하는 방법은 무엇입니까?

WBOY
WBOY앞으로
2023-05-06 19:52:174423검색

1 문제 배경

수없이 많은 구매 실패 끝에 상인들이 가끔씩 소량의 물량을 풀어놓는 걸 발견하고 그때마다 몇 개씩 나올지 눈으로 가늠해 봤습니다. 24시간 제품 재고를 모니터링하는 스크립트를 작성하고, 상품 출처를 조회하면 자동으로 주문을 시도하게 되어 성공 확률이 크게 높아질 수 있습니다.

2가지 디자인 아이디어

JD의 성급한 상품 구매는 크게 두 가지 유형으로 나뉩니다.

예약 구매: 현장 구매 가능, 일반 상품의 주문 과정과 동일: 별도 구매 인터페이스; 그리고 주문과정.

물론, 이번은 예약 급하게 구매하거나 품절 주문을 대상으로 합니다. 즉, 전체적인 주문 과정은 일반 상품 구매와 동일합니다.

로그인하세요.→ 장바구니→ 긴급 구매 제품 선택→ 주문 제출 클릭→ 결제 방법을 선택하세요. <code>登录账号 &rarr; 进入购物车 &rarr; 选择抢购商品 &rarr; 点击去结算 &rarr; 点击提交订单 &rarr; 选择付款方式并付款

3 具体实现

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

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

3.1 账号登录

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

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

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

获取登录二维码
def getQRcode(self):
    url = &#39;https://qr.m.jd.com/show&#39;
    payload = {
        &#39;appid&#39;: 133,
        &#39;size&#39;: 147,
        &#39;t&#39;: str(int(time.time() * 1000)),
    }
    headers = {
        &#39;User-Agent&#39;: self.userAgent,
        &#39;Referer&#39;: &#39;https://passport.jd.com/new/login.aspx&#39;,
    }
    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 = &#39;https://qr.m.jd.com/check&#39;
    payload = {
        &#39;appid&#39;: &#39;133&#39;,
        &#39;callback&#39;: &#39;jQuery{}&#39;.format(random.randint(1000000, 9999999)),
        &#39;token&#39;: self.sess.cookies.get(&#39;wlfstk_smdl&#39;),
        &#39;_&#39;: str(int(time.time() * 1000)),
    }
    headers = {
        &#39;User-Agent&#39;: self.userAgent,
        &#39;Referer&#39;: &#39;https://passport.jd.com/new/login.aspx&#39;,
    }
    resp = self.sess.get(url=url, headers=headers, params=payload)

    if not self.respStatus(resp):
        return False

    respJson = self.parseJson(resp.text)
    if respJson[&#39;code&#39;] != 200:
        return None
    else:
        return respJson[&#39;ticket&#39;]
验证 Ticket
def getQRcodeTicket(self):
    url = &#39;https://qr.m.jd.com/check&#39;
    payload = {
        &#39;appid&#39;: &#39;133&#39;,
        &#39;callback&#39;: &#39;jQuery{}&#39;.format(random.randint(1000000, 9999999)),
        &#39;token&#39;: self.sess.cookies.get(&#39;wlfstk_smdl&#39;),
        &#39;_&#39;: str(int(time.time() * 1000)),
    }
    headers = {
        &#39;User-Agent&#39;: self.userAgent,
        &#39;Referer&#39;: &#39;https://passport.jd.com/new/login.aspx&#39;,
    }
    resp = self.sess.get(url=url, headers=headers, params=payload)

    if not self.respStatus(resp):
        return False

    respJson = self.parseJson(resp.text)
    if respJson[&#39;code&#39;] != 200:
        return None
    else:
        return respJson[&#39;ticket&#39;]

此时验证 Ticket 有效后使用 pickle

3 구체적인 구현

저자는 패킷을 캡처할 수 있는 클라이언트가 없기 때문에 JD.com WEB 인터페이스를 사용하여 스크립트 프로그램을 구현하기로 결정했습니다.

그래서 JD.com 웹페이지의 주문 프로세스를 분석한 후 스크립트 프로그램을
계정 로그인 모듈, 재고 모니터링 모듈
,
장바구니 관리 모듈, 주문 관리 모듈의 네 가지 모듈로 나누었습니다.

3.1 계정 로그인

계정 비밀번호 사용 시 인증코드 제한으로 인해, QR코드를 스캔하여 우회하여 로그인하시기 바랍니다.
QR 코드 로그인에 대해 잘 모르거나 관심이 있는 학생들은 QR 코드 로그인의 원리와 구현에 대한 Zhou Zhou의 이전 블로그 게시물을 확인하실 수 있습니다.
이번에는 JD 로그인 페이지에서 패킷 캡처 분석만 수행하고 몇 가지 유용한 인터페이스를 찾으면 됩니다.
로그인 QR 코드 받기
def getItemDetail(self, skuId):
    url = &#39;https://item.jd.com/{}.html&#39;.format(skuId)
    page = requests.get(url=url, headers=self.headers)

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

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

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

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

티켓 확인하기

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

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

    data = {
        &#39;functionId&#39;: &#39;pcCart_jc_cartUnCheckAll&#39;,
        &#39;appid&#39;: &#39;JDC_mall_cart&#39;,
        &#39;body&#39;: &#39;{"serInfo":{"area":"","user-key":""}}&#39;,
        &#39;loginType&#39;: 3
    }

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

    # return self.respStatus(resp) and resp.json()[&#39;success&#39;]
    return resp

티켓 확인하기 이때 유효성 검사 후 pickle 라이브러리를 사용하여 다음 번 사용을 위해 프로그램 세션의 쿠키를 로컬에 저장합니다.
3.2 재고 모니터링
재고 모니터링은 비교적 간단하며 제품 세부 정보 페이지를 분석하고 매장 ID 및 제품 분류 속성을 얻습니다.
제품 세부 정보 가져오기
🎜
def addCartSku(self, skuId, skuNum):
    """ 加入购入车
    skuId 商品sku
    skuNum 购买数量
    retrun 是否成功
    """
    url = &#39;https://api.m.jd.com/api&#39;
    headers = {
        &#39;User-Agent&#39;: self.userAgent,
        &#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded&#39;,
        &#39;origin&#39;: &#39;https://cart.jd.com&#39;,
        &#39;referer&#39;: &#39;https://cart.jd.com&#39;
    }
    data = {
        &#39;functionId&#39;: &#39;pcCart_jc_cartAdd&#39;,
        &#39;appid&#39;: &#39;JDC_mall_cart&#39;,
        &#39;body&#39;: &#39;{\"operations\":[{\"carttype\":1,\"TheSkus\":[{\"Id\":\"&#39; + skuId + &#39;\",\"num\":&#39; + str(skuNum) + &#39;}]}]}&#39;,
        &#39;loginType&#39;: 3
    }
    resp = self.sess.post(url=url, headers=headers, data=data)
    return self.respStatus(resp) and resp.json()[&#39;success&#39;]
🎜🎜재고 쿼리🎜🎜
def changeCartSkuCount(self, skuId, skuUid, skuNum, areaId):
    """ 修改购物车商品数量
    skuId 商品sku
    skuUid 商品用户关系
    skuNum 购买数量
    retrun 是否成功
    """
    url = &#39;https://api.m.jd.com/api&#39;
    headers = {
        &#39;User-Agent&#39;: self.userAgent,
        &#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded&#39;,
        &#39;origin&#39;: &#39;https://cart.jd.com&#39;,
        &#39;referer&#39;: &#39;https://cart.jd.com&#39;
    }
    body = &#39;{\"operations\":[{\"TheSkus\":[{\"Id\":\"&#39;+skuId+&#39;\",\"num\":&#39;+str(
        skuNum)+&#39;,\"skuUuid\":\"&#39;+skuUid+&#39;\",\"useUuid\":false}]}],\"serInfo\":{\"area\":\"&#39;+areaId+&#39;\"}}&#39;
    data = {
        &#39;functionId&#39;: &#39;pcCart_jc_changeSkuNum&#39;,
        &#39;appid&#39;: &#39;JDC_mall_cart&#39;,
        &#39;body&#39;: body,
        &#39;loginType&#39;: 3
    }
    resp = self.sess.post(url=url, headers=headers, data=data)
    return self.respStatus(resp) and resp.json()[&#39;success&#39;]
🎜3.3 장바구니 작업 🎜🎜없음 페이지 작업을 통해 재고 품목을 장바구니에 추가할 수 없습니다. 여기서는 다른 재고 품목을 사용하여 장바구니의 추가, 삭제, 수정 및 확인을 주로 확인할 수 있습니다. 🎜🎜 🎜선택한 항목 모두 취소🎜🎜
def getCheckoutPage(self):
    """获取订单结算页面信息
    :return: 结算信息 dict
    """
    url = &#39;http://trade.jd.com/shopping/order/getOrderInfo.action&#39;
    # url = &#39;https://cart.jd.com/gotoOrder.action&#39;
    payload = {
        &#39;rid&#39;: str(int(time.time() * 1000)),
    }
    headers = {
        &#39;User-Agent&#39;: self.userAgent,
        &#39;Referer&#39;: &#39;https://cart.jd.com/cart&#39;,
    }
🎜🎜구매 추가 장바구니에 담기🎜🎜
def submitOrder(self):
    """提交订单
    :return: True/False 订单提交结果
    """
    url = &#39;https://trade.jd.com/shopping/order/submitOrder.action&#39;
    # js function of submit order is included in https://trade.jd.com/shopping/misc/js/order.js?r=2018070403091

    data = {
        &#39;overseaPurchaseCookies&#39;: &#39;&#39;,
        &#39;vendorRemarks&#39;: &#39;[]&#39;,
        &#39;submitOrderParam.sopNotPutInvoice&#39;: &#39;false&#39;,
        &#39;submitOrderParam.trackID&#39;: &#39;TestTrackId&#39;,
        &#39;submitOrderParam.ignorePriceChange&#39;: &#39;0&#39;,
        &#39;submitOrderParam.btSupport&#39;: &#39;0&#39;,
        &#39;riskControl&#39;: self.risk_control,
        &#39;submitOrderParam.isBestCoupon&#39;: 1,
        &#39;submitOrderParam.jxj&#39;: 1,
        &#39;submitOrderParam.trackId&#39;: self.track_id,
        &#39;submitOrderParam.eid&#39;: self.eid,
        &#39;submitOrderParam.fp&#39;: self.fp,
        &#39;submitOrderParam.needCheck&#39;: 1,
    }
🎜🎜장바구니에 있는 항목 수 수정🎜🎜rrreee🎜위는 구매에 필요한 최소 인터페이스입니다. 계정 장바구니에 있는 기존 데이터를 삭제하지 않으려면 다음 단계를 사용하여 장바구니를 준비하세요. 🎜🎜취소 모두 확인(장바구니 정보로 돌아가기), 이미 장바구니에 있는 경우 제품 수량을 수정하세요. 장바구니에 없으면 장바구니에 추가하세요. 3.4 주문 작업🎜🎜장바구니를 준비한 후(구매할 품목 선택 및 구매 수량 조정) 다음 주문 관련 작업을 진행할 수 있습니다. 🎜🎜🎜결제 양식 받기🎜🎜rrreee🎜🎜주문 제출 🎜🎜rrreee

위 내용은 Python을 사용하여 자동 JD 주문 스크립트를 작성하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제