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

238 lines
8.5 KiB
Python

import hashlib
import json
import re
import time
import execjs
from curl_cffi import requests
from observability.logging import get_logger_with_trace
logger = get_logger_with_trace(__name__)
class DeleteOrder:
def __init__(self, cookie, order_id):
self.cookie = cookie
self.order_id = order_id
self.timestamp = int(time.time() * 1000)
self.h5st_ctx = self.get_js_obj("h5st4.2.js")
self.ai = "8108f"
self.version = "4.2"
self.p1 = None
self.fp = None
self.tk = None
self.mode = None
self.rd = None
self.sign = None
self.timestamp_sha256 = None
self.t_sha256 = None
self.t_send_data = None
def get_js_obj(self, js):
with open(f"./js/{js}", "r", encoding="utf-8") as file:
js_code = file.read()
return execjs.compile(js_code, cwd="./node_modules")
def encrypt_body(self):
key = "e7c398ffcb2d4824b4d0a703e38eb0bb"
str_to_hash = f"{self.order_id}1sx{self.timestamp}{key}"
enc_str = hashlib.md5(str_to_hash.encode("utf-8")).hexdigest()
body = {
"orderId": self.order_id,
"source": "1",
"channelSource": "sx",
"t": self.timestamp,
"encStr": enc_str,
}
return json.dumps(body)
def cancel_order(self):
body = self.encrypt_body()
url = "https://api.m.jd.com/api"
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://recharge.m.jd.com",
"pragma": "no-cache",
"priority": "u=1, i",
"referer": "https://recharge.m.jd.com/",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-site",
"user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1",
"x-referer-page": "https://recharge.m.jd.com/orderDetail",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookie,
}
data = {
"appid": "tsw-m",
"functionId": "huafei_orderCancel",
"t": f"{self.timestamp}",
"body": body,
"client": "iPhone",
"uuid": "1735283651510338525254",
"osVersion": "16.6",
"screen": "828.0000123381615*1792.0000267028809",
"x-api-eid-token": "jdd03MOMPSVKGBFF6WCM3KNQK34LGPGSCNKB2WACDOVKFUNXQWAWDEVXSHMGQEQLJ6EUKKXZ7ARQA4CPF6EMRRUP5P7ETLEAAAAMUC37NLWQAAAAADDQSI4QCFE6GAAX",
}
response = requests.post(url, headers=headers, data=data)
print(response.text)
def get_fp(self):
self.fp = self.h5st_ctx.call("iC")
def get_env(self):
ctx = self.get_js_obj("h5st4.2.js")
env = ctx.call("expandParams", self.fp, self.p1)
return env
def request_algo(self):
env = self.get_env()
url = "https://cactus.jd.com/request_algo"
params = {"g_ty": "ajax"}
timestamp_ms = int(time.time() * 1000)
data = {
"version": "4.2",
"fp": self.fp,
"appId": "8108f",
"timestamp": timestamp_ms,
"platform": "web",
"expandParams": env,
"fv": "h5_npm_v4.2.0",
}
headers = {
"accept": "application/json",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
"content-type": "application/json",
"origin": "https://txsm-m.jd.com",
"pragma": "no-cache",
"referer": "https://txsm-m.jd.com/",
"sec-ch-ua": '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"',
"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": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
}
data = json.dumps(data, separators=(",", ":"))
response = requests.post(url, headers=headers, params=params, data=data)
return response.json().get("data")
def get_algo(self):
algo_data = self.request_algo()
print(algo_data)
algo = algo_data["result"]["algo"]
self.tk = algo_data["result"]["tk"]
self.mode = re.findall(r"algo\.(.*)\(", algo)[0]
self.rd = re.findall(r"rd='(.*)';", algo)[0]
def get_p1(self):
self.p1 = re.findall(r"pin=(.*);", self.cookie)[0]
def get_tm(self, timestamp):
import datetime
# 将13位时间戳转换为datetime对象
dt = datetime.datetime.fromtimestamp(timestamp / 1000)
year = dt.year
month = str(dt.month).zfill(2)
day = str(dt.day).zfill(2)
hour = str(dt.hour).zfill(2)
minute = str(dt.minute).zfill(2)
second = str(dt.second).zfill(2)
# 将微秒转换为毫秒
microsecond = dt.microsecond // 1000
return f"{year}{month}{day}{hour}{minute}{second}{microsecond}"
def get_oe(self, ts):
oe = self.h5st_ctx.call(
"test", self.mode, self.tk, self.fp, ts, self.ai, self.rd
)
return oe
def get_body(self):
self.t_send_data = int(time.time() * 1000)
self.t_sha256 = int(time.time() * 1000)
self.timestamp_sha256 = self.get_tm(self.t_sha256)
ts = self.timestamp_sha256 + "74"
oe = self.get_oe(ts)
body_hex = self.h5st_ctx.call("encrypt_body", self.order_id, "delete")
t_string = f"{oe}appid:m_core&body:{body_hex}&client:Win32&clientVersion:&functionId:order_recycle_m&t:{self.t_send_data}{oe}"
self.sign = self.h5st_ctx.call("__genSign", t_string)
body = self.h5st_ctx.call("build_params", self.order_id, "delete")
return body
def get_h5st(self):
h5st = f"{self.timestamp_sha256};{self.fp};{self.ai};{self.tk};{self.sign};{self.version};{self.t_sha256}"
return h5st
def request_jd_recycle(self, body, h5st):
headers = {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://trade.m.jd.com",
"pragma": "no-cache",
"referer": "https://trade.m.jd.com/",
"sec-ch-ua": '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"',
"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": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
"x-referer-page": "https://trade.m.jd.com/order/orderlist_jdm.shtml",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookie,
}
url = "https://api.m.jd.com/client.action"
data = {
"t": f"{self.t_send_data}",
"loginType": "2",
"loginWQBiz": "golden-trade",
"appid": "m_core",
"client": "Win32",
"clientVersion": "",
"build": "",
"osVersion": "null",
"screen": "1440*900",
"networkType": "4g",
"partner": "",
"forcebot": "",
"d_brand": "",
"d_model": "",
"lang": "zh-CN",
"scope": "",
"sdkVersion": "",
"openudid": "",
"uuid": "1658065822",
"x-api-eid-token": "jdd03EZ4U2HD6OVXEWMTFQVIXNMASQWBFCYSPX37R7H6QIQDPWYYPIESUHF2YNEGTGXKWHGCH5VEWPMZA4PWPPKX6ZJOKWIAAAAMOR6CEGEIAAAAADWOVM6433SKKPAX",
"functionId": "order_recycle_m",
"body": body,
"h5st": h5st,
}
response = requests.post(url, headers=headers, data=data)
print(response.text)
def recycle_order(self):
self.get_p1()
self.get_fp()
self.get_algo()
body = self.get_body()
h5st = self.get_h5st()
self.request_jd_recycle(body=body, h5st=h5st)
def run(self):
# 取消订单
self.cancel_order()
# 删除订单
self.recycle_order()