Files
kami_spider_monorepo/apps/jd/services/ctrip.py
danial 6c768b6e7b feat(jd): 添加京东相关路由及苹果权益充值功能
- 新增jd模块基础路由,整合app_store和payment子路由
- 实现苹果权益充值接口,支持苹果、携程及沃尔玛多个渠道
- 实现卡号密码查询接口,支持不同类别订单查询
- 新增短信认证相关接口,实现短信验证码发送及短信登录
- 新增商品管理接口,支持SKU详情查询及账号类下单功能
- 新增订单管理接口,实现订单删除功能
- 实现支付相关接口,增加刷新支付参数功能
- 定义完整请求及响应数据模型,确保接口数据规范
- 编写AppStoreSpider类,封装苹果应用内订单处理逻辑
- 引入多种代理池及请求重试机制,增强接口稳定性
- 添加详细日志记录,便于请求追踪与错误排查
2025-11-03 19:35:39 +08:00

818 lines
37 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import hashlib
import json
from logging import LoggerAdapter
import platform
import re
import time
import fake_useragent
from curl_cffi import ProxySpec, requests
from apps.jd.schemas.models import QueryCardResponseData
from apps.shared.proxy_pool.proxy_pool import ProxyPoolFactory
from core.config import ProxyPoolType
from core.exceptions import JDServiceException
from core.responses import BusinessCode
from observability.logging import get_logger_with_trace
logger: LoggerAdapter = get_logger_with_trace(__name__)
class XiechengCardSpider:
"""
携程
100元10140177420168
200元10148161391225
300元10148163028307
500元10148178960836
1000元10148179392280
"""
def __init__(self, cookies, order_num, sku_id):
self.eid = None
self.x_token = None
self._session = requests.Session()
self._order_num = order_num
self.cookies = cookies
self.time_stamp = int(time.time() * 1000)
self.current_os = platform.system()
self.sku_id = sku_id
self.submit_order_url = "https://api.m.jd.com/appstore/submitorder"
self.ticket_url = "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkcaptcha"
self.jd_api = "https://api.m.jd.com/api"
self.action_url = "https://api.m.jd.com/client.action"
self.check_captcha_url = (
"https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkcaptcha"
)
self._expiring_pool = ProxyPoolFactory.get_proxy_pool(
ProxyPoolType.EXPIRING, expire_time=60
)
self.user_agent = fake_useragent.FakeUserAgent().chrome
def _get_proxy(self):
proxy = self._expiring_pool.get_proxy(order_id=self._order_num)
return ProxySpec(all=proxy) if proxy else None
# def get_ticket_res(self):
# for i in range(1):
# try:
# headers = {
# "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
# "Accept-Language": "zh-CN,zh;q=0.9",
# "Cache-Control": "no-cache",
# "Connection": "keep-alive",
# "Pragma": "no-cache",
# "Upgrade-Insecure-Requests": "1",
# "User-Agent": self.user_agent,
# }
# url = f"http://119.23.175.61:8877/captcha/tx?aid=2093769752&ip={self.proxy}&host=https://t.captcha.qq.com"
# logger.info(f"获取ticket请求代理{self.proxy}")
# logger.info(f"获取ticket请求{url}")
# response = self._session.get(
# url, headers=headers, verify=False, timeout=60
# )
# logger.info(f"获取ticket结果{response.text}")
# if response.json().get("msg_code") != 200:
# continue
# if response.json().get("result", {}).get(
# "ticket"
# ) and response.json().get("result", {}).get("randstr"):
# return {
# "ticket": response.json().get("result", {}).get("ticket"),
# "randstr": response.json().get("result", {}).get("randstr"),
# }
# except Exception as e:
# logger.error(e)
# raise Exception("获取ticket失败")
def get_pay_res(self, order_id):
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/json;charset=UTF-8",
"origin": "https://trade.m.jd.com",
"priority": "u=1, i",
"referer": "https://trade.m.jd.com/",
"sec-ch-ua": '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": self.user_agent,
"x-referer-page": "https://trade.m.jd.com/order/orderlist_jdm.shtml",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies,
}
body = (
'{"appType":3,"bizType":"2","deviceUUId":"","platform":3,"sceneval":"2","source":"m_inner_myJd.orderFloor_orderlist","systemBaseInfo":"{\\"pixelRatio\\":1.25,\\"screenWidth\\":2048,\\"screenHeight\\":1152,\\"windowWidth\\":414,\\"windowHeight\\":1034,\\"statusBarHeight\\":null,\\"safeArea\\":{\\"bottom\\":0,\\"height\\":0,\\"left\\":0,\\"right\\":0,\\"top\\":0,\\"width\\":0},\\"bluetoothEnabled\\":false,\\"locationEnabled\\":false,\\"wifiEnabled\\":false,\\"deviceOrientation\\":\\"landscape\\",\\"benchmarkLevel\\":-1,\\"brand\\":\\"\\",\\"model\\":\\"\\",\\"system\\":null,\\"platform\\":\\"Win32\\",\\"SDKVersion\\":\\"\\",\\"enableDebug\\":false,\\"language\\":\\"zh-CN\\",\\"version\\":\\"\\",\\"theme\\":\\"light\\",\\"fontSizeSetting\\":null,\\"albumAuthorized\\":false,\\"cameraAuthorized\\":false,\\"locationAuthorized\\":false,\\"microphoneAuthorized\\":false,\\"notificationAuthorized\\":false,\\"notificationAlertAuthorized\\":false,\\"notificationBadgeAuthorized\\":false,\\"notificationSoundAuthorized\\":false,\\"phoneCalendarAuthorized\\":false,\\"locationReducedAccuracy\\":false,\\"environment\\":\\"\\"}","orderId":"%s","origin":10,"tenantCode":"jgm","bizModelCode":"2","bizModeClientType":"M","bizModeFramework":"Taro","externalLoginType":1,"token":"3852b12f8c4d869b7ed3e2b3c68c9436","appId":"m91d27dbf599dff74"}'
% order_id
)
encrypt_body = self.sha256_hash(body)
timestamp = f"{int(time.time() * 1000)}"
object_id = "9b070"
function_id = "pay_info_m"
h5st = self.get_h5st(timestamp, encrypt_body, object_id, function_id)
params = {
"t": f"{self.time_stamp}",
"loginType": "2",
"loginWQBiz": "golden-trade",
"appid": "m_core",
"client": "Win32",
"clientVersion": "",
"build": "",
"osVersion": "null",
"screen": "2048*1152",
"networkType": "4g",
"partner": "",
"forcebot": "",
"d_brand": "",
"d_model": "",
"lang": "zh-CN",
"scope": "",
"sdkVersion": "",
"openudid": "",
"uuid": "17295878824571442265187",
"x-api-eid-token": self.x_token,
"functionId": "pay_info_m",
"body": body,
"h5st": h5st,
}
proxy = self._get_proxy()
response = self._session.get(
self.action_url,
headers=headers,
params=params,
verify=False,
proxies=proxy,
)
return response.json()
def plat_pay_channel_res(self, pay_id):
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://mpay.m.jd.com",
"priority": "u=1, i",
"referer": "https://mpay.m.jd.com/",
"sec-ch-ua": '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": self.user_agent,
"x-referer-page": "https://mpay.m.jd.com/mpay.623f9498223cf9b9de9f.html",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies,
}
params = {"functionId": "platPayChannel", "appid": "mcashier", "scval": "mpay"}
body = (
'{"appId":"m_D1vmUq63","payId":"%s","source":"mcashier","origin":"h5","mcashierTraceId":1729842386189}'
% pay_id
)
encrypt_body = self.sha256_hash(body)
timestamp = f"{int(time.time() * 1000)}"
object_id = "303a7"
function_id = "plat_pay_channel"
proxy = self._get_proxy()
h5st = self.get_h5st(timestamp, encrypt_body, object_id, function_id)
data = {"body": body, "x-api-eid-token": self.x_token, "h5st": h5st}
response = self._session.post(
self.action_url,
headers=headers,
params=params,
data=data,
verify=False,
proxies=proxy,
)
return response.json()
def get_locdetails(self, order_id):
url = "https://api.m.jd.com/"
data = {
"appid": "loc",
"loginType": "2",
"cthr": "1",
"loginWQBiz": "locdetails",
"t": f"{int(time.time() * 1000)}",
"functionId": "queryLocOrderDetail",
"body": '{"version":"1.0.0","source":"","requestId":1757908327795,"orderId":"%s","oldHttp2Color":true}'
% order_id,
}
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://locdetails.jd.com",
"pragma": "no-cache",
"priority": "u=1, i",
"referer": "https://locdetails.jd.com/",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": self.user_agent,
"x-referer-page": "https://locdetails.jd.com/h5/index.html",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies,
}
# proxy = self._get_proxy()
response = self._session.post(
url,
headers=headers,
data=data,
verify=False,
# proxies={
# "http": proxy,
# "https": proxy,
# },
)
res = response.json()
if res.get("code") == 20001:
return BusinessCode.JD_ORDER_CK_ERR, QueryCardResponseData(
order_status="",
card_num="",
card_pwd="",
remark=str(res),
)
if res and res.get("code") == 0:
logger.info(f"请求结果 {response.json()}")
data = res.get("data", {})
order_status_data = data.get("orderStatusData", {})
shop_sku_info_list = data.get("shopSkuInfoList", [])
card_num = ""
card_pwd = ""
if shop_sku_info_list and len(shop_sku_info_list) > 0:
sku_infos = shop_sku_info_list[0].get("skuInfos", [])
if sku_infos and len(sku_infos) > 0:
code_info = sku_infos[0].get("codeInfo", [])
if code_info and len(code_info) > 0:
card_num = code_info[0].get("cardNum", "")
card_pwd = code_info[0].get("pwdNum", "")
return BusinessCode.SUCCESS, QueryCardResponseData(
order_status=order_status_data.get("statusName", ""),
card_num=card_num,
card_pwd=card_pwd,
)
else:
return BusinessCode.JD_ORDER_NORMAL_ERR, QueryCardResponseData(
order_status="", card_num="", card_pwd="", remark=str(res)
)
def plat_wx_pay_res(self, pay_id):
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://mpay.m.jd.com",
"priority": "u=1, i",
"referer": "https://mpay.m.jd.com/",
"sec-ch-ua": '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": self.user_agent,
"x-referer-page": "https://mpay.m.jd.com/mpay.623f9498223cf9b9de9f.html",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies,
}
params = {"functionId": "platWapWXPay", "appid": "mcashier", "scval": "mpay"}
body = (
'{"appId":"m_D1vmUq63","payId":"%s","eid":"%s","source":"mcashier","origin":"h5","mcashierTraceId":1729837716957}'
% (pay_id, self.eid)
)
encrypt_body = self.sha256_hash(body)
timestamp = f"{int(time.time() * 1000)}"
object_id = "303a7"
function_id = "plat_wx_pay"
h5st = self.get_h5st(timestamp, encrypt_body, object_id, function_id)
data = {"body": body, "x-api-eid-token": self.x_token, "h5st": h5st}
proxy = self._get_proxy()
response = self._session.post(
self.action_url,
headers=headers,
params=params,
data=data,
verify=False,
proxies=proxy,
)
return response.json()
# def get_deep_link_res(self, mweb_url):
# headers = {
# "Host": "wx.tenpay.com",
# "sec-ch-ua-platform": '"Windows"',
# "User-Agent": self.user_agent,
# "sec-ch-ua": '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
# "sec-ch-ua-mobile": "?0",
# "Accept": "*/*",
# "Sec-Fetch-Site": "same-origin",
# "Sec-Fetch-Mode": "cors",
# "Sec-Fetch-Dest": "empty",
# "Referer": mweb_url,
# "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
# }
# prepay_id = re.search(r"prepay_id=(wx\w+)", mweb_url).group(1)
# package = re.search(r"package=(\d+)", mweb_url).group(1)
# ticket_res = self.get_ticket_res()
# logger.info(f"订单号:{self._order_num}获取ticket返回{ticket_res}")
# ticket = ticket_res["ticket"]
# randstr = ticket_res["randstr"]
# params = {
# "ticket": ticket,
# "randstr": randstr,
# "prepayid": prepay_id,
# "package": package,
# }
# proxy = self._get_proxy()
# response = self._session.get(
# self.check_captcha_url,
# headers=headers,
# params=params,
# verify=False,
# proxies=proxy,
# )
# return response.json()
@staticmethod
def sha256_hash(text):
# 创建 SHA-256 哈希对象
sha256 = hashlib.sha256()
# 更新哈希对象(输入必须为字节类型)
sha256.update(text.encode("utf-8"))
# 返回 16 进制格式的哈希值
return sha256.hexdigest()
def _get_pt_pin(self, cookie_str):
cookies = {}
for item in cookie_str.strip(";").split(";"):
if "=" in item:
key, value = item.strip().split("=", 1)
cookies[key] = value
pt_pin = cookies.get("pt_pin")
return pt_pin
def get_h5st(self, timestamp, body, object_id, function_id):
sua = "Windows NT 10.0; Win64; x64"
pt_pin = self._get_pt_pin(self.cookies)
params_str = f"ai={object_id}&sua={sua}&pin={pt_pin}&appid=m_core&functionId={function_id}&body={body}&client=Win32&clientVersion=2.5.2&t={timestamp}"
h5st = requests.get(f"http://127.0.0.1:8887/jd/h5st?{params_str}").text
return h5st
def get_x_token(self):
proxy = None
_proxy = self._get_proxy()
if _proxy:
proxy = _proxy.get("all")
data = {"type": "1", "str": self.user_agent}
if proxy:
data["proxy"] = proxy
response = requests.post(
"http://127.0.0.1:8887/api/stash/algorithm",
data=data,
)
logger.info(f"获取x-api-eid-token返回{response.text}")
res = response.json()
token = res["data"]["token"]
eid = res["data"]["eid"]
return token, eid
def get_current_order(self, retry_count: int = 3):
if not retry_count:
return JDServiceException(BusinessCode.JD_ORDER_RISK_ERR)
body = (
'{"deviceUUID":"6785593751540242498","appId":"wxae3e8056daea8727","appVersion":"2.5.2","tenantCode":"jgm","bizModelCode":"3","bizModeClientType":"M","token":"3852b12f8c4d869b7ed3e2b3c68c9436","externalLoginType":1,"referer":"https://item.m.jd.com/","resetGsd":true,"useBestCoupon":"1","locationId":"1-72-2819-0","packageStyle":true,"sceneval":"2","balanceCommonOrderForm":{"supportTransport":false,"action":1,"overseaMerge":false,"international":false,"netBuySourceType":0,"appVersion":"2.5.2","tradeShort":false},"balanceDeviceInfo":{"resolution":"2048*1152"},"cartParam":{"skuItem":{"skuId":"%s","num":"1","orderCashBack":false,"extFlag":{}}}}'
% self.sku_id
)
encrypt_body = self.sha256_hash(body)
timestamp = f"{int(time.time() * 1000)}"
object_id = "bd265"
function_id = "balance_getCurrentOrder_m"
h5st = self.get_h5st(timestamp, encrypt_body, object_id, function_id)
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://trade.m.jd.com",
"pragma": "no-cache",
"priority": "u=1, i",
"referer": "https://trade.m.jd.com/",
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": self.user_agent,
"x-referer-page": "https://trade.m.jd.com/pay",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies,
}
url = "https://api.m.jd.com/client.action"
data = {
"t": timestamp,
"body": body,
"h5st": h5st,
"scval": self.sku_id,
"client": "Win32",
"clientVersion": "2.5.2",
"osVersion": "other",
"screen": "2048*1152",
"networkType": "false",
"d_brand": "",
"d_model": "",
"lang": "zh-CN",
"sdkVersion": "2.5.2",
"appid": "m_core",
"openudid": "",
"x-api-eid-token": self.x_token,
"functionId": "balance_getCurrentOrder_m",
"uuid": "17573259367521124301157",
"loginType": "2",
"xAPIScval3": "unknown",
}
proxy = self._get_proxy()
response = self._session.post(
url,
headers=headers,
data=data,
impersonate="chrome",
verify=False,
proxies=proxy,
)
if (
response.ok
and response.json()
and response.json().get("body", {}).get("errorCode") == "601"
):
return self.get_current_order(retry_count - 1)
def submit_order(self):
body = {
"deviceUUID": "6279258698405299736",
"appId": "wxae3e8056daea8727",
"tenantCode": "jgm",
"bizModelCode": "3",
"bizModeClientType": "M",
"token": "3852b12f8c4d869b7ed3e2b3c68c9436",
"externalLoginType": 1,
"appVersion": "2.5.2",
"referer": "https://item.m.jd.com/",
"checkPayPassport": False,
"checkpwdV2": False,
"isEncryptionMobile": True,
"outStockVendorIdList": [12514479],
"mainSkuIdList": [int(self.sku_id)],
"balanceDataServerSkuVOList": [
{
"id": int(self.sku_id),
"jdPrice": "499.00",
"buyNum": 1,
"firstCategoryId": 4938,
"secondCategoryId": 11760,
"thirdCategoryId": 22501,
"promoId": 305236894242,
"venderId": 12514479,
"type": 1,
}
],
"balanceTableWareVoList": [{}],
"cashierDeskBackUrl": f"https://trade.m.jd.com/buy/done.shtml?dealId=%24%7BorderId%7D&sceneval=2&fromPay=1&ptag=7039.27.14&gift_skuid={self.sku_id}&gift_venderid=12514479&gift_cid=22501&normal=1",
"payType": "4",
"subPayType": "",
"licenseList": [],
"balanceCommonOrderForm": {
"action": 1,
"overseaMerge": False,
"international": False,
"netBuySourceType": 0,
"appVersion": "2.5.2",
"supportTransport": False,
"tradeShort": False,
"useChannelFlag": "10000000",
"hasSingleOrderGovSubsidy": False,
"unionPayCouponEffective": False,
"oldAgeStyle": False,
"balanceRefreshByAction": "1",
"supportUserPrivacy": True,
"userPrivacyChecked": True,
},
"balanceExt": {
"baiDuJumpButtonSwitch": False,
"bubbleTips": {"enable": True, "num": 1, "time": 3, "useNum": 0},
"cashierDeskEnable": True,
"cashierPayFlag": "0",
"checkIdInfo": False,
"couponRedText": "",
"hasBackupStorage": False,
"hasCwbg": False,
"hasFreightInsurance": False,
"isInternational": False,
"isSupportTranport": False,
"jdCombineType": 0,
"knowledgeServiceStatus": 0,
"noAddressMatchDegradeSwitch": True,
"overseaMerge": False,
"plusFloorStr": '{"addressType":0,"area":"19-1601-3633-63243","freightInfoList":[],"invoiceType":1,"payWay":4,"plusPromotionRequest":{"couponTotalAmount":0.00,"fareCouponTotalAmount":0.00,"officialDiscountTotalDiscount":0.00,"promotionReduceTotalAmount":0.00,"promotionTotalPrice":499.00,"redBagTotalAmount":0.00,"totalCashGiftDiscount":0,"totalCashGiftNew":0,"totalCashGiftOld":0,"totalParallelDiscount":0.00},"plusStatus":"203","requestConditionList":[105,106,305,529,523,521,522,351],"skuInfoRequestList":[{"col_type":"0","companyType":0,"factoryShip":0,"firstCategory":4938,"isCanUseDongCoupon":1,"isCanUseJingCoupon":1,"isJxzy":0,"isLoc":1,"isOverseaPurchase":0,"jdPrice":"499.00","number":"1","secondCategory":11760,"shopId":12204479,"skuExtension":{"fields":{"fare":"2849262","saler":"","saleAttributes":"[{\\"saleName\\":\\"颜色\\",\\"dim\\":1},{\\"saleName\\":\\"尺码\\",\\"dim\\":2}]","maxBuyNum":"19","is7ToReturn":"0","features":"consumptionVAT:0,inputVAT:0,outputVAT:0","vender_attribute":"","isHitGovSubsidy":"0","selectedGBCZGovConsumerCoupon":"false","yn":"1","vender_name":"易点生活电子商务有限公司","product_id":"10028314345641","sale_atts":"","warranty":"","timeliness_id":"0","sku_name":"【谨防刷单诈骗】沃尔玛大卖场卡500元 官方卡密 卡号8688 不支持山姆 本店不刷单 谨防诈骗 不支持退换","supply_unit":"","model":"","shopId":"12204479","cn_sku_name":"【谨防刷单诈骗】沃尔玛大卖场卡500元 官方卡密 卡号8688 不支持山姆 本店不刷单 谨防诈骗 不支持退换","height":"0","MN":"19","first_buyer_post":"4541","unLimit_cid":"22501","isCanVAT":"0","pay_first":"1","tsfw":"p8,","ms":"0","weight":"0","sku_id":"%s","tax":"consumptionVAT:0,inputVAT:0,outputVAT:0","shop_name":"沃尔玛礼品卡专卖店","product_name":"【谨防刷单诈骗】沃尔玛大卖场卡500元 官方卡密 卡号8688 不支持山姆","brand_id":"250870","shop_id":"12204479","size":"不支持退换","brandId":"250870","col_type":"0","color":"本店不刷单 谨防诈骗","cn_color":"本店不刷单 谨防诈骗","isLOC":"2","img_dfs_url":"jfs/t1/225028/24/16896/94540/6667fb55Fad484540/4069fd317318e9da.jpg","outer_id":"DSwemmck0500","platform":"1","vender_id":"12514479","jc_buyer":"","category_id":"22501","fxg":"0","isQdh":"0","venderAttribute":"","sku_tag":"0","category_id1":"4938","sku_mark":"0","template_type_attributes":"[{\\"attrid\\":\\"1001050620\\",\\"dim\\":1,\\"saleName\\":\\"颜色\\",\\"saleValue\\":\\"本店不刷单 谨防诈骗\\",\\"sequenceNo\\":1,\\"valueId\\":\\"2916524754\\"},{\\"attrid\\":\\"1001051741\\",\\"dim\\":2,\\"saleName\\":\\"尺码\\",\\"saleValue\\":\\"不支持退换\\",\\"sequenceNo\\":1,\\"valueId\\":\\"3924738280\\"}]","category_id2":"11760","sale_template_id":"POP_MODEL","jc_saler":"","day_limited_sales":"19","length":"0","locGroupId":"-100","vender_col_type":"0","sku_status":"1","allnum":"0","containsGovConsumerCoupon":"false","width":"0"},"fresh":false,"num":1,"parallelPromo":false,"samShop":false,"selfSupport":false,"shoppingMalls":false,"skuPriceAfterSinglePromotion":"499.00","skuUuid":"1012_F2t2t3H1499005262095200256","spuId":"-1","storeId":"-1","vendor":"12514479","vendorType":2},"skuId":%s,"skuMark":"","spuId":"-1","thirdCategory":22501,"uuid":"1012_F2t2t3H1499005262095200256","venderId":12514479,"vender_bizid":",popsop,","vender_col_type":"0","vendorType":0}],"totalPrice":"499.00"}'
% (self.sku_id, self.sku_id),
"selectedCouponNum": 0,
"sellLargeDay": "7",
"supportPaymentSkuList": [self.sku_id],
"useBestCoupon": True,
},
"actualPayment": "499.00",
"sendGift": {},
"dsList": [
{"paramName": "report_time", "paramVal": ""},
{"paramName": "deal_id", "paramVal": ""},
{"paramName": "buyer_uin"},
{"paramName": "pin", "paramVal": ""},
{
"paramName": "cookie_pprd_p",
"paramVal": "UUID.17512753463451844059233-LOGID.1751857899901.1014192400",
},
{
"paramName": "cookie_pprd_s",
"paramVal": "76161171.17512753463451844059233.1751275346.1751856681.1751857862.11",
},
{"paramName": "cookie_pprd_t"},
{"paramName": "ip", "paramVal": ""},
{"paramName": "visitkey", "paramVal": "6279258698405299736"},
{"paramName": "gen_entrance", "paramVal": ""},
{"paramName": "deal_src", "paramVal": "7"},
{"paramName": "item_type", "paramVal": "1"},
{"paramName": "fav_unixtime", "paramVal": ""},
{"paramName": "pay_type", "paramVal": "0"},
{"paramName": "ab_test", "paramVal": ""},
{"paramName": "serilize_type", "paramVal": "0"},
{"paramName": "property1", "paramVal": "0"},
{"paramName": "property2", "paramVal": "0"},
{"paramName": "property3", "paramVal": "0"},
{"paramName": "property4", "paramVal": "0"},
{"paramName": "seller_uin", "paramVal": "0"},
{"paramName": "pp_item_id", "paramVal": ""},
{"paramName": "openid"},
{"paramName": "orderprice", "paramVal": ""},
{"paramName": "actiontype", "paramVal": ""},
{"paramName": "extinfo", "paramVal": ""},
{"paramName": "ext1", "paramVal": self.sku_id},
{"paramName": "ext2", "paramVal": ""},
{"paramName": "ext3", "paramVal": ""},
{"paramName": "ext4", "paramVal": ""},
{"paramName": "ext5", "paramVal": ""},
{"paramName": "ext6"},
{"paramName": "ext7", "paramVal": ""},
{"paramName": "ext8", "paramVal": "0"},
{"paramName": "ext9", "paramVal": "0|0|0|0|0||0|0"},
{"paramName": "ext10", "paramVal": "|||"},
{
"paramName": "ext11",
"paramVal": "http://wq.jd.com/wxapp/pages/pay/index/index",
},
{"paramName": "ext12", "paramVal": "1"},
{"paramName": "ext13", "paramVal": ""},
{"paramName": "ext14", "paramVal": ""},
{"paramName": "ext15", "paramVal": ""},
{"paramName": "ext16", "paramVal": ""},
{
"paramName": "ext17",
"paramVal": "76161171%7Ciosapp%7Ct_335139774%7Cappshare%7CCopyURL_shareidde4fa5e467a1fbe323b52ed0fa61777f5ce3e1fe17503293501852_shangxiang_none%7C1751857899902",
},
{"paramName": "ext18"},
{"paramName": "ext19", "paramVal": ""},
{"paramName": "ext20"},
{
"paramName": "fpa",
"paramVal": "7f07f4e1-6ac2-2918-ff9a-18320538d8b2-1743129927",
},
{
"paramName": "fpb",
"paramVal": "BApXSBoHW4fJA8VrxmIXHrE1TcUW-_mloBgFTnghK9xJ1MvE2-4G2",
},
{"paramName": "ext21", "paramVal": ""},
{"paramName": "ext22", "paramVal": ""},
{"paramName": "ext23", "paramVal": "NULL"},
{"paramName": "ext24", "paramVal": "NULL"},
{"paramName": "ext25", "paramVal": "NULL"},
{"paramName": "ext26", "paramVal": "NULL"},
{"paramName": "ext27", "paramVal": "NULL"},
{"paramName": "ext28", "paramVal": "NULL"},
{"paramName": "ext29", "paramVal": "NULL"},
{"paramName": "ext30", "paramVal": "NULL"},
{"paramName": "ext31", "paramVal": "NULL"},
{"paramName": "ext32", "paramVal": "NULL"},
{"paramName": "ext33", "paramVal": "NULL"},
{"paramName": "ext34", "paramVal": "NULL"},
{"paramName": "ext35", "paramVal": "NULL"},
{"paramName": "ext36", "paramVal": "NULL"},
{"paramName": "ext37", "paramVal": "NULL"},
{"paramName": "ext38", "paramVal": "NULL"},
{"paramName": "dt", "paramVal": ""},
],
"govUseGisLocation": False,
"packageStyle": True,
"sceneval": "2",
"balanceDeviceInfo": {"resolution": "2048*1152"},
"balanceId": "5351641558031892481751857904612",
}
encrypt_body = self.sha256_hash(json.dumps(body))
timestamp = f"{int(time.time() * 1000)}"
object_id = "cc85b"
function_id = "balance_submitOrder_m"
h5st = self.get_h5st(timestamp, encrypt_body, object_id, function_id)
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://trade.m.jd.com",
"pragma": "no-cache",
"priority": "u=1, i",
"referer": "https://trade.m.jd.com/",
"sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": self.user_agent,
"x-referer-page": "https://trade.m.jd.com/pay",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies,
}
data = {
"scval": self.sku_id,
"body": json.dumps(body),
"t": timestamp,
"h5st": h5st,
"appid": "m_core",
"client": "Win32",
"clientVersion": "2.5.2",
"d_brand": "",
"d_model": "",
"functionId": "balance_submitOrder_m",
"lang": "zh-CN",
"loginType": "2",
"networkType": "false",
"osVersion": "",
"screen": "1152*2048",
"sdkVersion": "",
"uuid": "17573259367521124301157",
"x-api-eid-token": self.x_token,
"xAPIScval2": "wx",
"xAPIScval3": "unknown",
}
url = "https://api.m.jd.com/client.action"
proxy = self._get_proxy()
response = self._session.post(
url,
headers=headers,
data=data,
verify=False,
proxies=proxy,
)
logger.info(
f"订单号:{self._order_num}app_store提交订单返回{response.json()}"
)
return response.json()
def run(self):
self.x_token, self.eid = self.get_x_token()
# 提交预付款订单
self.get_current_order()
order_res = self.submit_order()
logger.info(
f"订单号:{self._order_num}app_store提交预付款订单返回{order_res}"
)
# 火爆
if order_res.get("body", {}).get("errorCode") == "7201":
return BusinessCode.JD_ORDER_RISK_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(order_res),
}
# 未登录
if order_res.get("body", {}).get("errorCode") == "302":
return BusinessCode.JD_ORDER_CK_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": order_res.get("body", {}).get("errorReason"),
}
# 无货
if order_res.get("body", {}).get("errorCode") == "722":
return BusinessCode.JD_ORDER_STOCK_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": order_res.get("body", {})
.get("submitOrderPromptVO", {})
.get("title"),
}
# 火爆
if order_res.get("body", {}).get("errorCode") == "601":
return BusinessCode.JD_ORDER_RISK_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(order_res),
}
if order_res.get("code") != "0":
return BusinessCode.JD_ORDER_NORMAL_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(order_res),
}
if order_res.get("body", {}).get("errorCode") == "601":
return BusinessCode.JD_ORDER_NORMAL_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(order_res),
}
order_id = order_res.get("body", {}).get("order", {}).get("orderId")
# 获取支付信息
pay_res = self.get_pay_res(order_id)
logger.info(f"订单号:{self._order_num}app_store获取支付信息返回{pay_res}")
if (
order_res.get("body", {}).get("errorCode") == "302"
and order_res.get("body", {}).get("errorReason") == "未登录"
):
return BusinessCode.JD_ORDER_CK_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(order_res),
}
if pay_res.get("code") != "0":
return BusinessCode.JD_ORDER_NORMAL_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(pay_res),
}
pay_id = pay_res["body"]["payId"]
# 获取微信支付信息
return self.refresh_payment_url(pay_id, order_id)
def refresh_payment_url(self, pay_id: str, order_id: int):
logger.info(f"订单号:{pay_id}app_store刷新支付链接 {order_id}")
pay_channel_res = self.plat_pay_channel_res(pay_id)
logger.info(
f"订单号:{self._order_num}app_store请求微信渠道返回{pay_channel_res}"
)
if pay_channel_res.get("code") == "601":
return BusinessCode.JD_ORDER_RISK_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(pay_channel_res),
}
if pay_channel_res.get("code") != "0":
return BusinessCode.JD_ORDER_NORMAL_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(pay_channel_res),
}
wx_pay_res = self.plat_wx_pay_res(pay_id)
logger.info(
f"订单号:{self._order_num}app_store获取微信支付信息返回{wx_pay_res}"
)
if wx_pay_res.get("code") != "0":
return BusinessCode.JD_ORDER_NORMAL_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(wx_pay_res),
}
if wx_pay_res.get("errorCode") == "-1":
return BusinessCode.JD_ORDER_CK_ERR, {
"deeplink": "",
"order_id": "",
"pay_id": "",
"remark": str(wx_pay_res),
}
return BusinessCode.SUCCESS, {
"deeplink": wx_pay_res.get("payInfo", {}).get("mweb_url"),
"order_id": str(order_id),
"pay_id": str(pay_id),
}