- 新增jd模块基础路由,整合app_store和payment子路由 - 实现苹果权益充值接口,支持苹果、携程及沃尔玛多个渠道 - 实现卡号密码查询接口,支持不同类别订单查询 - 新增短信认证相关接口,实现短信验证码发送及短信登录 - 新增商品管理接口,支持SKU详情查询及账号类下单功能 - 新增订单管理接口,实现订单删除功能 - 实现支付相关接口,增加刷新支付参数功能 - 定义完整请求及响应数据模型,确保接口数据规范 - 编写AppStoreSpider类,封装苹果应用内订单处理逻辑 - 引入多种代理池及请求重试机制,增强接口稳定性 - 添加详细日志记录,便于请求追踪与错误排查
238 lines
8.5 KiB
Python
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()
|