Browse Source

init

master
燕鹏 1 year ago
commit
a4b10b13a8
  1. 70
      JDMain.py
  2. 0
      __init__.py
  3. 52
      api_timer.py
  4. 75
      app.py
  5. 1
      cookie-yibeizi.txt
  6. 350
      jdseckillAPIv2.py
  7. 81
      myapp.py
  8. 3
      requirements.txt
  9. 30
      success.txt
  10. 112
      tools/ModifiedBase64.py
  11. 0
      tools/__init__.py
  12. 51
      tools/jd_sign.py
  13. 31
      tools/mylogger.py
  14. 163
      tools/utils.py

70
JDMain.py

@ -0,0 +1,70 @@
import warnings
import time
from datetime import datetime
import requests.utils
from jdseckillAPIv2 import JDSecKillAPI
from tools.mylogger import logger
warnings.filterwarnings('ignore')
from concurrent.futures import ThreadPoolExecutor, wait
class JDSecKillSubmit(JDSecKillAPI):
def __init__(self, sku, ck):
super().__init__(sku=sku, ck=ck)
self.sku = sku
self.ck = ck
def log(self, str_p):
logger.info(str_p)
def doKill(self, sk, order_data):
resp_json = self.submit_order(order_data=order_data, sk=sk)
if resp_json is not None:
txt = order_data['address']['name'] + "抢购结果:" + str(resp_json)
self.log(txt)
if resp_json['success']:
self.send_message(order_data['address']['name'] + '抢购成功, 订单:' + str(resp_json))
def appoint_task(self):
try:
resp_json = self.appoint_sku()
print("预约结果:%s" % str(resp_json))
self.log('appoint:' + str(resp_json))
except Exception as e:
print(str(e))
def killSku(self):
try:
token_params = self.get_token_key()
print(datetime.now())
divide_url = self.get_appjmp(token_params=token_params)
print(datetime.now())
captcha_url = self.get_divide(divide_url=divide_url)
print(datetime.now())
seckill_url = self.get_captcha(captcha_url=captcha_url)
print(datetime.now())
# todo 测试url
# seckill_url = 'https://marathon.jd.com/seckillM/seckill.action?skuId=' + self.sku + '&num=1&rid=1639830212'
resp = self.visit_seckill(seckill_url=seckill_url)
order_data = self.init_action()
print(datetime.now())
if order_data is not None:
for k in range(50):
sk_val = self.get_tak()
print("计算sk:%s" % str(sk_val))
self.doKill(sk_val, order_data)
time.sleep(0.5)
return True
return False
except Exception as e:
print(str(e))
return False

0
__init__.py

52
api_timer.py

@ -0,0 +1,52 @@
import json
import time
import requests
class JDTimer:
def __init__(self):
self.headers = {
'user-agent': 'okhttp/3.12.1;jdmall;android;version/10.5.0;build/95837;',
'content-type': 'application/x-www-form-urlencoded',
}
self.session = requests.Session()
try:
self.jd_time()
except Exception as e:
print(e)
def jd_time(self):
"""
从京东服务器获取时间毫秒
:return:
"""
url = 'https://api.m.jd.com/client.action?functionId=queryMaterialProducts&client=wh5'
ret = self.session.get(url, headers=self.headers, allow_redirects=False, verify=False).text
js = json.loads(ret)
return int(js["currentTime2"])
def local_time(self):
"""
获取本地毫秒时间
:return:
"""
return int(round(time.time() * 1000))
def local_jd_time_diff(self):
"""
计算本地与京东服务器时间差
:return:
"""
try:
return self.local_time() - self.jd_time()
except Exception as e:
print(e)
return 0
if __name__ == '__main__':
jdtimer = JDTimer()
for i in range(5):
print(jdtimer.local_jd_time_diff())

75
app.py

@ -0,0 +1,75 @@
import time
import sys
import os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
from api_timer import JDTimer
from tools import utils
from JDMain import JDSecKillSubmit
from tools.mylogger import logger
class JD:
def __init__(self):
sku = '100012043978'
def log(self, str_p):
logger.info(str_p)
def yuyueSku(self, sku, ck):
self.jdapi = JDSecKillSubmit(sku, ck)
self.jdapi.appoint_task()
def killSku(self):
for i in range(5):
print('%d次kill---------------------------->' % i)
result = self.jdapi.killSku()
if result:
break
def syncTime(self):
jdTimer = JDTimer()
return jdTimer.local_jd_time_diff()
if __name__ == '__main__':
jd = JD()
jd.log("正在读取cookie")
file = open("cookie-xqs.txt")
ck = file.read()
ck = 'pin=jd_694172ad51580;wskey=AAJgfXWSAEBLNQvLpLSYBYcBCqSXPF0LSFJksN9TUW-zjHxTQzDHotSD_LUE5EqkKLhBT3r0b3jCYYm33xg21oLFXWdad7mG;whwswswws=ypBVaXEwFjiJxh/kEB/6O2f6fohXOoCM3D8YNlQLR9tc=;unionwsws={"devicefinger":"eidA852c81205asb09A7r2HGTjCoC1RNl7MXytPQPScu2F6yVo+5IRMfDrQg8oI21UoEA0ZlhW+EgFWItSqxk76gpd5LLB389Tk1jXNw+GmMO1H7tOt5","jmafinger":"ypBVaXEwFjiJxh\/kEB\/6O2f6fohXOoCM3D8YNlQLR9tc="};'
jd.log(ck)
sku = '100012043978'
killTime = '2022-09-24 11:59:59.900'
killTimeTs = utils.getTimeStamp(killTime, format='%Y-%m-%d %H:%M:%S.%f')
syncedTime = False
hasYuyue = False
timeDiff = 0 # 时差
while True:
nowTimeTs = int(time.time() * 1000)
killDiff = killTimeTs - nowTimeTs
print("时间剩余%s" % str(int(killDiff / 1000)))
if killDiff < 5 * 60 * 1000 and not syncedTime:
syncedTime = True
timeDiff = jd.syncTime()
print("时差:%s" % str(timeDiff))
killTimeTs = killTimeTs + timeDiff
elif killDiff < 1 * 60 * 1000 and not hasYuyue:
hasYuyue = True
jd.yuyueSku(sku=sku, ck=ck)
elif killDiff < 0:
print("时差:%s" % str(timeDiff))
jd.killSku()
break
time.sleep(0.01)

1
cookie-yibeizi.txt

@ -0,0 +1 @@
pin=jd_41d74c83f8224;wskey=AAJjKGIcAED51MS4xl3rMhkuKoz3aIdtHgYbbY_gONAtDcvoXgp0nCjPWKcjgXoBw3ZNcm-HVECeryK5NBFQiErqyGbAcqt-;whwswswws=JD012145b9WBZ52FxcoJ166359098310502j1UGQOp_xw1sHnZf2TBLxIAVcI1pr_ptSG7GbI4Jh8JHPzpgXIVd6vHgcp4KUP7bIcL92ot4SobMNdIjsb6CeO0xXfdGg1DB166dh3n~lV6zvij0xVW8O87RwFvqyq8bfocRq2uG0yIAc6GJfPzG3Vt7W-bSkl68yzw3cggRUZpEKUJ0VpkW0x0Q0aGrCFLasnWujHANJMp2D1tUHzbtF-NKQkCBUiGE1ZKdTwYkeVoNQaOoU87ivURTKramyPzaIW67BRI6kPNkr3PLHsHc;unionwsws={"devicefinger":"eidAfa90812247s5vgf0CkxeRgeWBZfWowyK9r4H9Y2h1wPWRDa\/+LyYAJea3ooTv4ePNmFFv1ZArvKR74Nk1rlZWoaTpHUgZCeqmC5Lix6Hz1eGUEN6","jmafinger":"JD012145b9WBZ52FxcoJ166359098310502j1UGQOp_xw1sHnZf2TBLxIAVcI1pr_ptSG7GbI4Jh8JHPzpgXIVd6vHgcp4KUP7bIcL92ot4SobMNdIjsb6CeO0xXfdGg1DB166dh3n~lV6zvij0xVW8O87RwFvqyq8bfocRq2uG0yIAc6GJfPzG3Vt7W-bSkl68yzw3cggRUZpEKUJ0VpkW0x0Q0aGrCFLasnWujHANJMp2D1tUHzbtF-NKQkCBUiGE1ZKdTwYkeVoNQaOoU87ivURTKramyPzaIW67BRI6kPNkr3PLHsHc"};

350
jdseckillAPIv2.py

@ -0,0 +1,350 @@
import json
import warnings
import requests
import re
from urllib import parse
import time
from wxpusher import WxPusher
from tools import utils
from tools.jd_sign import getSign
warnings.filterwarnings('ignore')
def getUrlParams(url):
res = dict(parse.parse_qsl(url))
return res
def get_cookie_string(cookie):
cookie_string = ''
for cookie_key in cookie.keys():
cookie_string += '%s=%s;' % (cookie_key, cookie[cookie_key])
return cookie_string
def get_jd_time():
response = requests.get(url='https://api.m.jd.com/client.action?functionId=queryMaterialProducts&client=wh5')
print(response.json())
def get_sk(data):
data_val = [val for val in data['data'].values()]
n, o, p, q, r, s = data_val[0], data_val[1], data_val[2], data_val[3], data_val[4], data_val[5]
sk_val = ''
if n == 'cca':
sk_val = p[14:19].lower() + o[5:15].upper()
if n == 'ab': # check ok
sk_val = r[10:18] + s[2:13].lower()
if n == 'ch':
sk_val = q.upper() + r[6:10].upper()
if n == 'cbc': # check ok
sk_val = q[3:13].upper() + p[10:19].lower()
if n == 'by':
sk_val = o[5:8] + re.sub('a', 'c', p, flags=re.IGNORECASE)
if n == 'xa':
sk_val = o[1:16] + s[4:10]
if n == 'cza':
sk_val = q[6:19].lower() + s[5:11]
if n == 'cb':
sk_val = s[5:14] + p[2:13].upper()
return sk_val
class JDSecKillAPI:
def __init__(self, sku, ck):
self.skuId = sku
self.s = requests.session()
self.sku = sku
self.ck = ck
self.aid = ''
self.eid = 'eidAccfa8121das3mOM5swaGRcSw7E22kO50H5jjOzSUZLdxjWFZLi3ATsvj875K/RWM0W4ztxrbes6TNeio5uhWCeJIKObRbFo6NaYRyMqYuMJ2MM5D'
self.uuid = '351792042184702-6dd3f46ae26a'
self.uts = '0f31TVRjBSsqndu4/jgUPz6uymy50MQJAUhDDPnNIByQiRdjk5SK6CXmdShdxGaPRUd2+o8JNufp2fsgzyZpKhao+6lXsd3TXF8+jFmN/08eWFOjD36AXn3DPYPoc8MKL9ccf40wpTgO1wSP1oliin/fcMzzPHSxzINfo/svdCXHzPsMY3eZLWP0KGqPLr5fXA1RZRoBs4xl/IYv7E80OQ=='
self.wifiBssid = ''
self.ua = 'AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.106 Mobile Safari/537.36'
def appoint_sku(self):
headers = {
'user-agent': 'okhttp/3.12.1;jdmall;android;version/10.5.0;build/95837;',
'content-type': 'application/x-www-form-urlencoded',
'cookie': self.ck,
'jdc-backup': self.ck,
}
ts = int(time.time() * 1000)
uuid = self.uuid
ep = utils.get_ep(ts, uuid)
query_params = {
'functionId': 'appoint',
'clientVersion': '10.5.0',
'build': '95837',
'client': 'android',
'd_brand': 'HUAWEI',
'd_model': 'LIO-AN00',
'osVersion': '7.1.2',
'screen': '1920*1080',
'partner': 'hhqj02',
'aid': self.aid,
'eid': self.eid,
'sdkVersion': '29',
'lang': 'zh_CN',
'harmonyOs': '0',
'uuid': self.uuid,
'area': '',
'networkType': 'wifi',
'wifiBssid': self.wifiBssid,
'uts': self.uts,
'uemps': '0-0',
'ext': '{"prstate":"0","pvcStu":"1"}',
'ef': '1',
'ep': json.dumps(ep, ensure_ascii=False, separators=(',', ':')),
}
reserve_url = 'https://api.m.jd.com/client.action'
body = {"autoAddCart": "0", "bsid": "", "check": "0", "ctext": "", "isShowCode": "0", "mad": "0",
"skuId": self.skuId, "type": "1"}
plainTextDic = {
"st": ts, # 毫秒级时间戳
"sv": "120",
"functionId": query_params['functionId'],
"uuid": uuid,
"client": query_params['client'],
"clientVersion": query_params['clientVersion'],
"body": json.dumps(body, ensure_ascii=False, separators=(',', ':'))
}
st, sign, sv = getSign(plainTextDic)
query_params.update(st=st)
query_params.update(sign=sign)
query_params.update(sv=sv)
data = {'body': json.dumps(body, ensure_ascii=False, separators=(',', ':'))}
response = self.s.post(url=reserve_url,
params=query_params,
data=data,
headers=headers,
allow_redirects=False,
verify=False,
timeout=3)
return response.json()
def get_token_key(self):
headers = {
'user-agent': 'okhttp/3.12.1;jdmall;android;version/10.5.0;build/95837;',
'content-type': 'application/x-www-form-urlencoded',
'cookie': self.ck,
'jdc-backup': self.ck,
}
ts = int(time.time() * 1000)
uuid = self.uuid
ep = utils.get_ep(ts, uuid)
query_params = {
'functionId': 'genToken',
'clientVersion': '10.5.0',
'build': '95837',
'client': 'android',
'd_brand': 'HUAWEI',
'd_model': 'LIO-AN00',
'osVersion': '7.1.2',
'screen': '1920*1080',
'partner': 'hhqj02',
'aid': self.aid,
'eid': self.eid,
'sdkVersion': '29',
'lang': 'zh_CN',
'harmonyOs': '0',
'uuid': self.uuid,
'area': '',
'networkType': 'wifi',
'wifiBssid': self.wifiBssid,
'uts': self.uts,
'uemps': '0-0',
'ext': '{"prstate":"0","pvcStu":"1"}',
'ef': '1',
'ep': json.dumps(ep, ensure_ascii=False, separators=(',', ':')),
}
body = {"action": "to", "to": "https://divide.jd.com/user_routing?skuId="+self.sku}
plainTextDic = {
"st": ts, # 毫秒级时间戳
"sv": "120",
"functionId": query_params['functionId'],
"uuid": uuid,
"client": query_params['client'],
"clientVersion": query_params['clientVersion'],
"body": json.dumps(body, ensure_ascii=False, separators=(',', ':'))
}
st, sign, sv = getSign(plainTextDic)
query_params.update(st=st)
query_params.update(sign=sign)
query_params.update(sv=sv)
data = {'body': json.dumps(body, ensure_ascii=False, separators=(',', ':'))}
response = self.s.post(url='https://api.m.jd.com/client.action',
params=query_params,
data=data,
headers=headers,
allow_redirects=False,
verify=False,
timeout=3)
# token_key = response.json()['tokenKey']
# print('Token Key: ----------> %s' % response.json())
# print(response.status_code)
json_obj = response.json()
print('Get genToken--------------->%s' % str(json_obj))
return json_obj
def get_appjmp(self, token_params):
headers = {
'user-agent': self.ua
}
appjmp_url = token_params['url']
params = {
'to': 'https://divide.jd.com/user_routing?skuId=%s' % self.skuId,
'tokenKey': token_params['tokenKey']
}
response = self.s.get(url=appjmp_url, params=params, allow_redirects=False, verify=False, headers=headers)
print('Get Appjmp跳转链接-------------->%s' % response.headers['Location'])
return response.headers['Location']
def get_divide(self, divide_url):
headers = {
'user-agent': self.ua
}
response = self.s.get(url=divide_url, allow_redirects=False, verify=False, headers=headers)
print('Get Divide跳转链接-------------->%s' % response.headers['Location'])
return response.headers['Location']
def get_captcha(self, captcha_url):
headers = {
'user-agent': self.ua
}
response = self.s.get(url=captcha_url, allow_redirects=False, verify=False, headers=headers)
print('Get Captcha跳转链接-------------->%s' % response.headers['Location'])
return response.headers['Location']
def visit_seckill(self, seckill_url):
headers = {
'user-agent': self.ua
}
response = self.s.get(url=seckill_url, allow_redirects=False, verify=False, headers=headers)
return response
def init_action(self, num=1):
try:
headers = {
'user-agent': self.ua,
'Connection': 'keep-alive'
}
init_action_url = 'https://marathon.jd.com/seckillnew/orderService/init.action'
data = {
'sku': self.skuId,
'num': num,
'id': 0,
'provinceId': 0,
'cityId': 0,
'countyId': 0,
'townId': 0,
}
response = self.s.post(url=init_action_url, data=data, allow_redirects=False, verify=False, headers=headers)
print('init action返回数据:%s' % response.text)
return response.json()
except Exception as e:
print(str(e))
return None
def get_tak(self):
try:
headers = {
'user-agent': self.ua,
'Connection': 'keep-alive'
}
tak_url = 'https://tak.jd.com/t/871A9?_t=%d' % (int(round(time.time() * 1000)))
response = self.s.get(url=tak_url, allow_redirects=False, verify=False, headers=headers)
sk_val = get_sk(data=response.json())
return sk_val
except Exception as e:
print(str(e))
return ''
def submit_order(self, order_data, sk):
try:
headers = {
'user-agent': self.ua,
'Connection': 'keep-alive'
}
submit_order_url = 'https://marathon.jd.com/seckillnew/orderService/submitOrder.action?skuId=%s' % self.skuId
address_info = order_data['address']
invoice_info = order_data['invoiceInfo']
data = {
'num': order_data['seckillSkuVO']['num'],
'addressId': address_info['id'],
'yuShou': True,
'isModifyAddress': False,
'name': address_info['name'],
'provinceId': address_info['provinceId'],
'provinceName': address_info['provinceName'],
'cityId': address_info['cityId'],
'cityName': address_info['cityName'],
'countyId': address_info['countyId'],
'countyName': address_info['countyName'],
'townId': address_info['townId'],
'townName': address_info['townName'],
'addressDetail': address_info['addressDetail'],
'mobile': address_info['mobile'],
'mobileKey': address_info['mobileKey'],
'email': '',
'invoiceTitle': invoice_info['invoiceTitle'],
'invoiceContent': invoice_info['invoiceContentType'],
'invoicePhone': invoice_info['invoicePhone'],
'invoicePhoneKey': invoice_info['invoicePhoneKey'],
'invoice': True,
'codTimeType': '3',
'paymentType': '4',
'overseas': '0',
'token': order_data['token'],
'sk': sk,
}
response = self.s.post(url=submit_order_url, data=data, allow_redirects=False, verify=False, headers=headers)
return response.json()
except Exception as e:
print('submit error--->')
return None
def send_message(self, content):
try:
# 推送token
PUSH_TOKEN = 'AT_4XxUFvSjSLWTlFhX1nFmIepe1RNoGq8b'
UIDS = [
'UID_D77yyDO0pT7K0f1q2UijDTGnGthF',
]
msg = WxPusher.send_message(content,
uids=UIDS,
token=PUSH_TOKEN)
except Exception as e:
print('send_message error--->'+str(e))
if __name__ == '__main__':
ck = 'pin=jd_694172ad51580;wskey=AAJgfXWSAEBLNQvLpLSYBYcBCqSXPF0LSFJksN9TUW-zjHxTQzDHotSD_LUE5EqkKLhBT3r0b3jCYYm33xg21oLFXWdad7mG;whwswswws=ypBVaXEwFjiJxh/kEB/6O2f6fohXOoCM3D8YNlQLR9tc=;unionwsws={"devicefinger":"eidA852c81205asb09A7r2HGTjCoC1RNl7MXytPQPScu2F6yVo+5IRMfDrQg8oI21UoEA0ZlhW+EgFWItSqxk76gpd5LLB389Tk1jXNw+GmMO1H7tOt5","jmafinger":"ypBVaXEwFjiJxh\/kEB\/6O2f6fohXOoCM3D8YNlQLR9tc="};'
ck = 'pin=jd_4d36cfba7dab3;wskey=AAJjGfg2AEDbVEKTmVkgEvWx-McNVFq980fU5IHeej0nLaHVNdOtzlTLYBDCEucWGJ4G9teOfEzntfRGd6KQyjXgY3rjDDn1;whwswswws=JD012145b9v1fE5xpOyD1662646298263061cDoZzexYxAp8KLqT9smx6eCUAMi_vgpfvlNGugBkHqboOLvPxFIIgdchS83Af4aCPkH9MZR8ybX3QlO52r5tGF45M9TrieypOzwu3NAoOs0a40rty~w8wI98OE8okFESgoJ3sI8KD1kO1fXEYyQfW7eDyRLBI1VlbD72BRZvaIwvqX8mX245w7Jl7eI9mR2U_2IrtbtCm-NOZyDZr7LWiepMRuTaaO-iRDLr0M_4xyeRgstrh1ombJE27yWpzAQs4PLrFSWhVWGnPf597V0y6FJhG3YaXA;unionwsws={"devicefinger":"eidAea1681212dsbM9nriXryQHq\/kLPLj0nYnTPZ7QyYY2ofy15o7Ohj1DMrIY\/71NnUV3ow\/8dwlD\/hgR5tfjQJNif\/1NbGABbd9A29YETZGl0TuF45","jmafinger":"JD012145b9v1fE5xpOyD1662646298263061cDoZzexYxAp8KLqT9smx6eCUAMi_vgpfvlNGugBkHqboOLvPxFIIgdchS83Af4aCPkH9MZR8ybX3QlO52r5tGF45M9TrieypOzwu3NAoOs0a40rty~w8wI98OE8okFESgoJ3sI8KD1kO1fXEYyQfW7eDyRLBI1VlbD72BRZvaIwvqX8mX245w7Jl7eI9mR2U_2IrtbtCm-NOZyDZr7LWiepMRuTaaO-iRDLr0M_4xyeRgstrh1ombJE27yWpzAQs4PLrFSWhVWGnPf597V0y6FJhG3YaXA"};'
jdapi = JDSecKillAPI('100012043978', ck)
print('预约结果--->', jdapi.appoint_sku())
print('gentoken结果--->', jdapi.get_token_key('100012043978'))

81
myapp.py

@ -0,0 +1,81 @@
import time
import sys
import os
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
from multiprocessing import Process
import requests
from tools import utils
from JDMain import JDSecKillSubmit
from api_timer import JDTimer
def syncTime():
jdTimer = JDTimer()
return jdTimer.local_jd_time_diff()
def yuyueSku(sku, ck):
jdapi = JDSecKillSubmit(sku, ck)
jdapi.appoint_task()
def killSku(sku, ck):
jdapi = JDSecKillSubmit(sku, ck)
for i in range(5):
print('%d次kill---------------------------->' % i)
if jdapi.killSku():
break
def work(killTime, ck):
print('ck:', ck)
sku = '100012043978'
killTimeTs = utils.getTimeStamp(killTime, format='%Y-%m-%d %H:%M:%S.%f')
syncedTime = False
hasYuyue = False
timeDiff = 0 # 时差
while True:
nowTimeTs = int(time.time() * 1000)
killDiff = killTimeTs - nowTimeTs
print("时间剩余%s" % str(int(killDiff / 1000)))
if killDiff < 5 * 60 * 1000 and not syncedTime:
syncedTime = True
timeDiff = syncTime()
print("时差:%s" % str(timeDiff))
killTimeTs = killTimeTs + timeDiff
elif killDiff < 2 * 60 * 1000 and not hasYuyue:
hasYuyue = True
yuyueSku(sku=sku, ck=ck)
elif killDiff < 0:
print("时差:%s" % str(timeDiff))
killSku(sku=sku, ck=ck)
break
time.sleep(0.01)
if __name__ == '__main__':
# 抢购时间
killTime = '2022-11-09 11:59:59.800'
# cookie
cks = [
'pin=jd_41d74c83f8224;wskey=AAJjKGIcAED51MS4xl3rMhkuKoz3aIdtHgYbbY_gONAtDcvoXgp0nCjPWKcjgXoBw3ZNcm-HVECeryK5NBFQiErqyGbAcqt-;whwswswws=JD012145b9WBZ52FxcoJ166359098310502j1UGQOp_xw1sHnZf2TBLxIAVcI1pr_ptSG7GbI4Jh8JHPzpgXIVd6vHgcp4KUP7bIcL92ot4SobMNdIjsb6CeO0xXfdGg1DB166dh3n~lV6zvij0xVW8O87RwFvqyq8bfocRq2uG0yIAc6GJfPzG3Vt7W-bSkl68yzw3cggRUZpEKUJ0VpkW0x0Q0aGrCFLasnWujHANJMp2D1tUHzbtF-NKQkCBUiGE1ZKdTwYkeVoNQaOoU87ivURTKramyPzaIW67BRI6kPNkr3PLHsHc;unionwsws={"devicefinger":"eidAfa90812247s5vgf0CkxeRgeWBZfWowyK9r4H9Y2h1wPWRDa\/+LyYAJea3ooTv4ePNmFFv1ZArvKR74Nk1rlZWoaTpHUgZCeqmC5Lix6Hz1eGUEN6","jmafinger":"JD012145b9WBZ52FxcoJ166359098310502j1UGQOp_xw1sHnZf2TBLxIAVcI1pr_ptSG7GbI4Jh8JHPzpgXIVd6vHgcp4KUP7bIcL92ot4SobMNdIjsb6CeO0xXfdGg1DB166dh3n~lV6zvij0xVW8O87RwFvqyq8bfocRq2uG0yIAc6GJfPzG3Vt7W-bSkl68yzw3cggRUZpEKUJ0VpkW0x0Q0aGrCFLasnWujHANJMp2D1tUHzbtF-NKQkCBUiGE1ZKdTwYkeVoNQaOoU87ivURTKramyPzaIW67BRI6kPNkr3PLHsHc"};',
]
p = []
for i in range(len(cks)):
p1 = Process(target=work, args=(killTime, cks[i],))
p1.start()
p.append(p1)
for i in range(len(cks)):
p[i].join()

3
requirements.txt

@ -0,0 +1,3 @@
requests==2.27.1
wxpusher==2.2.0
urllib3==1.26.9

30
success.txt

@ -0,0 +1,30 @@
计算sk:zr7oflx9p335iWYurie
Expecting value: line 1 column 1 (char 0)
Get Divide跳转链接-------------->https://marathon.jd.com/m/captcha.html?sid=b8385a800e93b184ff8bb16a0e79d8aw&skuId=10001
2043978&mid=rvXgpdduG3wnlgfPzI2wXkvpgNqF4IA9qcWds4ffipY
Get Captcha跳转链接-------------->https://marathon.jd.com/mobile/koFail.html
init action返回数据:{"address":{"addressDetail":"西李村","areaCode":"999999","cityId":2900,"cityName":"济宁市","countyI
d":2917,"countyName":"金乡县","defaultAddress":false,"id":6188735630,"mobile":"133****4689","mobileKey":"f7dcf949de1a7b4
27463a9dd90f632e1","name":"王秋娟","overseas":0,"phone":"","postCode":"","provinceId":13,"provinceName":"山东","selected
":true,"townId":25860,"townName":"鱼山街道","yuyueAddress":false},"buyNum":2,"code":"200","invoiceInfo":{"invoiceContent
Type":1,"invoicePhone":"133****4689","invoicePhoneKey":"f7dcf949de1a7b427463a9dd90f632e1","invoiceTitle":4,"invoiceType"
:3},"jingdouBO":{"canUseCount":0,"forbidUseJingdou":false,"jingdouDiscount":0,"jingdouSteps":[],"pointsDeductionRate":50
,"rate":100,"totalCount":179,"usedCount":0},"orderPriceBO":{"couponAbleNum":0,"couponDiscount":0.00,"couponDiscountTotal
":0.00,"couponSelectNum":0,"couponTypeList":[],"freight":0.00,"giftCardAbleNum":0,"giftCardDiscount":0.00,"giftCardSelec
tNum":0,"jingdouDiscount":0,"manjianDiscount":0.00,"orderTax":0.00,"productTotalPrice":1499.00,"redPacketDeductionAmount
":0,"redPacketIsSelected":false,"redPacketTotalAmount":0,"showXuZhongInfo":false,"totalPrice":1499.00,"weight":"1.12","y
unfeiDiscount":0.00},"payment":{"paymentId":4,"paymentName":"在线支付"},"preSaleBO":{"hidePrice":false,"refundDeposit":f
alse},"seckillOrderExt":{},"seckillSkuVO":{"color":"飞天 53%vol 500ml 贵州茅台酒","extMap":{"YuShou":"1","is7ToReturn":"
0","new7ToReturn":"8","thwa":"0","SoldOversea":"0"},"height":0.0,"jdPrice":1499.00,"length":0.0,"num":1,"rePrice":0.00,"
size":"","skuId":100012043978,"skuImgUrl":"jfs/t1/204850/31/20522/123067/61af3d74E747493f0/385d705a66b5263b.jpg","skuNam
e":"飞天 53%vol 500ml 贵州茅台酒(带杯)","skuPrice":1499.00,"thirdCategoryId":0.0,"venderName":"京东自营","venderType"
:0,"weight":1.120,"width":0.0},"shipment":{"bundleUuid":"BundleRelation_1125395520593502208","obtainAllCombinationBundle
":"CombinationBundleRelation_1125395520425730051","obtainOrder":"-1719262869","shipmentTimeType":4,"shipmentTimeTypeName
":"标准达","shipmentType":65,"shipmentTypeName":"京东配送","uuid":"101612_1125395520610279424"},"token":"fdc90dde774b3c5
84b613a8b33050a95","userInfoBO":{"userScore":5525}}
计算sk:6ktun1kxw1gypV4GMMQ
抢购结果:{'appUrl': 'https://mpay.m.jd.com/mpay.1ec8f70280318a51e2bb.html?appId=jd_m_msha&payId=3420cb4f0d7a4424b53f8ae7
81f542f6', 'orderId': 250387144183, 'pcUrl': '//sko.jd.com/success/success.action?orderId=250387144183&rid=0.88556282118
81714', 'resultCode': 0, 'skuId': 0, 'success': True, 'totalMoney': '1499.00'}
耗时:941
Get Divide跳转链接-------------->https://marathon.jd.com/m/captcha.html?sid=b8385a800e93b184ff8bb16a0e79d8aw&skuId=10001

112
tools/ModifiedBase64.py

@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
class ModifiedBase64(object):
def __init__(self):
self.aae = ['K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', '/']
self.aaf = [None] * 128
# renamed from: pf
# def m23208pf(self):
i = 0
i2 = 0
while True:
bArr = self.aaf
if i2 <= len(bArr) - 1:
bArr[i2] = -1
i2 += 1
else:
break
while True:
cArr = self.aae
if i <= len(cArr) - 1:
self.aaf[ord(cArr[i])] = int(i)
i += 1
else:
return
def m23207r(self, str_):
result = ''
bArr = bytearray(str_.encode('utf-8'))
i = 0
while i <= len(bArr) - 1:
bArr2 = [None] * 4
b = 0
i2 = 0
while i2 <= 2:
i3 = i + i2
if i3 <= len(bArr) - 1:
bArr2[i2] = (b | ((bArr[i3] & 255) >> ((i2 * 2) + 2)))
b = ((((bArr[i3] & 255) << (((2 - i2) * 2) + 2)) & 255) >> 2)
else:
bArr2[i2] = b
b = 0x40 # SignedBytes.MAX_POWER_OF_TWO;
i2 += 1
bArr2[3] = b
i4 = 0
while i4 <= 3:
if bArr2[i4] <= 63:
result = result + self.aae[bArr2[i4]]
else:
result = result + '='
i4 += 1
i += 3
return result
# renamed from: eC
def m23209eC(self, str_):
""" generated source for method m23209eC """
bys = []
# bytes = str_.encode('utf-8')
bytes = bytearray(str_.encode('utf-8'))
# print(bytes)
bArr = [None] * len(bytes)
i = 0
while i <= len(bytes) - 1:
bArr[i] = self.aaf[bytes[i]]
i += 1
i2 = 0
while i2 <= len(bArr) - 1:
bArr2 = [None] * 3
i3 = 0
i4 = 0
i7 = 0
while i4 <= 2:
i5 = i2 + i4
i6 = i5 + 1
if i6 <= len(bArr) and bArr[i6] >= 0:
bArr2[i4] = ((bArr[i5] & 255) << ((i4 * 2) + 2)) | ((bArr[i6] & 255) >> (((2 - (i4 + 1)) * 2) + 2))
i3 += 1
i4 += 1
while i7 <= i3 - 1:
bys.append(self.py2ja(bArr2[i7]))
i7 += 1
i2 += 4
return bytearray(bys).decode('utf-8')
def py2ja(self, arr: int):
"""
python字节数组转java字节数组
:return:
"""
while arr >= 256:
arr = arr - 256
return arr
if __name__ == '__main__':
# UUID = "ENYnDJO5CNGnCJC5DzcyBWHtEJK4ENcyDJu3EG=="
v = ModifiedBase64()
# a = v.m23209eC(UUID)
# print(a)
text = '5ZIG5Ya26AQX6YQJ5YsY6SML5bsS'
print(v.m23209eC(text))
text = '唐冶街道刘老师'
print(v.m23207r(text))

0
tools/__init__.py

51
tools/jd_sign.py

@ -0,0 +1,51 @@
import base64
import hashlib
def getSign(params):
# sv传120
key = [55, 146, 68, 104, 165, 61, 204, 127, 187, 15, 217, 136, 238, 154, 233, 90]
arg0 = [56, 48, 51, 48, 54, 102, 52, 51, 55, 48, 98, 51, 57, 102, 100, 53, 54, 51, 48, 97, 100, 48, 53, 50, 57, 102,
55, 55, 97, 100, 98, 54]
sign = "functionId=" + params.get("functionId") + "&body=" + params.get("body") + "&uuid=" + params.get("uuid") \
+ "&client=" + params.get("client") + "&clientVersion=" + params.get("clientVersion") + "&st=" + str(
params.get("st")) \
+ "&sv=" + str(params.get("sv"))
arg2 = bytearray(sign, 'utf-8')
# print([x for x in arg2])
ss = [None] * len(arg2)
for i in range(len(arg2)):
R0 = arg2[i]
R2 = key[i & 15]
R4 = arg0[i & 7]
R0 = ((R2 ^ R0) ^ R4) + R2
R2 = (R2 ^ R0)
R1 = arg0[i & 7]
R2 = (R2 ^ R1)
# print(R2)
ss[i] = R2
m = hashlib.md5()
m.update(base64.b64encode(bytes(i % 256 for i in ss)))
return str(params.get("st")), m.hexdigest(), str(params.get("sv"))
# return "st=" + str(params.get("st")) + "&sign=" + m.hexdigest() + "&sv=" + str(params.get("sv"))
def generateSign():
params = {
"st": 1648992407201, # 毫秒级时间戳
"sv": "120",
"functionId": 'serverConfig',
"uuid": '947934e94e0cb9e4',
"client": "android",
"clientVersion": '10.4.6',
# "body": '{"to":"https://plogin.m.jd.com/jd-mlogin/static/html/appjmp_blank.html"}'
"body": '{}'
}
# return getSign(params)
print(getSign(params))
# print("正确结果:st=1648992407201&sign=474c50af52257126ae65700b825bdf4c&sv=120")
if __name__ == '__main__':
generateSign()

31
tools/mylogger.py

@ -0,0 +1,31 @@
import logging
import logging.handlers
import os
'''
os.getcwd()代表py执行目录
日志模块
'''
# 创建log文件夹
new_path = os.path.join(os.getcwd(), 'log')
if not os.path.exists(new_path):
os.makedirs(new_path)
LOG_FILENAME = 'log/jd.log'
logger = logging.getLogger()
def set_logger():
if not logger.handlers:
logger.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s')
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
file_handler = logging.handlers.RotatingFileHandler(
LOG_FILENAME, maxBytes=5*1024*1024, backupCount=5, encoding="utf-8")
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
set_logger()

163
tools/utils.py

@ -0,0 +1,163 @@
import hashlib
import platform
import random
import socket
from datetime import datetime
import sys
import os
from http.cookies import SimpleCookie
import json
import re
from tools.ModifiedBase64 import ModifiedBase64
def text_to_json(text, regex):
pattern = re.compile(regex)
text_list = re.findall(pattern, text)
_json = json.loads(text_list[0])
return _json
def remove_unused_symbol(text):
return text.replace('\n', '').replace('\r', '').replace('\t', '')
def remove_redundant_comma(text):
"""
移除json多余逗号避免json.loads报错
"""
rex = r"""(?<=[}\]"'])\s*,\s*(?!\s*[{["'])"""
return re.sub(rex, "", text, 0)
def resource_path(relative_path):
if getattr(sys, 'frozen', False):
base_path = sys._MEIPASS
else:
base_path = os.path.abspath("../..")
return os.path.join(base_path, relative_path)
def export_file_name():
return "ck-export-" + datetime.now().strftime('%Y%m%d%H%M%S') + ".txt"
def desktop_path():
if platform.system() == 'Windows':
return r"C:\Users\Administrator\Desktop"
else:
return "/Users/xiaoqingsong/Desktop"
def is_json(text):
if text is None:
return False
try:
json.loads(text)
except ValueError:
return False
return True
def getTimeStamp(time):
"""
:param time: 形如 2021-01-20 10:10:20.120
:return:
"""
ts = datetime.timestamp(datetime.strptime(time, '%Y-%m-%d %H:%M:%S.%f'))
return int(ts * 1000)
def getTimeStamp(time, format):
"""
:param format: %Y-%m-%d %H:%M:%S
:param time: 形如 2021-01-20 10:10:20
:return:
"""
ts = datetime.timestamp(datetime.strptime(time, format))
return int(ts * 1000)
def getNowTime():
return datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-7]
def getCookieFromStr(rawStr):
cookie = SimpleCookie()
cookie.load(rawStr)
# Even though SimpleCookie is dictionary-like, it internally uses a Morsel object
# which is incompatible with requests. Manually construct a dictionary instead.
cookies = {}
for key, morsel in cookie.items():
cookies[key] = morsel.value
return cookies
def get_random_number_str(length):
"""
生成随机数字字符串
:param length: 字符串长度
:return:
"""
num_str = ''.join(str(random.choice(range(10))) for _ in range(length))
return num_str
def randomUUID():
random_number = get_random_number_str(15)
random_str = hashlib.md5(random_number.encode('utf-8')).hexdigest()[:12]
return random_number + "-" + random_str
def get_host_ip():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
finally:
s.close()
return ip
def mb_encrypt(str):
v = ModifiedBase64()
return v.m23207r(str)
def get_ep(ts, uuid):
area = '13_1000_40488_54435'
d_model = 'PDNM00'
wifiBssid = 'unknown'
osVersion = '11'
d_brand = 'OPPO'
screen = '2161*1080'
uuid = uuid
aid = uuid
openudid = uuid
hdid = ''
ep = {
'hdid': mb_encrypt(hdid),
'ts': ts,
'ridx': -1,
'cipher': {
'area': mb_encrypt(area),
'd_model': mb_encrypt(d_model),
'wifiBssid': mb_encrypt(wifiBssid),
'osVersion': mb_encrypt(osVersion),
'd_brand': mb_encrypt(d_brand),
'screen': mb_encrypt(screen),
'uuid': mb_encrypt(uuid),
'aid': mb_encrypt(aid),
'openudid': mb_encrypt(openudid),
},
'ciphertype': 5,
'version': '1.2.0',
'appname': 'com.jingdong.app.mall',
}
return ep
Loading…
Cancel
Save