Files
kami_jd_ck/babel_channel/spider.py
2025-04-13 19:17:51 +08:00

1111 lines
50 KiB
Python
Raw Permalink 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 base64
import hashlib
import json
import os
import platform
import re
import time
import execjs
import requests
import ddddocr
from logger import get_logger
logger = get_logger()
class GameArea:
@staticmethod
def get_details(cookies, sku_id):
headers = {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "no-cache",
"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/cardSettlement",
"x-rp-client": "h5_1.0.0",
"cookie": cookies
}
params = {
"appid": "tsw-m",
"functionId": "getGameDetailBySkuId",
"t": f"{int(time.time() * 1000)}",
"body": "{\"skuId\":\"%s\",\"appKey\":\"apple\",\"source\":41}" % sku_id,
"client": "iPhone",
"uuid": "1731377463937218663686",
"osVersion": "16.6",
"screen": "1170.000046491623*2532.0001006126404",
# "h5st": "20241112145441915;l055lflh9lr1i4k8;8e94a;tk03w92d21bda18nCxAp7H5xKn6xhgPjl2DU239CUZMhS1OwR9VyMZc5hQGRyFwDwYV8pE9DyQ7wpjquSVNSz5Kj3B5v;cbe697aecf5adbdd1ee2ddb4a1943f24;4.9;1731394481915;pjbMhjpdAaYR6jkQyLlQF6Ve2roQJrJdJrESJrpjh7Jf6rJdJz1TIipjLDrgJTISJSVS6PYd1jof0bFTKqIfJqoe1rYTImFf1LofzfITJrJdJrEa-OFTGOEjLrJp-jJS5ToeyT4e6nodGSld4j4TJeYe7PYS4bVT6T1fFSYTyjpjxj5PKSEQKeFjLrJp-jJf9HIg3T0UG6VRFuWeDipjxjJOJrpjh7JjbKUXzfUSnWYQfe2XJrJdJ31QHyVT5ipjLDrgJj4f9G1WJrJdJTlPJrpjh7ZMLrJp7rJdJLYOJipjLrpjh7JjJrJdJPYOJipjLrpjh7peLDIj1XETJrpjLrJp-rojxjZe2iFjLrpjLDrg7rJdJbYOJipjLrpjh7Je2rJdJfYOJipjLrpjh7Jf_rJdJjYOJipjLrpjh7Jj2zZf9rIjLDIj6XETJrpjLrJp-rojxj5R0ipjLrpjh7pfLDIj46FjLrpjLDrg7rJdJ7FjLrpjLDrg7rJdJb1OJrpjLrJpwqJdJbFQGakNGipjLDrguqpjhjZVl6VS5C2OqmHXi_1UHCFjLDIj6rEjLrpjLD7NLDIj7qEjLrJp-jpVLf2YLfVTeqZSAGlQLT4U1nojYunjGy1QDqWRLXmXoq5dGy1QDqWRJrJdJnVO4ipjLD7N;949f348da7bbb53fcee1f3a592db0ad3",
"x-api-eid-token": "jdd03MOMPSVKGBFF6WCM3KNQK34LGPGSCNKB2WACDOVKFUNXQWAWDEVXSHMGQEQLJ6EUKKXZ7ARQA4CPF6EMRRUP5P7ETLEAAAAMTD4S5X6IAAAAADZXKZJY7RRZL4AX"
}
jd_api = "https://api.m.jd.com/api"
response = requests.get(jd_api, headers=headers, params=params)
return response.json()
class AppStoreSpider:
SKU_MAP = {
"10.00": 10022039398507,
"50.00": 11170365589,
"100.00": 11183343342,
"200.00": 11183368356,
"500.00": 11183445154,
"1000.00": 10066407336810,
}
def __init__(
self,
cookies,
order_num,
face_price=None
):
self.order_num = order_num
self.cookies = cookies
self.face_price = face_price
self.user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0"
self.md5_key = "e7c398ffcb2d4824b4d0a703e38eb0bb"
self.time_stamp = int(time.time() * 1000)
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.headers = {
"content-type": "application/x-www-form-urlencoded",
"cookie": self.cookies,
"origin": "https://txsm-m.jd.com",
"referer": "https://txsm-m.jd.com/",
"user-agent": self.user_agent
}
self.current_os = platform.system()
self.js = None
self.init_js()
def init_js(self):
if self.current_os == "Linux":
js_path = r"/app/js"
node_modules_path = r"/app/node_modules"
else:
js_path = "js"
node_modules_path = "./node_modules"
captcha_path = os.path.join(js_path, 'decrypt_des.js')
self.js = execjs.compile(
open(captcha_path, encoding='utf8').read(),
cwd=node_modules_path
)
def format_number(self, number):
if not number:
number = 0
number = float(number)
formatted_number = "{:.2f}".format(number)
return formatted_number
def get_s(self):
use_bean = 0
buy_num = 1
face_price = self.face_price
type = 1
brand_id = 999440
eid = "QXVELAP4INIRMWVGXUQZWOOO46TSRY6NV7IRIZPZVYRRDA3JSYOXRK34SAMFD5JCMHYTABOYJXTUZOTOR5ATVDLMSM"
pay_mode = 0
coupon_ids = ""
sku_id = self.SKU_MAP[self.format_number(self.face_price)]
total_price = self.format_number(self.face_price)
order_source = 2
order_source_type = 2
s = f"{use_bean}{buy_num}{face_price}{type}{brand_id}{eid}{pay_mode}{coupon_ids}{sku_id}{total_price}{order_source}{order_source_type}"
return s
def get_u(self):
u = f"{self.time_stamp}{self.md5_key}"
return u
def get_enc_str(self):
s = self.get_s()
u = self.get_u()
_str = f"{s}{u}"
enc_str = hashlib.md5(_str.encode()).hexdigest()
return enc_str
def get_body(self, enc_str):
item = {
"useBean": 0,
"buyNum": 1,
"facePrice": self.face_price,
"type": 1,
"brandId": 999440,
"eid": "QXVELAP4INIRMWVGXUQZWOOO46TSRY6NV7IRIZPZVYRRDA3JSYOXRK34SAMFD5JCMHYTABOYJXTUZOTOR5ATVDLMSM",
"payMode": "0",
"couponIds": "",
"skuId": self.SKU_MAP[self.format_number(self.face_price)],
"totalPrice": self.format_number(self.face_price),
"orderSource": 2,
"orderSourceType": 2,
"t": self.time_stamp,
"channelSource": "txzs",
"encStr": enc_str,
"babelChannel": "ttt35"
}
json_string = json.dumps(item)
encrypted_message = base64.b64encode(json_string.encode('utf-8')).decode('utf-8').rstrip('=')
return encrypted_message
def submit_order(self, body):
data = {
"appid": "txsm-m",
"client": "iPhone",
"functionId": "appstore_order_submit_new",
"uuid": "1717649136178703924319",
"osVersion": "16.6",
"screen": "1170.000046491623*2532.0001006126404",
"t": self.time_stamp,
# "h5st": "20241028200339289;8fvel000191i1i93;583cc;tk03w8c3f1be418nQa6EtyNN1i0efjq2_3Af0KKS2OvDxI_UCy_hC2FuA-nJZtpgK3VtOi--6wEtccGDVuRfa3EpowsE;0b371d677eb468de9653cda6840a8bfc;4.9;1730117019289;pjbMhj5fyHVfCmYd6rof77VS1SldJrJdJrESJrpjh7Jf6rJdJz1TIipjLDrgJTISJSVS6PYd1jof0bFTKqIfJqoe1rYTImFf1LofzfITJrJdJrEa-OFTGOEjLrJp-jJS5ToeyT4e6nodGSld4j4TJeYe7PYS4bVT6T1fFSYTyjpjxj5PKSEQKeFjLrJp-jZf9HIg3T0UG6VRFuWeDipjxjJOJrpjh7JjRiWPRG2ZTSVSyjIVJrJdJ31QHyVT5ipjLDrgJj4f9G1WJrJdJTlPJrpjh7ZMLrJp7rJdJLYOJipjLrpjh7JjJrJdJPYOJipjLrpjh7Jf5rJdJTYOJipjLrpjh7pfLDIj2XETJrpjLrJp-rojxjpe2iFjLrpjLDrg6bojxj5f2iFjLrpjLDrg63pjxjJf2iFjLrpjLDrgJbIg6zpfJrJdJnYOJipjLrpjh7pfLDIjAOEjLrpjLDrg7rJdJfkQJrpjLrJp-rojxjpQJrpjLrJp-rojxjpS0ipjLrpjh-kjxjpS9WlOzWFjLrJp-3kjLDLjSSnQGiEV0mXbZG3RMaFRJrJdJjoPJrpjLrJp-jZVl6VS5C2OqmHXi_1UHCFjLDIj6rEjLrpjLD7NLDIj7qEjLrJp-jpVLf2YLfVTeqZSAGlQLT4U1nojYunjGy1QDqWRLXmXoq5dGy1QDqWRJrJdJnVO4ipjLD7N;5fbb8b3774fd7e25bc3742f4156c87d8",
"loginType": "2",
"x-api-eid-token": "jdd03MOMPSVKGBFF6WCM3KNQK34LGPGSCNKB2WACDOVKFUNXQWAWDEVXSHMGQEQLJ6EUKKXZ7ARQA4CPF6EMRRUP5P7ETLEAAAAMS2MA4W7AAAAAADYFXHMH6GITT4EX",
"body": body
}
response = requests.post(
url=self.submit_order_url,
headers=self.headers,
data=data
)
return response.json()
def get_ticket_res(self):
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": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
}
url = "http://127.0.0.1:99/api/TX?aid=2093769752&host=https://t.captcha.qq.com&ip="
response = requests.get(url, headers=headers, verify=False)
return response.json()
def decrypt_card_info(self, message):
key = "2E1ZMAF88CCE5EBE551FR3E9AA6FF322"
card_info = self.js.call("decryptDes", message, key)
card_info = json.loads(card_info)
return card_info[0]
def get_card_res(self, 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",
"content-type": "application/x-www-form-urlencoded",
"origin": "https://recharge.m.jd.com",
"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": self.user_agent,
"x-referer-page": "https://recharge.m.jd.com/orderDetail",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies
}
data = {
"appid": "tsw-m",
"functionId": "getGPOrderDetail",
"t": self.time_stamp,
"body": "{\"appKey\":\"apple\",\"source\":41,\"orderId\":\"%s\",\"version\":\"1.10\",\"rechargeversion\":\"12.8\",\"moduleName\":\"JDReactVirtualRecharge\",\"apiVersion\":\"new\"}" % (
order_id),
"client": "iPhone",
"uuid": "1717649136178703924319",
"osVersion": "16.6",
"screen": "1170.000046491623*2532.0001006126404",
"x-api-eid-token": "jdd03MOMPSVKGBFF6WCM3KNQK34LGPGSCNKB2WACDOVKFUNXQWAWDEVXSHMGQEQLJ6EUKKXZ7ARQA4CPF6EMRRUP5P7ETLEAAAAMS2MA4W7AAAAAADYFXHMH6GITT4EX"
}
response = requests.post(self.jd_api, headers=headers, data=data)
return response.json()
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": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
"x-referer-page": "https://trade.m.jd.com/order/orderlist_jdm.shtml",
"x-rp-client": "h5_1.0.0",
"cookie": self.cookies
}
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": "jdd03PBZHV4O4RF5SAA7QGYPZEPRPAYOCCF3WTUQYMWEFASLCJNYX2HWO7C35L5TYQUL66FGXVVMXDWKTBEEE24LW42XEWMAAAAMSWN4KSOAAAAAACY2DMACM6CADIQX",
"functionId": "pay_info_m",
"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),
"h5st": "20241025142424843;miziz93wtzzzzgh5;9b070;tk03wa71a1ca518nFJq8OPxuvCEgJZrrjKB2ONH5SManNhGNGW2uSVhhFFx0bCkdZKQw0OH2FyaleaKKyybvEMaCxrXo;2a3300f2f9a346ca68af9fc8cccb393097d0fa2cd49da944c008aa90ce57490e;4.2;1729837464843;0aeefaf52c5a7fa31a1ad5e06c8551fda85ad5f4536e7e4aa639c27c742cb035bc404e042da71a6faa85368294121c998970b119166b80123d8bdc72009e29dac35c297c81be0d1b37dbbc13d4b1aad4964ea0ad73c8ffb64f0db8be2ca213a9654d5e12b62f9391d200f62c0d4c7b1f3a7a55a1522198915f6bc11bfe4a8737e68502fbb62d9c2f817c7e93c036750464be6c7061419b46e3e74149948c9b8b339efa0f072f393ee70d5d03450a479d0d88aa3d57ec6402effae31c81c82a9d4d094a606e51aed4cad77a8457f3c31b29ff4380e14c580fdc068ad0d134b77e1a5928debd815d06cc53c4c267935e3509ce7b17f119c71a038eee0aacaa3ccf98f635a23c272662788e7e04454c5327f46b18904e93ca95463fcb7617b8a4481d5409a29b0afdd1a59513f34184fc6a"
}
response = requests.get(self.action_url, headers=headers, params=params)
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"
}
data = {
"body": "{\"appId\":\"m_D1vmUq63\",\"payId\":\"%s\",\"source\":\"mcashier\",\"origin\":\"h5\",\"mcashierTraceId\":1729842386189}" % (
pay_id),
"x-api-eid-token": "jdd03PBZHV4O4RF5SAA7QGYPZEPRPAYOCCF3WTUQYMWEFASLCJNYX2HWO7C35L5TYQUL66FGXVVMXDWKTBEEE24LW42XEWMAAAAMSYKR67JYAAAAACKNZVOOO4PUVKQX",
"h5st": "20241025154626341;0587023779148689;303a7;tk03w7da11b8b18nOQ6HZGNLj6DdtLQBS695YHMu7RyONolcwWCRc8ihMUs5ITCem6HIGhdYo_DpJ62yYLkdrxIBxE0N;ab8a935407baae929b0d3e267f67693f9c00a5d876ad149c10e904371f87726f;3.1;1729842386341;24c9ee85e67cf80746dd82817ecbeafc7a829b35c7f446a4c7d476cc9faa1d8834a93323ad7bce9bef1bba682b93d2e3694e425ff68d304875c1ae9e2ae398cfd94e4ff03cd3bdd9f0f600a0d75c92d537baaa944d39072a92db7dc20c99e7f80889e289e78a1f8f93c57f8471890c464b78b61e9b3bbffea712e6d6c671ad12"
}
response = requests.post(self.action_url, headers=headers, params=params, data=data)
return response.json()
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": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
"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"
}
data = {
"body": "{\"appId\":\"m_D1vmUq63\",\"payId\":\"%s\",\"eid\":\"PBZHV4O4RF5SAA7QGYPZEPRPAYOCCF3WTUQYMWEFASLCJNYX2HWO7C35L5TYQUL66FGXVVMXDWKTBEEE24LW42XEWM\",\"source\":\"mcashier\",\"origin\":\"h5\",\"mcashierTraceId\":1729837716957}" % (
pay_id),
"x-api-eid-token": "jdd03PBZHV4O4RF5SAA7QGYPZEPRPAYOCCF3WTUQYMWEFASLCJNYX2HWO7C35L5TYQUL66FGXVVMXDWKTBEEE24LW42XEWMAAAAMSYJMLE3IAAAAAC5OTMMGGUM5SYIX",
# "h5st": "20241025142845015;0587023779148689;303a7;tk03w7da11b8b18nOQ6HZGNLj6DdtLQBS695YHMu7RyONolcwWCRc8ihMUs5ITCem6HIGhdYo_DpJ62yYLkdrxIBxE0N;48aee025d65fab059f98c546832f7a1d7bca99dba6bc0df9bd6328b9817cf394;3.1;1729837725015;24c9ee85e67cf80746dd82817ecbeafc7a829b35c7f446a4c7d476cc9faa1d8834a93323ad7bce9bef1bba682b93d2e3694e425ff68d304875c1ae9e2ae398cfd94e4ff03cd3bdd9f0f600a0d75c92d537baaa944d39072a92db7dc20c99e7f80889e289e78a1f8f93c57f8471890c464b78b61e9b3bbffea712e6d6c671ad12"
}
response = requests.post(self.action_url, headers=headers, params=params, data=data)
return response.json()
def get_deep_link_res(self, mweb_url):
headers = {
"Host": "wx.tenpay.com",
"sec-ch-ua-platform": "\"Windows\"",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
"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
}
response = requests.get(self.check_captcha_url, headers=headers, params=params)
return response.json()
def get_card_secret(self, jd_order_num):
card_res = self.get_card_res(jd_order_num)
logger.info(f"获取卡密信息返回:{card_res}")
card_info = card_res.get("result").get("cardInfos")
if card_res.get("code") != "0" or not card_info:
return 110, card_res
card_info = self.decrypt_card_info(card_info)
return 100, card_info
def run(self):
# 获取加密参数
try:
enc_str = self.get_enc_str()
except KeyError as e:
return 110, {"msg": "充值面值有误"}
# 获取请求body
body = self.get_body(enc_str)
# 提交预付款订单
order_res = self.submit_order(body)
# order_res = {'code': 200, 'msg': '成功', 'dispCode': '200', 'dispPhone': '', 'data': '304550362538', 'viewMsg': ''}
logger.info(f"订单号:{self.order_num}app_store提交预付款订单返回{order_res}")
if order_res.get("code") != 200:
return 110, order_res
order_id = order_res["data"]
# 获取支付信息
pay_res = self.get_pay_res(order_id)
logger.info(f"订单号:{self.order_num}app_store获取支付信息返回{pay_res}")
if pay_res.get("code") != "0":
return 110, pay_res
pay_id = pay_res["body"]["payId"]
# 获取微信支付信息
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") != "0":
return 110, 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 110, wx_pay_res
if wx_pay_res.get("errorCode") == "-1":
wx_pay_res["order_id"] = order_id
wx_pay_res["pay_id"] = pay_id
wx_pay_res["face_price"] = self.face_price
return 110, wx_pay_res
mweb_url = wx_pay_res["payInfo"]["mweb_url"]
# 获取支付链接信息
deep_link_res = self.get_deep_link_res(mweb_url)
logger.info(f"订单号:{self.order_num}app_store获取支付链接deep_link信息返回{deep_link_res}")
if deep_link_res.get("retcode") != 1:
return 110, deep_link_res
return 100, {
"deeplink": deep_link_res["deeplink"],
"order_id": pay_channel_res["orderId"],
"pay_id": pay_id,
"face_price": self.face_price,
}
class GoodsAppleCard(AppStoreSpider):
def __init__(
self,
cookies,
order_num,
brand_id,
face_price,
sku_id,
username,
game_srv=None,
game_area=None,
recharge_type=1
):
super(GoodsAppleCard, self).__init__(
cookies,
order_num,
face_price=face_price
)
self.sku_id = sku_id
self.brand_id = brand_id
self.username = username
self.game_srv = game_srv
self.game_area = game_area
self.face_price = face_price
self.recharge_type = recharge_type
def encrypt_username(self, username):
key = "2E1ZMAF88CCE5EBE551FR3E9AA6FF322"
username = self.js.call("encryptDes", username, key)
return username
def submit_gp_order(self):
headers = {
"Host": "api.m.jd.com",
"pragma": "no-cache",
"cache-control": "no-cache",
"user-agent": self.user_agent,
"accept": "application/json, text/plain, */*",
"x-referer-page": "https://recharge.m.jd.com/cardSettlement",
"content-type": "application/x-www-form-urlencoded",
"x-rp-client": "h5_1.0.0",
"origin": "https://recharge.m.jd.com",
"sec-fetch-site": "same-site",
"sec-fetch-mode": "cors",
"sec-fetch-dest": "empty",
"referer": "https://recharge.m.jd.com/",
"accept-language": "zh-CN,zh;q=0.9",
"priority": "u=1, i",
"cookie": self.cookies
}
username = self.encrypt_username(self.username)
data = {}
if self.recharge_type == 1:
data = {
"appid": "tsw-m",
"functionId": "submitGPOrder",
"t": f"{self.time_stamp}",
"body": "{\"skuId\":\"%s\",\"brandId\":\"%s\",\"type\":2,\"buyNum\":1,\"payMode\":\"0\",\"totalPrice\":\"%s\",\"username\":\"%s\",\"appKey\":\"apple\",\"source\":41,\"version\":\"1.10\",\"orderSource\":41}" % (
self.sku_id, self.brand_id, self.face_price, username
),
"client": "iPhone",
"uuid": "1731377463937218663686",
"osVersion": "16.6",
"screen": "1170.000046491623*2532.0001006126404",
# "h5st": "20241112141707038;l055lflh9lr1i4k8;8e94a;tk03w92d21bda18nCxAp7H5xKn6xhgPjl2DU239CUZMhS1OwR9VyMZc5hQGRyFwDwYV8pE9DyQ7wpjquSVNSz5Kj3B5v;8effdf684f396d5889d2bde7e769f965;4.9;1731392227038;pjbMhjpdAaYR6jkQyLlQF6Ve2roQJrJdJrESJrpjh7Jf6rJdJz1TIipjLDrgJTISJSVS6PYd1jof0bFTKqIfJqoe1rYTImFf1LofzfITJrJdJrEa-OFTGOEjLrJp-jJS5ToeyT4e6nodGSld4j4TJeYe7PYS4bVT6T1fFSYTyjpjxj5PKSEQKeFjLrJp-jJf9HIg3T0UG6VRFuWeDipjxjJOJrpjh7JjxOYRhiFPyK3Z2f2XJrJdJ31QHyVT5ipjLDrgJj4f9G1WJrJdJTlPJrpjh7ZMLrJp7rJdJLYOJipjLrpjh7JjJrJdJPYOJipjLrpjh7ZeLDIj1XETJrpjLrJp-rojxjZe2iFjLrpjLDrg7rJdJbYOJipjLrpjh75e2rJdJfYOJipjLrpjh7Jf_rJdJjYOJipjLrpjh7Jj2zZf9rIjLDIj6XETJrpjLrJp-rojxj5R0ipjLrpjh7pfLDIj46FjLrpjLDrg7rJdJ7FjLrpjLDrg7rJdJb1OJrpjLrJpwqJdJbFQGakNGipjLDrguqpjhjZVl6VS5C2OqmHXi_1UHCFjLDIj6rEjLrpjLD7NLDIj7qEjLrJp-jpVLf2YLfVTeqZSAGlQLT4U1nojYunjGy1QDqWRLXmXoq5dGy1QDqWRJrJdJnVO4ipjLD7N;204790ef3f0380d87102b52131fd50d7",
"x-api-eid-token": "jdd03MOMPSVKGBFF6WCM3KNQK34LGPGSCNKB2WACDOVKFUNXQWAWDEVXSHMGQEQLJ6EUKKXZ7ARQA4CPF6EMRRUP5P7ETLEAAAAMTDYRX6SIAAAAACB66T3PYQZLCEEX"
}
if self.recharge_type == 2:
data = {
"appid": "tsw-m",
"functionId": "submitGPOrder",
"t": f"{self.time_stamp}",
"body": "{\"skuId\":\"%s\",\"brandId\":\"%s\",\"type\":2,\"buyNum\":1,\"payMode\":\"0\",\"totalPrice\":\"%s\",\"gamesrv\":\"%s\",\"gamearea\":\"%s\",\"username\":\"%s\",\"appKey\":\"apple\",\"source\":41,\"version\":\"1.10\",\"orderSource\":41}" % (
self.sku_id, self.brand_id, self.face_price, self.game_srv, self.game_area, username
),
"client": "iPhone",
"uuid": "1731377463937218663686",
"osVersion": "16.6",
"screen": "1170.000046491623*2532.0001006126404",
# "h5st": "20241112172954252;l055lflh9lr1i4k8;8e94a;tk03w92d21bda18nCxAp7H5xKn6xhgPjl2DU239CUZMhS1OwR9VyMZc5hQGRyFwDwYV8pE9DyQ7wpjquSVNSz5Kj3B5v;dcf2dab0edd6fadd62550cc4ca5e28c4;4.9;1731403794252;pjbMhjpdAaYR6jkQyLlQF6Ve2roQJrJdJrESJrpjh7Jf6rJdJz1TIipjLDrgJTISJSVS6PYd1jof0bFTKqIfJqoe1rYTImFf1LofzfITJrJdJrEa-OFTGOEjLrJp-jJS5ToeyT4e6nodGSld4j4TJeYe7PYS4bVT6T1fFSYTyjpjxj5PKSEQKeFjLrJp-jJf9HIg3T0UG6VRFuWeDipjxjJOJrpjh7JjWW1f5LnageHNqSEOJrJdJ31QHyVT5ipjLDrgJj4f9G1WJrJdJTlPJrpjh7ZMLrJp7rJdJLYOJipjLrpjh7JjJrJdJPYOJipjLrpjh7ZeLDIj1XETJrpjLrJp-rojxjZe2iFjLrpjLDrg7rJdJbYOJipjLrpjh75e2rJdJfYOJipjLrpjh7Jf_rJdJjYOJipjLrpjh7Jj2zZf9rIjLDIj6XETJrpjLrJp-rojxj5R0ipjLrpjh7pfLDIj46FjLrpjLDrg7rJdJ7FjLrpjLDrg7rJdJb1OJrpjLrJpwqJdJbFQGakNGipjLDrguqpjhjZVl6VS5C2OqmHXi_1UHCFjLDIj6rEjLrpjLD7NLDIj7qEjLrJp-jpVLf2YLfVTeqZSAGlQLT4U1nojYunjGy1QDqWRLXmXoq5dGy1QDqWRJrJdJnVO4ipjLD7N;651ee3204b43d0d514092fa61f5629f1",
"x-api-eid-token": "jdd03MOMPSVKGBFF6WCM3KNQK34LGPGSCNKB2WACDOVKFUNXQWAWDEVXSHMGQEQLJ6EUKKXZ7ARQA4CPF6EMRRUP5P7ETLEAAAAMTD6ZVZVQAAAAADSCNVUR4IR7W54X"
}
response = requests.post(self.jd_api, headers=headers, data=data)
return response.json()
def run(self):
# 提交预付款订单
gp_order_res = self.submit_gp_order()
# gp_order_res = {'result': {'orderId': 304636667875, 'paySuccessUrl': ''}, 'code': '0'}
logger.info(f"订单号:{self.order_num},商品下单提交预付款订单返回:{gp_order_res}")
if gp_order_res.get("code") != '0':
return 110, gp_order_res
order_id = gp_order_res["result"]["orderId"]
# 获取支付信息
pay_res = self.get_pay_res(order_id)
logger.info(f"订单号:{self.order_num},商品下单获取支付信息返回:{pay_res}")
if pay_res.get("code") != "0":
return 110, pay_res
pay_id = pay_res["body"]["payId"]
# 获取微信支付信息
pay_channel_res = self.plat_pay_channel_res(pay_id)
logger.info(f"订单号:{self.order_num},商品下单请求微信渠道返回:{pay_channel_res}")
if pay_channel_res.get("code") != "0":
return 110, pay_channel_res
wx_pay_res = self.plat_wx_pay_res(pay_id)
logger.info(f"订单号:{self.order_num},商品下单获取微信支付信息返回:{wx_pay_res}")
if wx_pay_res.get("code") != "0":
return 110, wx_pay_res
if wx_pay_res.get("errorCode") == "-1":
wx_pay_res["order_id"] = order_id
wx_pay_res["pay_id"] = pay_id
wx_pay_res["face_price"] = self.face_price
return 110, wx_pay_res
mweb_url = wx_pay_res["payInfo"]["mweb_url"]
# 获取支付链接信息
deep_link_res = self.get_deep_link_res(mweb_url)
logger.info(f"订单号:{self.order_num}商品下单获取支付链接deep_link信息返回{deep_link_res}")
if deep_link_res.get("retcode") != 1:
return 110, deep_link_res
return 100, {
"deeplink": deep_link_res["deeplink"],
"order_id": pay_channel_res["orderId"],
"pay_id": pay_id,
"face_price": self.face_price
}
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()
class LoginSpider:
def __init__(self, phone):
self.phone = phone
self.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://plogin.m.jd.com',
'pragma': 'no-cache',
'priority': 'u=1, i',
'referer': 'https://plogin.m.jd.com/login/login?appid=300&returnurl=https%3A%2F%2Fm.jd.com%2F&source=wq_passport',
'sec-ch-ua': '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0',
}
self.cookies = {}
self.current_os = platform.system()
self.js_path = None
self.node_modules_path = None
self.load_directory()
self.slide_ctw = self.init_verify_data_js()
self.user_ctw = self.init_user_encrypt_js()
self.h5st_ctw = self.init_h5st_js()
self.session = requests.Session()
self.ocr = ddddocr.DdddOcr()
self.eid = ""
self.fp = "26114226dc0c6ee7f1eaf3d4abb30cf2"
self.s_token = None
self.rsa_modulus = None
self.api_st = None
self.api_fp = None
self.img1 = None
self.img2 = None
self.vt = None
self.img = None
self.jd_risk_token_id = None
self.jcap_sid = None
self.ck = None
def load_directory(self):
if self.current_os == "Linux":
self.js_path = r"/app/js"
self.node_modules_path = r"/app/node_modules"
else:
self.js_path = "js"
self.node_modules_path = "./node_modules"
def do_execjs(self, path):
return execjs.compile(
open(path, encoding='utf8').read(),
cwd=self.node_modules_path
)
def init_verify_data_js(self):
js_path = os.path.join(self.js_path, 'modules.js')
return execjs.compile(
open(js_path, encoding='gbk', errors='ignore').read(),
cwd=self.node_modules_path
)
def init_user_encrypt_js(self):
js_path = os.path.join(self.js_path, 'user_encrypt.js')
return execjs.compile(
open(js_path, encoding='gbk', errors='ignore').read(),
cwd=self.node_modules_path
)
def init_h5st_js(self):
js_path = os.path.join(self.js_path, 'h5st-5.0.js')
return execjs.compile(
open(js_path, encoding='gbk', errors='ignore').read(),
cwd=self.node_modules_path
)
def request_jd_risk_token_id(self):
response = self.session.get('https://payrisk.jd.com/m.html', cookies=self.cookies, headers=self.headers)
return response.text
def build_jcapsid_data(self):
return self.user_ctw.call('init', self.phone, self.fp, self.jd_risk_token_id, self.s_token)
def request_jcapsid(self):
url = "https://plogin.m.jd.com/cgi-bin/mm/jcapsid"
data = self.build_jcapsid_data()
response = self.session.post(url, headers=self.headers, data=data)
print(f"request_jcapsid返回{response.text}")
return response.json()
def request_new_login_entrance(self):
url = "https://plogin.m.jd.com/cgi-bin/mm/new_login_entrance"
params = {
"lang": "chs",
"returnurl": "https://my.m.jd.com/",
"risk_jd\\[eid\\]": self.eid,
"risk_jd\\[fp\\]": self.fp
}
response = self.session.get(url, headers=self.headers, cookies=self.cookies, params=params)
print(response.text)
return response.json()
def get_jcap_sid(self):
jcapsid_res = self.request_jcapsid()
self.jcap_sid = jcapsid_res["jcap_sid"]
def get_login_entrance(self):
login_entrance_res = self.request_new_login_entrance()
self.s_token = login_entrance_res["s_token"]
self.rsa_modulus = login_entrance_res["rsa_modulus"]
def build_fp_data(self):
return self.slide_ctw.call('getFp', self.phone, self.jcap_sid)
def request_data_fp(self):
data = self.build_fp_data()
url = "https://jcap.m.jd.com/cgi-bin/api/fp"
response = self.session.post(url, headers=self.headers, data=data)
print(response.text)
return response.json()
def get_api_params(self):
fp_res = self.request_data_fp()
self.api_st = fp_res["st"]
self.api_fp = fp_res["fp"]
def build_captcha_data(self):
return self.slide_ctw.call('getImage', self.phone, self.jcap_sid, self.api_st)
def request_captcha(self):
url = "https://jcap.m.jd.com/cgi-bin/api/check"
data = self.build_captcha_data()
response = requests.post(url, headers=self.headers, data=data)
print(response.text)
return response.json()
def set_img(self, captcha_res):
self.img = captcha_res['img']
img_json = json.loads(captcha_res['img'])
self.api_st = captcha_res['st']
self.img1 = img_json['b1']
self.img2 = img_json['b2']
def get_captcha(self):
captcha_res = self.request_captcha()
if captcha_res.get("vt"):
self.vt = captcha_res["vt"]
self.api_st = captcha_res["st"]
return True
self.set_img(captcha_res)
return False
def verify_captcha(self):
bg = self.img1.replace('data:image/jpg;base64,', '')
background = base64.b64decode(bg)
fg = self.img2.replace('data:image/png;base64,', '')
target = base64.b64decode(fg)
res = self.ocr.slide_match(target, background, simple_target=True)
x = round(res['target'][0] * (290 / 275))
url = "https://jcap.m.jd.com/cgi-bin/api/check"
data = self.slide_ctw.call("verify", self.phone, self.jcap_sid, self.img, self.api_st, x)
response = self.session.post(url, headers=self.headers, data=data)
print(response.text)
return response.json()
def check_captcha(self):
captcha_res = self.verify_captcha()
if captcha_res.get("vt"):
self.vt = captcha_res["vt"]
self.api_st = captcha_res["st"]
return True
self.set_img(captcha_res)
return False
def build_send_code_data(self):
return self.user_ctw.call(
'sendMsg',
self.phone,
self.vt,
self.jd_risk_token_id,
self.s_token,
self.rsa_modulus
)
def send_code(self):
url = "https://plogin.m.jd.com/cgi-bin/mm/dosendlogincode"
data = self.build_send_code_data()
response = self.session.post(url, headers=self.headers, data=data)
print(response.text)
self.ck = self.get_cookie()
return response.json()
def get_h5st(self, code):
return self.h5st_ctw.call('getH5st', code, self.s_token)
def build_verify_data(self, phone, code, s_token, jd_risk_token_id, rsa_modulus):
h5st = self.get_h5st(code)
return self.user_ctw.call(
'login',
phone,
code,
s_token,
h5st,
jd_risk_token_id,
rsa_modulus
)
def get_cookie(self):
cookie_dict = self.session.cookies.get_dict()
return "; ".join([f"{key}={value}" for key, value in cookie_dict.items()]) + ";"
def request_sms_login(self, ck, code, s_token, jd_risk_token_id, rsa_modulus):
url = "https://plogin.m.jd.com/cgi-bin/mm/dosmslogin"
h5st = self.get_h5st(code)
data = self.user_ctw.call(
'login',
phone,
code,
s_token,
h5st,
jd_risk_token_id,
rsa_modulus
)
self.headers["cookie"] = ck
response = requests.post(url, headers=self.headers, data=data)
print(response.text)
self.ck = self.get_cookie()
return response.json()
def get_jd_risk_token_id(self):
res = self.request_jd_risk_token_id()
self.jd_risk_token_id = res.split('var jd_risk_token_id = ')[1].strip(";").strip("'")
def get_code_res(self):
send_res = self.send_code()
if send_res.get("err_code") == 0:
return 100, {
"ck": self.ck,
"s_token": self.s_token,
"jd_risk_token_id": self.jd_risk_token_id,
"rsa_modulus": self.rsa_modulus
}
else:
return 101, {
"ck": "",
"s_token": "",
"jd_risk_token_id": "",
"rsa_modulus": ""
}
@staticmethod
def my_response(status_code, data):
return {
"code": status_code,
"data": data,
"msg": "请求成功"
}
def run_get_ck(self, ck, code, s_token, jd_risk_token_id, rsa_modulus):
login_res = self.request_sms_login(ck, code, s_token, jd_risk_token_id, rsa_modulus)
if login_res.get("err_code") == 0:
data = {
"ck": self.ck
}
return self.my_response(status_code=100, data=data)
else:
data = {
"ck": ""
}
return self.my_response(status_code=101, data=data)
def run_send_code(self):
try:
# 获取risk_token_id
self.get_jd_risk_token_id()
# 获取登录所需初始sid
self.get_login_entrance()
self.get_jcap_sid()
# 获取验证码
self.get_api_params()
captcha_status = self.get_captcha()
if not captcha_status:
print("出现滑块验证")
# 验证验证码
check_status = self.check_captcha()
if check_status:
print("滑块验证通过,发送验证码")
status_code, data = self.get_code_res()
return self.my_response(status_code, data)
else:
print("没有出现滑块验证,直接发送验证码")
status_code, data = self.get_code_res()
return self.my_response(status_code, data)
except:
return self.my_response(status_code=111, data={})
if __name__ == '__main__':
phone = "13071534209"
res = LoginSpider(
phone=phone,
).run_send_code()
print(res)
res = LoginSpider(
phone=phone,
).run_get_ck(
ck="jcap_dvzw_fp=7Hq5_QuYK92sDlclFxhJ8m28JaYU1hDYJ-U-gC59LmJRPuo3ERCbiMGzn5vdc3WcTX0ndWGFZNOs3BDenMr7lw==; guid=a5bb2dc650ab23a2cf5cb58afef19b3f35adba9613421b4cba79aa59ea891803; lang=chs; lsid=503346699194megeguncgrf6gvwb9tdujp2md5p27pkt1737276375048; lstoken=vvwcnbi4;",
code="315572",
s_token='vvwcnbi4',
jd_risk_token_id='SH6IDCXBUWZNAV3SJPRGIXLVNHGLZR6AYHJ3244TGU5Z35SFJU76TAQ3OMNTXE7XA3SBRMPVTZJVW',
rsa_modulus='B03744DE9EAB28F6FA6B9C8FB1873CF57D42A2B6D382B79B276C2079A42B24C11D641EA642CF62485A632AE244DE6DE05A92A20EEFE8B6C7743F09FCE0BF78E6D614C115CDAEC2F4825F82E06770A2599D69BBADBE678DD25F2E5B9E2D0E3E15BEB749B436860872D30676794D3C3E8C37B71372DE52F223917FA730EC21F047'
)
print(res)