From 8b97613776635609653ce13170b261bdb58578a6 Mon Sep 17 00:00:00 2001 From: dylan <58234511@qq.com> Date: Mon, 18 Dec 2023 20:15:21 +0800 Subject: [PATCH] 1 --- jd_wskey.py | 653 ++++++++++++++++++---------------------------------- 1 file changed, 229 insertions(+), 424 deletions(-) diff --git a/jd_wskey.py b/jd_wskey.py index 0e60f93..96dba78 100644 --- a/jd_wskey.py +++ b/jd_wskey.py @@ -4,122 +4,43 @@ 2 10 20 5 * jd_wskey.py new Env('wskey转换'); ''' -import socket # 用于端口检测 -import base64 # 用于编解码 -import json # 用于Json解析 -import os # 用于导入系统变量 -import sys # 实现 sys.exit -import logging # 用于日志输出 -import time # 时间 -import re # 正则过滤 + +import socket +import base64 +import json +import os +import sys +import logging +import time +import re import hmac import struct -import random WSKEY_MODE = 0 # 0 = Default / 1 = Debug! - -def getua(): - global uuid, addressid, iosVer, iosV, clientVersion, iPhone, area, ADID - uuid = ''.join([str(random.randint(0, 9)) for _ in range(40)]) - addressid = ''.join(random.sample('1234567898647', 10)) - iosVer = ''.join(random.sample( - ["15.1.1", "14.5.1", "14.4", "14.3", "14.2", "14.1", "14.0.1"], 1)) - iosV = iosVer.replace('.', '_') - clientVersion = ''.join(random.sample(["10.3.0", "10.2.7", "10.2.4"], 1)) - iPhone = ''.join(random.sample(["8", "9", "10", "11", "12", "13"], 1)) - ADID = ''.join(random.sample('0987654321ABCDEF', 8)) + '-' + ''.join(random.sample('0987654321ABCDEF', 4)) + '-' + ''.join(random.sample( - '0987654321ABCDEF', 4)) + '-' + ''.join(random.sample('0987654321ABCDEF', 4)) + '-' + ''.join(random.sample('0987654321ABCDEF', 12)) - UserAgent = '' - if not UserAgent: - return f'jdapp;iPhone;{clientVersion};{iosVer};{uuid};network/wifi;ADID/{ADID};model/iPhone{iPhone},1;addressid/{addressid};appBuild/167707;jdSupportDarkMode/0;Mozilla/5.0 (iPhone; CPU iPhone OS {iosV} like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/null;supportJDSHWK/1' - else: - return UserAgent - - -def get_proxy_api(proxy_url, max_retries=5, timeout=60, retry_delay=1): - for retry in range(max_retries): - res = requests.get(url=proxy_url) - print(f"使用代理:{res.text}") - proxy_ip_port = res.text.strip() - proxy_address = f"http://{proxy_ip_port}" - - try: - response = requests.get( - "https://jd.com", proxies={"http": proxy_address, "https": proxy_address}, timeout=timeout) - if response.status_code == 200: - return proxy_address - except Exception as e: - print(f"代理检测失败,错误信息:{e}") - - print("代理检测失败,重新获取...") - time.sleep(retry_delay) - - print("无法获取可用的代理IP,尝试次数已达上限。") - return None - - if "WSKEY_DEBUG" in os.environ or WSKEY_MODE: # 判断调试模式变量 - logging.basicConfig(level=logging.DEBUG, - format='%(message)s') # 设置日志为 Debug等级输出 + logging.basicConfig(level=logging.DEBUG, format='%(message)s') # 设置日志为 Debug等级输出 logger = logging.getLogger(__name__) # 主模块 logger.debug("\nDEBUG模式开启!\n") # 消息输出 -else: # 判断分支 +else: logging.basicConfig(level=logging.INFO, format='%(message)s') # Info级日志 logger = logging.getLogger(__name__) # 主模块 -try: # 异常捕捉 +try: import requests # 导入HTTP模块 -except Exception as e: # 异常捕捉 +except Exception as e: logger.info(str(e) + "\n缺少requests模块, 请执行命令:pip3 install requests\n") # 日志输出 sys.exit(1) # 退出脚本 os.environ['no_proxy'] = '*' # 禁用代理 requests.packages.urllib3.disable_warnings() # 抑制错误 -try: # 异常捕捉 - from sendNotify import send # 导入青龙消息通知模块 -except Exception as err: # 异常捕捉 +try: + from notify import send # 导入青龙消息通知模块 +except Exception as err: logger.debug(str(err)) # 调试日志输出 logger.info("无推送文件") # 标准日志输出 -ver = 21212 # 版本号 - - -# def ql_2fa(): -# ''' Demo -# if "WSKEY_TOKEN" in os.environ: -# url = 'http://127.0.0.1:{0}/api/user'.format(port) # 设置 URL地址 -# try: # 异常捕捉 -# res = s.get(url) # HTTP请求 [GET] 使用 session -# except Exception as err: # 异常捕捉 -# logger.debug(str(err)) # 调试日志输出 -# else: # 判断分支 -# if res.status_code == 200 and res.json()["code"] == 200: -# twoFactorActivated = str(res.json()["data"]["twoFactorActivated"]) -# if twoFactorActivated == 'true': -# logger.info("青龙 2FA 已开启!") -# url = 'http://127.0.0.1:{0}/api/envs?searchValue=WSKEY_Client'.format(port) # 设置 URL地址 -# res = s.get(url) -# if res.status_code == 200 and res.json()["code"] == 200: -# data = res.json()["data"] -# if len(data) == 0: -# url = 'http://127.0.0.1:{0}/api/apps' -# data = json.dumps({ -# "name": "wskey", -# "scopes": ["crons", "envs", "configs", "scripts", "logs", "dependencies", "system"] -# }) -# res = s.post(url, data=data) -# if res.status_code == 200 and res.json()["code"] == 200: -# logger.info("OpenApi创建成功") -# client_id = res.json()["data"]["client_id"] -# client_secret = res.json()["data"]["client_secret"] -# wskey_value = 'client_id={0}&client_secret={1}'.format(client_id, client_secret) -# data = [{"value": wskey_value, "name": "WSKEY_Client", "remarks": "WSKEY_OpenApi请勿删除"}] -# data = json.dumps(data) # Json格式化数据 -# url = 'http://127.0.0.1:{0}/api/envs'.format(port) # 设置 URL地址 -# s.post(url=url, data=data) # HTTP[POST]请求 使用session -# logger.info("\nWSKEY_Client变量添加完成\n--------------------\n") # 标准日志输出 -# ''' +ver = 31207 # 版本号 def ttotp(key): key = base64.b32decode(key.upper() + '=' * ((8 - len(key)) % 8)) @@ -134,9 +55,9 @@ def ql_send(text): if "WSKEY_SEND" in os.environ and os.environ["WSKEY_SEND"] == 'disable': return True else: - try: # 异常捕捉 + try: send('WSKEY转换', text) # 消息发送 - except Exception as err: # 异常捕捉 + except Exception as err: logger.debug(str(err)) # Debug日志输出 logger.info("通知发送失败") # 标准日志输出 @@ -152,56 +73,50 @@ def get_qltoken(username, password, twoFactorSecret): # 方法 用于获取青 logger.info("TOTP异常") sys.exit(1) url = ql_url + "api/user/login" # 设置青龙地址 使用 format格式化自定义端口 - payload = json.dumps({ + body = { 'username': username, 'password': password - }) # HTTP请求载荷 + } # HTTP请求载荷 headers = { 'Accept': 'application/json', 'Content-Type': 'application/json' } # HTTP请求头 设置为 Json格式 - try: # 异常捕捉 - # 使用 requests模块进行 HTTP POST请求 - res = requests.post(url=url, headers=headers, data=payload) + try: + res = requests.post(url=url, headers=headers, json=body) # 使用 requests模块进行 HTTP POST请求 if res.status_code == 200 and res.json()["code"] == 420: url = ql_url + 'api/user/two-factor/login' - data = json.dumps({ - "username": username, - "password": password, - "code": twoCode - }) - res = requests.put(url=url, headers=headers, data=data) + body = { + 'username': username, + 'password': password, + 'code': twoCode + } + res = requests.put(url=url, headers=headers, json=body) if res.status_code == 200 and res.json()["code"] == 200: - # 从 res.text 返回值中 取出 Token值 - token = res.json()["data"]['token'] + token = res.json()["data"]['token'] # 从 res.text 返回值中 取出 Token值 return token else: logger.info("两步校验失败\n") # 日志输出 sys.exit(1) elif res.status_code == 200 and res.json()["code"] == 200: - # 从 res.text 返回值中 取出 Token值 - token = res.json()["data"]['token'] + token = res.json()["data"]['token'] # 从 res.text 返回值中 取出 Token值 return token except Exception as err: logger.debug(str(err)) # Debug日志输出 sys.exit(1) else: url = ql_url + 'api/user/login' - payload = { + body = { 'username': username, 'password': password } # HTTP请求载荷 - payload = json.dumps(payload) # json格式化载荷 headers = { 'Accept': 'application/json', 'Content-Type': 'application/json' } # HTTP请求头 设置为 Json格式 - try: # 异常捕捉 - # 使用 requests模块进行 HTTP POST请求 - res = requests.post(url=url, headers=headers, data=payload) + try: + res = requests.post(url=url, headers=headers, json=body) # 使用 requests模块进行 HTTP POST请求 if res.status_code == 200 and res.json()["code"] == 200: - # 从 res.text 返回值中 取出 Token值 - token = res.json()["data"]['token'] + token = res.json()["data"]['token'] # 从 res.text 返回值中 取出 Token值 return token else: ql_send("青龙登录失败!") @@ -210,21 +125,10 @@ def get_qltoken(username, password, twoFactorSecret): # 方法 用于获取青 logger.debug(str(err)) # Debug日志输出 logger.info("使用旧版青龙登录接口") url = ql_url + 'api/login' # 设置青龙地址 使用 format格式化自定义端口 - payload = { - 'username': username, - 'password': password - } # HTTP请求载荷 - payload = json.dumps(payload) # json格式化载荷 - headers = { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - } # HTTP请求头 设置为 Json格式 - try: # 异常捕捉 - # 使用 requests模块进行 HTTP POST请求 - res = requests.post(url=url, headers=headers, data=payload) - # 从 res.text 返回值中 取出 Token值 - token = json.loads(res.text)["data"]['token'] - except Exception as err: # 异常捕捉 + try: + res = requests.post(url=url, headers=headers, json=body) # 使用 requests模块进行 HTTP POST请求 + token = json.loads(res.text)["data"]['token'] # 从 res.text 返回值中 取出 Token值 + except Exception as err: logger.debug(str(err)) # Debug日志输出 logger.info("青龙登录失败, 请检查面板状态!") # 标准日志输出 ql_send('青龙登陆失败, 请检查面板状态.') @@ -236,7 +140,7 @@ def get_qltoken(username, password, twoFactorSecret): # 方法 用于获取青 # 返回值 Token -def ql_login(): # 方法 青龙登录(获取Token 功能同上) +def ql_login() -> str: # 方法 青龙登录(获取Token 功能同上) path = '/ql/config/auth.json' # 设置青龙 auth文件地址 if not os.path.isfile(path): path = '/ql/data/config/auth.json' # 尝试设置青龙 auth 新版文件地址 @@ -254,60 +158,57 @@ def ql_login(): # 方法 青龙登录(获取Token 功能同上) logger.debug(str(err)) # Debug日志输出 twoFactorSecret = '' if token == '': # 判断 Token是否为空 - # 调用方法 get_qltoken 传递 username & password - return get_qltoken(username, password, twoFactorSecret) - else: # 判断分支 + return get_qltoken(username, password, twoFactorSecret) # 调用方法 get_qltoken 传递 username & password + else: url = ql_url + 'api/user' # 设置URL请求地址 使用 Format格式化端口 headers = { 'Authorization': 'Bearer {0}'.format(token), 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36 Edg/94.0.992.38' } # 设置用于 HTTP头 - # 调用 request模块发送 get请求 - res = requests.get(url=url, headers=headers) + res = requests.get(url=url, headers=headers) # 调用 request模块发送 get请求 if res.status_code == 200: # 判断 HTTP返回状态码 return token # 有效 返回 token - else: # 判断分支 - # 调用方法 get_qltoken 传递 username & password - return get_qltoken(username, password, twoFactorSecret) - else: # 判断分支 + else: + return get_qltoken(username, password, twoFactorSecret) # 调用方法 get_qltoken 传递 username & password + else: logger.info("没有发现auth文件, 你这是青龙吗???") # 输出标准日志 sys.exit(0) # 脚本退出 # 返回值 list[wskey] -def get_wskey(): # 方法 获取 wskey值 [系统变量传递] +def get_wskey() -> list: # 方法 获取 wskey值 [系统变量传递] if "JD_WSCK" in os.environ: # 判断 JD_WSCK是否存在于环境变量 wskey_list = os.environ['JD_WSCK'].split('&') # 读取系统变量 以 & 分割变量 if len(wskey_list) > 0: # 判断 WSKEY 数量 大于 0 个 return wskey_list # 返回 WSKEY [LIST] - else: # 判断分支 + else: logger.info("JD_WSCK变量未启用") # 标准日志输出 sys.exit(1) # 脚本退出 - else: # 判断分支 + else: logger.info("未添加JD_WSCK变量") # 标准日志输出 sys.exit(0) # 脚本退出 # 返回值 list[jd_cookie] -def get_ck(): # 方法 获取 JD_COOKIE值 [系统变量传递] +def get_ck() -> list: # 方法 获取 JD_COOKIE值 [系统变量传递] if "JD_COOKIE" in os.environ: # 判断 JD_COOKIE是否存在于环境变量 ck_list = os.environ['JD_COOKIE'].split('&') # 读取系统变量 以 & 分割变量 if len(ck_list) > 0: # 判断 WSKEY 数量 大于 0 个 return ck_list # 返回 JD_COOKIE [LIST] - else: # 判断分支 + else: logger.info("JD_COOKIE变量未启用") # 标准日志输出 sys.exit(1) # 脚本退出 - else: # 判断分支 + else: logger.info("未添加JD_COOKIE变量") # 标准日志输出 sys.exit(0) # 脚本退出 # 返回值 bool -def check_ck(ck): # 方法 检查 Cookie有效性 使用变量传递 单次调用 +def check_ck(ck) -> bool: # 方法 检查 Cookie有效性 使用变量传递 单次调用 searchObj = re.search(r'pt_pin=([^;\s]+)', ck, re.M | re.I) # 正则检索 pt_pin if searchObj: # 真值判断 pin = searchObj.group(1) # 取值 - else: # 判断分支 + else: pin = ck.split(";")[1] # 取值 使用 ; 分割 if "WSKEY_UPDATE_HOUR" in os.environ: # 判断 WSKEY_UPDATE_HOUR是否存在于环境变量 updateHour = 23 # 更新间隔23小时 @@ -315,68 +216,59 @@ def check_ck(ck): # 方法 检查 Cookie有效性 使用变量传递 单次调 updateHour = int(os.environ["WSKEY_UPDATE_HOUR"]) # 使用 int化数字 nowTime = time.time() # 获取时间戳 赋值 updatedAt = 0.0 # 赋值 - searchObj = re.search( - r'__time=([^;\s]+)', ck, re.M | re.I) # 正则检索 [__time=] + searchObj = re.search(r'__time=([^;\s]+)', ck, re.M | re.I) # 正则检索 [__time=] if searchObj: # 真值判断 updatedAt = float(searchObj.group(1)) # 取值 [float]类型 if nowTime - updatedAt >= (updateHour * 60 * 60) - (10 * 60): # 判断时间操作 logger.info(str(pin) + ";即将到期或已过期\n") # 标准日志输出 return False # 返回 Bool类型 False - else: # 判断分支 - remainingTime = (updateHour * 60 * 60) - \ - (nowTime - updatedAt) # 时间运算操作 + else: + remainingTime = (updateHour * 60 * 60) - (nowTime - updatedAt) # 时间运算操作 hour = int(remainingTime / 60 / 60) # 时间运算操作 [int] minute = int((remainingTime % 3600) / 60) # 时间运算操作 [int] - logger.info( - str(pin) + ";未到期,{0}时{1}分后更新\n".format(hour, minute)) # 标准日志输出 + logger.info(str(pin) + ";未到期,{0}时{1}分后更新\n".format(hour, minute)) # 标准日志输出 return True # 返回 Bool类型 True - elif "WSKEY_DISCHECK" in os.environ: # 判断分支 WSKEY_DISCHECK 是否存在于系统变量 + elif "WSKEY_DISCHECK" in os.environ: logger.info("不检查账号有效性\n--------------------\n") # 标准日志输出 return False # 返回 Bool类型 False - else: # 判断分支 + else: url = 'https://me-api.jd.com/user_new/info/GetJDUserInfoUnion' # 设置JD_API接口地址 headers = { 'Cookie': ck, 'Referer': 'https://home.m.jd.com/myJd/home.action', 'user-agent': ua } # 设置 HTTP头 - try: # 异常捕捉 - res = requests.get(url=url, headers=headers, verify=False, proxies={"http": proxys, "https": proxys}, - timeout=10, allow_redirects=False) # 进行 HTTP请求[GET] 超时 10秒 - except Exception as err: # 异常捕捉 + try: + res = requests.get(url=url, headers=headers, verify=False, timeout=10, allow_redirects=False) # 进行 HTTP请求[GET] 超时 10秒 + except Exception as err: logger.debug(str(err)) # 调试日志输出 logger.info("JD接口错误 请重试或者更换IP") # 标准日志输出 return False # 返回 Bool类型 False - else: # 判断分支 + else: if res.status_code == 200: # 判断 JD_API 接口是否为 200 [HTTP_OK] - # 使用 Json模块对返回数据取值 int([retcode]) - code = int(json.loads(res.text)['retcode']) + code = int(json.loads(res.text)['retcode']) # 使用 Json模块对返回数据取值 int([retcode]) if code == 0: # 判断 code值 logger.info(str(pin) + ";状态正常\n") # 标准日志输出 return True # 返回 Bool类型 True - else: # 判断分支 + else: logger.info(str(pin) + ";状态失效\n") return False # 返回 Bool类型 False - else: # 判断分支 + else: logger.info("JD接口错误码: " + str(res.status_code)) # 标注日志输出 return False # 返回 Bool类型 False # 返回值 bool jd_ck -def getTokenx(wskey): # 方法 获取 Wskey转换使用的 Token 由 JD_API 返回 这里传递 wskey - if flag == 'bak': - return getToken_bak(wskey) - try: # 异常捕捉 - url = str(base64.b64decode(url_t).decode()) + \ - 'api/genToken' # 设置云端服务器地址 路由为 genToken +def getToken(wskey): # 方法 获取 Wskey转换使用的 Token 由 JD_API 返回 这里传递 wskey + try: + url = str(base64.b64decode(url_t).decode()) + 'api/genToken' # 设置云端服务器地址 路由为 genToken header = {"User-Agent": ua} # 设置 HTTP头 - # 设置 HTTP请求参数 超时 20秒 Json解析 - params = requests.get(url=url, headers=header, - verify=False, timeout=20).json() - except Exception as err: # 异常捕捉 + params = requests.get(url=url, headers=header, verify=False, timeout=20).json() # 设置 HTTP请求参数 超时 20秒 Json解析 + except Exception as err: logger.info("Params参数获取失败") # 标准日志输出 logger.debug(str(err)) # 调试日志输出 - return False, wskey # 返回 -> False[Bool], Wskey + # return False, wskey # 返回 -> False[Bool], Wskey + return False # 返回 -> False[Bool], Wskey headers = { 'cookie': wskey, 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', @@ -386,67 +278,27 @@ def getTokenx(wskey): # 方法 获取 Wskey转换使用的 Token 由 JD_API 返 } # 设置 HTTP头 url = 'https://api.m.jd.com/client.action' # 设置 URL地址 data = 'body=%7B%22to%22%3A%22https%253a%252f%252fplogin.m.jd.com%252fjd-mlogin%252fstatic%252fhtml%252fappjmp_blank.html%22%7D&' # 设置 POST 载荷 - try: # 异常捕捉 + try: res = requests.post(url=url, params=params, headers=headers, data=data, verify=False, timeout=10) # HTTP请求 [POST] 超时 10秒 res_json = json.loads(res.text) # Json模块 取值 tokenKey = res_json['tokenKey'] # 取出TokenKey - except Exception as err: # 异常捕捉 + except Exception as err: logger.info("JD_WSKEY接口抛出错误 尝试重试 更换IP") # 标准日志输出 logger.info(str(err)) # 标注日志输出 - return False, wskey # 返回 -> False[Bool], Wskey - else: # 判断分支 + # return False, wskey # 返回 -> False[Bool], Wskey + return False # 返回 -> False[Bool], Wskey + else: return appjmp(wskey, tokenKey) # 传递 wskey, Tokenkey 执行方法 [appjmp] -# 备用 - - -def getToken(wskey): # 方法 获取 Wskey转换使用的 Token 由 JD_API 返回 这里传递 wskey - try: # 异常捕捉 - # 设置云端服务器地址 路由为 genToken - url = str(base64.b64decode( - 'aHR0cHM6Ly82ZHkuamRwcm8uc2l0ZS8=').decode()) + 'sign' - header = {"Content-Type": "application/json"} # 设置 HTTP头 - data = {'body': { - "to": "https%3a%2f%2fplogin.m.jd.com%2fjd-mlogin%2fstatic%2fhtml%2fappjmp_blank.html"}, 'fn': 'genToken'} - params = requests.post(url=url, headers=header, json=data, - verify=False, timeout=20).json() # 设置 HTTP请求参数 超时 20秒 Json解析 - params = 'functionId=genToken&'+params['body'] - except Exception as err: # 异常捕捉 - logger.info("Params参数获取失败") # 标准日志输出 - logger.debug(str(err)) # 调试日志输出 - return False, wskey # 返回 -> False[Bool], Wskey - headers = { - 'cookie': wskey, - 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', - 'charset': 'UTF-8', - 'accept-encoding': 'br,gzip,deflate', - 'user-agent': ua - } # 设置 HTTP头 - url = 'https://api.m.jd.com/client.action' # 设置 URL地址 - data = 'body=%7B%22to%22%3A%22https%253a%252f%252fplogin.m.jd.com%252fjd-mlogin%252fstatic%252fhtml%252fappjmp_blank.html%22%7D&' # 设置 POST 载荷 - try: # 异常捕捉 - res = requests.post(url=url, params=params, headers=headers, data=data, verify=False, proxies={"http": proxys, "https": proxys}, - timeout=10) # HTTP请求 [POST] 超时 10秒 - res_json = json.loads(res.text) # Json模块 取值 - tokenKey = res_json['tokenKey'] # 取出TokenKey - except Exception as err: # 异常捕捉 - logger.info("JD_WSKEY接口抛出错误 尝试重试 更换IP") # 标准日志输出 - logger.info(str(err)) # 标注日志输出 - return False, wskey # 返回 -> False[Bool], Wskey - - else: # 判断分支 - return appjmp(wskey, tokenKey) # 传递 wskey, Tokenkey 执行方法 [appjmp] # 返回值 bool jd_ck - - def appjmp(wskey, tokenKey): # 方法 传递 wskey & tokenKey wskey = "pt_" + str(wskey.split(";")[0]) # 变量组合 使用 ; 分割变量 拼接 pt_ if tokenKey == 'xxx': # 判断 tokenKey返回值 - logger.info( - str(wskey) + ";疑似IP风控等问题 默认为失效\n--------------------\n") # 标准日志输出 - return False, wskey # 返回 -> False[Bool], Wskey + logger.info(str(wskey) + ";疑似IP风控等问题 默认为失效\n--------------------\n") # 标准日志输出 + # return False, wskey # 返回 -> False[Bool], Wskey + return False # 返回 -> False[Bool], Wskey headers = { 'User-Agent': ua, 'accept': '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.9', @@ -457,34 +309,38 @@ def appjmp(wskey, tokenKey): # 方法 传递 wskey & tokenKey 'to': 'https://plogin.m.jd.com/jd-mlogin/static/html/appjmp_blank.html' } # 设置 HTTP_URL 参数 url = 'https://un.m.jd.com/cgi-bin/app/appjmp' # 设置 URL地址 - try: # 异常捕捉 - res = requests.get(url=url, headers=headers, params=params, verify=False, proxies={ - "http": proxys, "https": proxys}, allow_redirects=False, timeout=20) # HTTP请求 [GET] 阻止跳转 超时 20秒 - except Exception as err: # 异常捕捉 + try: + res = requests.get(url=url, headers=headers, params=params, verify=False, allow_redirects=False, + timeout=20) # HTTP请求 [GET] 阻止跳转 超时 20秒 + except Exception as err: logger.info("JD_appjmp 接口错误 请重试或者更换IP\n") # 标准日志输出 logger.info(str(err)) # 标准日志输出 - return False, wskey # 返回 -> False[Bool], Wskey - else: # 判断分支 - try: # 异常捕捉 + # return False, wskey # 返回 -> False[Bool], Wskey + return False # 返回 -> False[Bool], Wskey + else: + try: res_set = res.cookies.get_dict() # 从res cookie取出 pt_key = 'pt_key=' + res_set['pt_key'] # 取值 [pt_key] pt_pin = 'pt_pin=' + res_set['pt_pin'] # 取值 [pt_pin] - if "WSKEY_UPDATE_HOUR" in os.environ: # 判断是否在系统变量中启用 WSKEY_UPDATE_HOUR - jd_ck = str(pt_key) + ';' + str(pt_pin) + \ - ';__time=' + str(time.time()) + ';' # 拼接变量 - else: # 判断分支 + # if "WSKEY_UPDATE_HOUR" in os.environ: # 判断是否在系统变量中启用 WSKEY_UPDATE_HOUR + if WSKEY_UPDATE_BOOL: + jd_ck = str(pt_key) + ';' + str(pt_pin) + ';__time=' + str(time.time()) + ';' # 拼接变量 + else: jd_ck = str(pt_key) + ';' + str(pt_pin) + ';' # 拼接变量 - except Exception as err: # 异常捕捉 + except Exception as err: logger.info("JD_appjmp提取Cookie错误 请重试或者更换IP\n") # 标准日志输出 logger.info(str(err)) # 标准日志输出 - return False, wskey # 返回 -> False[Bool], Wskey - else: # 判断分支 + # return False, wskey # 返回 -> False[Bool], Wskey + return False # 返回 -> False[Bool], Wskey + else: if 'fake' in pt_key: # 判断 pt_key中 是否存在fake logger.info(str(wskey) + ";WsKey状态失效\n") # 标准日志输出 - return False, wskey # 返回 -> False[Bool], Wskey - else: # 判断分支 + # return False, wskey # 返回 -> False[Bool], Wskey + return False # 返回 -> False[Bool], Wskey + else: logger.info(str(wskey) + ";WsKey状态正常\n") # 标准日志输出 - return True, jd_ck # 返回 -> True[Bool], jd_ck + # return True, jd_ck # 返回 -> True[Bool], jd_ck + return jd_ck def update(): # 方法 脚本更新模块 @@ -492,7 +348,7 @@ def update(): # 方法 脚本更新模块 if ver >= up_ver: # 判断版本号大小 logger.info("当前脚本版本: " + str(ver)) # 标准日志输出 logger.info("--------------------\n") # 标准日志输出 - else: # 判断分支 + else: logger.info("当前脚本版本: " + str(ver) + "新版本: " + str(up_ver)) # 标准日志输出 logger.info("存在新版本, 请更新脚本后执行") # 标准日志输出 logger.info("--------------------\n") # 标准日志输出 @@ -501,10 +357,31 @@ def update(): # 方法 脚本更新模块 # sys.exit(0) # 退出脚本 [未启用] -def ql_check(port): # 方法 检查青龙端口 +def ql_api(method, api, body=None) -> dict: + headers = { + "Content-Type": "application/json", + "Authorization": f"Bearer {token}" + } + url = ql_url + api + for retry_count in range(3): + try: + if type(body) == dict: + res = ql_session.request(method, url=url, headers=headers, json=body).json() + else: + res = ql_session.request(method, url=url, headers=headers, data=body).json() + except Exception as err: + logger.debug(str(err)) + logger.info(f"\n青龙{api}接口错误,重试次数:{retry_count + 1}") + continue + else: + return res + logger.info(f"\n青龙{api}接口多次重试仍然失败") + sys.exit(1) + +def ql_check(port) -> bool: # 方法 检查青龙端口 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Socket模块初始化 sock.settimeout(2) # 设置端口超时 - try: # 异常捕捉 + try: sock.connect(('127.0.0.1', port)) # 请求端口 except Exception as err: # 捕捉异常 logger.debug(str(err)) # 调试日志输出 @@ -523,264 +400,192 @@ def serch_ck(pin): # 方法 搜索 Pin value = envlist[i]['value'] # 取值['value'] id = envlist[i][ql_id] # 取值 [ql_id](变量) logger.info(str(pin) + "检索成功\n") # 标准日志输出 - return True, value, id # 返回 -> True[Bool], value, id - else: # 判断分支 + # return True, value, id # 返回 -> True[Bool], value, id + return value, id # 返回 -> value, id + else: continue # 继续循环 logger.info(str(pin) + "检索失败\n") # 标准日志输出 - return False, 1 # 返回 -> False[Bool], 1 + return False # 返回 -> False[Bool], 1 def get_env(): # 方法 读取变量 - url = ql_url + 'api/envs' - try: # 异常捕捉 - res = s.get(url) # HTTP请求 [GET] 使用 session - except Exception as err: # 异常捕捉 - logger.debug(str(err)) # 调试日志输出 - logger.info("\n青龙环境接口错误") # 标准日志输出 - sys.exit(1) # 脚本退出 - else: # 判断分支 - data = json.loads(res.text)['data'] # 使用Json模块提取值[data] - return data # 返回 -> data + api = 'api/envs' + res = ql_api("GET", api) + data = res['data'] + return data -def check_id(): # 方法 兼容青龙老版本与新版本 id & _id的问题 - url = ql_url + 'api/envs' - try: # 异常捕捉 - res = s.get(url).json() # HTTP[GET] 请求 使用 session - except Exception as err: # 异常捕捉 - logger.debug(str(err)) # 调试日志输出 - logger.info("\n青龙环境接口错误") # 标准日志输出 - sys.exit(1) # 脚本退出 - else: # 判断分支 - if '_id' in res['data'][0]: # 判断 [_id] - logger.info("使用 _id 键值") # 标准日志输出 - return '_id' # 返回 -> '_id' - else: # 判断分支 - logger.info("使用 id 键值") # 标准日志输出 - return 'id' # 返回 -> 'id' +def check_id() -> str: # 方法 兼容青龙老版本与新版本 id & _id的问题 + api = 'api/envs' + res = ql_api("GET", api) + if '_id' in res['data'][0]: # 判断 [_id] + logger.info("使用 _id 键值") # 标准日志输出 + return '_id' # 返回 -> '_id' + else: + logger.info("使用 id 键值") # 标准日志输出 + return 'id' # 返回 -> 'id' -def ql_update(e_id, n_ck): # 方法 青龙更新变量 传递 id cookie - url = ql_url + 'api/envs' - data = { - "name": "JD_COOKIE", - "value": n_ck, - ql_id: e_id - } # 设置 HTTP POST 载荷 - data = json.dumps(data) # json模块格式化 - s.put(url=url, data=data) # HTTP [PUT] 请求 使用 session - ql_enable(eid) # 调用方法 ql_enable 传递 eid +def ql_update(eid, newck): # 方法 青龙更新变量 传递 id cookie + api = 'api/envs' + body = { + 'name': 'JD_COOKIE', + 'value': newck, + ql_id: eid + } + ql_api("PUT", api, body) + ql_enable(eid) -def ql_enable(e_id): # 方法 青龙变量启用 传递值 eid - url = ql_url + 'api/envs/enable' - data = '["{0}"]'.format(e_id) # 格式化 POST 载荷 - res = json.loads(s.put(url=url, data=data).text) # json模块读取 HTTP[PUT] 的返回值 +def ql_enable(eid): # 方法 青龙变量启用 传递值 eid + api = 'api/envs/enable' + body = f'[{eid}]' + res = ql_api("PUT", api, body) if res['code'] == 200: # 判断返回值为 200 logger.info("\n账号启用\n--------------------\n") # 标准日志输出 - return True # 返回 ->True - else: # 判断分支 + return True + else: logger.info("\n账号启用失败\n--------------------\n") # 标准日志输出 - return False # 返回 -> Fasle + return False -def ql_disable(e_id): # 方法 青龙变量禁用 传递 eid - url = ql_url + 'api/envs/disable' - data = '["{0}"]'.format(e_id) # 格式化 POST 载荷 - res = json.loads(s.put(url=url, data=data).text) # json模块读取 HTTP[PUT] 的返回值 +def ql_disable(eid): # 方法 青龙变量禁用 传递 eid + api = 'api/envs/disable' + body = f'[{eid}]' + res = ql_api("PUT", api, body) if res['code'] == 200: # 判断返回值为 200 logger.info("\n账号禁用成功\n--------------------\n") # 标准日志输出 - return True # 返回 ->True - else: # 判断分支 + else: logger.info("\n账号禁用失败\n--------------------\n") # 标准日志输出 - return False # 返回 -> Fasle def ql_insert(i_ck): # 方法 插入新变量 - data = [{"value": i_ck, "name": "JD_COOKIE"}] # POST数据载荷组合 - data = json.dumps(data) # Json格式化数据 - url = ql_url + 'api/envs' - s.post(url=url, data=data) # HTTP[POST]请求 使用session - logger.info("\n账号添加完成\n--------------------\n") # 标准日志输出 + api = 'api/envs' + body = json.dumps([{"value": i_ck, "name": "JD_COOKIE"}]) + res = ql_api("POST", api, body) + if res['code'] == 200: # 判断返回值为 200 + logger.info("\n账号添加完成\n--------------------\n") # 标准日志输出 + else: + logger.info("\n账号添加失败\n--------------------\n") # 标准日志输出 def cloud_info(): # 方法 云端信息 - url = str(base64.b64decode(url_t).decode()) + \ - 'api/check_api' # 设置 URL地址 路由 [check_api] + url = str(base64.b64decode(url_t).decode()) + 'api/check_api' # 设置 URL地址 路由 [check_api] for i in range(3): # For循环 3次 - try: # 异常捕捉 + try: headers = {"authorization": "Bearer Shizuku"} # 设置 HTTP头 - # HTTP[GET] 请求 超时 20秒 - res = requests.get(url=url, verify=False, - headers=headers, timeout=20).text - except requests.exceptions.ConnectTimeout: # 异常捕捉 + res = requests.get(url=url, verify=False, headers=headers, timeout=20).text # HTTP[GET] 请求 超时 20秒 + except requests.exceptions.ConnectTimeout: logger.info("\n获取云端参数超时, 正在重试!" + str(i)) # 标准日志输出 time.sleep(1) # 休眠 1秒 continue # 循环继续 - except requests.exceptions.ReadTimeout: # 异常捕捉 + except requests.exceptions.ReadTimeout: logger.info("\n获取云端参数超时, 正在重试!" + str(i)) # 标准日志输出 time.sleep(1) # 休眠 1秒 continue # 循环继续 - except Exception as err: # 异常捕捉 + except Exception as err: logger.info("\n未知错误云端, 退出脚本!") # 标准日志输出 logger.debug(str(err)) # 调试日志输出 sys.exit(1) # 脚本退出 - else: # 分支判断 - try: # 异常捕捉 + else: + try: c_info = json.loads(res) # json读取参数 - except Exception as err: # 异常捕捉 + except Exception as err: logger.info("云端参数解析失败") # 标准日志输出 logger.debug(str(err)) # 调试日志输出 sys.exit(1) # 脚本退出 - else: # 分支判断 + else: return c_info # 返回 -> c_info -def check_cloud(): # 方法 云端地址检查 - url_list = ['aHR0cHM6Ly9hcGkubW9tb2UubWwv', 'aHR0cHM6Ly9hcGkubGltb2UuZXUub3JnLw==', - 'aHR0cHM6Ly9hcGkuaWxpeWEuY2Yv'] # URL list Encode - for i in url_list: # for循环 url_list +def check_cloud(): + url_list = ['aHR0cHM6Ly9hcGkubW9tb2UubGluay8=', 'aHR0cHM6Ly9hcGkubGltb2UuZXUub3JnLw==', 'aHR0cHM6Ly9hcGkuaWxpeWEuY2Yv'] + for i in url_list: url = str(base64.b64decode(i).decode()) # 设置 url地址 [str] - try: # 异常捕捉 - # HTTP[GET]请求 超时 10秒 - requests.get(url=url, verify=False, timeout=10) - except Exception as err: # 异常捕捉 + try: + requests.get(url=url, verify=False, timeout=10) # HTTP[GET]请求 超时 10秒 + except Exception as err: logger.debug(str(err)) # 调试日志输出 continue # 循环继续 else: # 分支判断 info = ['HTTPS', 'Eu_HTTPS', 'CloudFlare'] # 输出信息[List] - logger.info(str(info[url_list.index(i)]) + - " Server Check OK\n--------------------\n") # 标准日志输出 + logger.info(str(info[url_list.index(i)]) + " Server Check OK\n--------------------\n") # 标准日志输出 return i # 返回 ->i logger.info("\n云端地址全部失效, 请检查网络!") # 标准日志输出 - # ql_send('云端地址失效. 请联系作者或者检查网络.') # 推送消息 - return 403 - # sys.exit(1) # 脚本退出 + ql_send('云端地址失效. 请联系作者或者检查网络.') # 推送消息 + sys.exit(1) # 脚本退出 def check_port(): # 方法 检查变量传递端口 logger.info("\n--------------------\n") # 标准日志输出 - if "QL_PORT" in os.environ: # 判断 系统变量是否存在[QL_PORT] - try: # 异常捕捉 - port = int(os.environ['QL_PORT']) # 取值 [int] - except Exception as err: # 异常捕捉 - logger.debug(str(err)) # 调试日志输出 - logger.info("变量格式有问题...\n格式: export QL_PORT=\"端口号\"") # 标准日志输出 - logger.info("使用默认端口5700") # 标准日志输出 - return 5700 # 返回端口 5700 - else: # 判断分支 - port = 5700 # 默认5700端口 - if not ql_check(port): # 调用方法 [ql_check] 传递 [port] - logger.info(str( - port) + "端口检查失败, 如果改过端口, 请在变量中声明端口 \n在config.sh中加入 export QL_PORT=\"端口号\"") # 标准日志输出 - logger.info( - "\n如果你很确定端口没错, 还是无法执行, 在GitHub给我发issus\n--------------------\n") # 标准日志输出 - sys.exit(1) # 脚本退出 - else: # 判断分支 + port = int(os.environ.get("QL_PORT", "5700") if str(os.environ.get("QL_PORT")).isdigit() else "5700") + if ql_check(port): # 调用方法 [ql_check] 传递 [port] logger.info(str(port) + "端口检查通过") # 标准日志输出 return port # 返回->port + else: + logger.info(str(port) + "端口检查失败, 如果改过端口, 请在变量中声明端口 \n在config.sh中加入 export QL_PORT=\"端口号\"") # 标准日志输出 + logger.info("\n如果你很确定端口没错, 还是无法执行, 在GitHub给我发issus\n--------------------\n") # 标准日志输出 + sys.exit(1) # 脚本退出 if __name__ == '__main__': # Python主函数执行入口 - proxy_url = os.environ.get("WSKEY_PROXY_URL") or os.environ.get( - "WSKEY_PROXY_TUNNRL") or None - proxys = proxy_url - print("代理池接口:export WSKEY_PROXY_TUNNRL='http://127.0.0.1:123456'") - print("代理API接口(数据格式:txt;提取数量:每次一个):export WSKEY_PROXY_URL='http://xxx.com/apiUrl'") - print("没有代理可以自行注册,比如携趣,巨量,每日免费1000IP,完全够用") - if proxy_url is None: - print("\n\n没有配置代理URL,直连模式!\n环境变量WSKEY_PROXY_TUNNRL或WSKEY_PROXY_URL\n") - print("====================================") - else: - print(f"已配置代理: {proxy_url}\n") port = check_port() # 调用方法 [check_port] 并赋值 [port] - ql_url = 'http://127.0.0.1:{0}/'.format(port) + ql_url = f'http://127.0.0.1:{port}/' + ql_session = requests.session() token = ql_login() # 调用方法 [ql_login] 并赋值 [token] - s = requests.session() # 设置 request session方法 - s.headers.update({"authorization": "Bearer " + str(token)}) # 增加 HTTP头认证 - # 增加 HTTP头 json 类型 - s.headers.update({"Content-Type": "application/json;charset=UTF-8"}) - ql_id = check_id() # 调用方法 [check_id] 并赋值 [ql_id] - # url_t = check_cloud() # 调用方法 [check_cloud] 并赋值 [url_t] - # flag = '' - # if url_t == 403: - # logger.info("\n尝试使用nolan接口请求\n") - # ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36' - # flag = 'bak' - # else: - # cloud_arg = cloud_info() # 调用方法 [cloud_info] 并赋值 [cloud_arg] - # update() # 调用方法 [update] - # ua = cloud_arg['User-Agent'] # 设置全局变量 UA - wslist = get_wskey() # 调用方法 [get_wskey] 并赋值 [wslist] - envlist = get_env() # 调用方法 [get_env] 并赋值 [envlist] - # 判断变量[WSKEY_SLEEP]是否为数字类型 - if "WSKEY_SLEEP" in os.environ and str(os.environ["WSKEY_SLEEP"]).isdigit(): - sleepTime = int(os.environ["WSKEY_SLEEP"]) # 获取变量 [int] - else: # 判断分支 - sleepTime = 10 # 默认休眠时间 10秒 + ql_id = check_id() + url_t = check_cloud() + cloud_arg = cloud_info() + update() + ua = cloud_arg['User-Agent'] + wslist = get_wskey() + envlist = get_env() + sleepTime = int(os.environ.get("WSKEY_SLEEP","10") if str(os.environ.get("WSKEY_SLEEP")).isdigit() else "10") + tryCount = int(os.environ.get("WSKEY_TRY_COUNT","1") if str(os.environ.get("WSKEY_TRY_COUNT")).isdigit() else "1") + WSKEY_UPDATE_BOOL = bool(os.environ.get("WSKEY_UPDATE_HOUR")) + WSKEY_AUTO_DISABLE = bool(os.environ.get("WSKEY_AUTO_DISABLE")) for ws in wslist: # wslist变量 for循环 [wslist -> ws] - ua = getua() - if os.getenv("WSKEY_PROXY_URL"): - proxys = get_proxy_api(proxy_url) wspin = ws.split(";")[0] # 变量分割 ; if "pin" in wspin: # 判断 pin 是否存在于 [wspin] wspin = "pt_" + wspin + ";" # 封闭变量 return_serch = serch_ck(wspin) # 变量 pt_pin 搜索获取 key eid - if return_serch[0]: # bool: True 搜索到账号 - jck = str(return_serch[1]) # 拿到 JD_COOKIE + if return_serch: # bool: True 搜索到账号 + jck, eid = return_serch # 拿到 JD_COOKIE if not check_ck(jck): # bool: False 判定 JD_COOKIE 有效性 - tryCount = 2 # 重试次数 2次 - # 判断 [WSKEY_TRY_COUNT] 是否存在于系统变量 - if "WSKEY_TRY_COUNT" in os.environ: - # 判断 [WSKEY_TRY_COUNT] 是否为数字 - if os.environ["WSKEY_TRY_COUNT"].isdigit(): - # 设置 [tryCount] int - tryCount = int(os.environ["WSKEY_TRY_COUNT"]) for count in range(tryCount): # for循环 [tryCount] count += 1 # 自增 - # 使用 WSKEY 请求获取 JD_COOKIE bool jd_ck - return_ws = getToken(ws) - if return_ws[0]: # 判断 [return_ws]返回值 Bool类型 + return_ws = getToken(ws) # 使用 WSKEY 请求获取 JD_COOKIE bool jd_ck + if return_ws: break # 中断循环 if count < tryCount: # 判断循环次 - logger.info("{0} 秒后重试,剩余次数:{1}\n".format( - sleepTime, tryCount - count)) # 标准日志输出 + logger.info("{0} 秒后重试,剩余次数:{1}\n".format(sleepTime, tryCount - count)) # 标准日志输出 time.sleep(sleepTime) # 脚本休眠 使用变量 [sleepTime] - if os.getenv("WSKEY_PROXY_URL"): - proxys = get_proxy_api(proxy_url) - if return_ws[0]: # 判断 [return_ws]返回值 Bool类型 - # 从 return_ws[1] 取出 -> nt_key - nt_key = str(return_ws[1]) + if return_ws: # 判断 [return_ws]返回值 Bool类型 # logger.info("wskey转pt_key成功", nt_key) # 标准日志输出 [未启用] logger.info("wskey转换成功") # 标准日志输出 - eid = return_serch[2] # 从 return_serch 拿到 eid - ql_update(eid, nt_key) # 函数 ql_update 参数 eid JD_COOKIE - else: # 判断分支 - if "WSKEY_AUTO_DISABLE" in os.environ: # 从系统变量中获取 WSKEY_AUTO_DISABLE + ql_update(eid, return_ws) # 函数 ql_update 参数 eid JD_COOKIE + else: + if WSKEY_AUTO_DISABLE: logger.info(str(wspin) + "账号失效") # 标准日志输出 - text = "账号: {0} WsKey疑似失效".format(wspin) # 设置推送内容 - else: # 判断分支 - eid = return_serch[2] # 读取 return_serch[2] -> eid + text = f"账号: {wspin} WsKey疑似失效" # 设置推送内容 + else: logger.info(str(wspin) + "账号禁用") # 标准日志输出 ql_disable(eid) # 执行方法[ql_disable] 传递 eid - text = "账号: {0} WsKey疑似失效, 已禁用Cookie".format( - wspin) # 设置推送内容 - ql_send(text) - else: # 判断分支 + text = f"账号: {wspin} WsKey疑似失效, 已禁用Cookie" + ql_send(text) + else: logger.info(str(wspin) + "账号有效") # 标准日志输出 - eid = return_serch[2] # 读取 return_serch[2] -> eid ql_enable(eid) # 执行方法[ql_enable] 传递 eid logger.info("--------------------\n") # 标准日志输出 - else: # 判断分支 + else: logger.info("\n新wskey\n") # 标准日志分支 return_ws = getToken(ws) # 使用 WSKEY 请求获取 JD_COOKIE bool jd_ck - if return_ws[0]: # 判断 (return_ws[0]) 类型: [Bool] - nt_key = str(return_ws[1]) # return_ws[1] -> nt_key + if return_ws: # 判断 (return_ws[0]) 类型: [Bool] logger.info("wskey转换成功\n") # 标准日志输出 - ql_insert(nt_key) # 调用方法 [ql_insert] - logger.info("暂停{0}秒\n".format(sleepTime)) # 标准日志输出 + ql_insert(return_ws) # 调用方法 [ql_insert] + logger.info(f"暂停{sleepTime}秒\n") # 标准日志输出 time.sleep(sleepTime) # 脚本休眠 - else: # 判断分支 + else: logger.info("WSKEY格式错误\n--------------------\n") # 标准日志输出 logger.info("执行完成\n--------------------") # 标准日志输出 sys.exit(0) # 脚本退出