363 lines
13 KiB
Python
363 lines
13 KiB
Python
# Source: https://github.com/LinYuanovo/AutoTaskScripts/blob/main/utils/wechatCodeAdapter.py
|
||
# Raw: https://raw.githubusercontent.com/LinYuanovo/AutoTaskScripts/main/utils/wechatCodeAdapter.py
|
||
# Repo: LinYuanovo/AutoTaskScripts
|
||
# Path: utils/wechatCodeAdapter.py
|
||
# UploadedAt: 2025-08-27T15:31:08+08:00
|
||
# SHA256: 36b9c2d8634e456f442d8308b0b552eb86d59b1d65f9c1d0d8c2a8b370b34c3b
|
||
# Category: 微信小程序/协议版
|
||
# Evidence: getMiniProgramCode/wx_cloud/wx_token/code协议链路
|
||
|
||
"""
|
||
作者: 临渊
|
||
日期: 2025/7/22
|
||
name: 微信协议适配器
|
||
变量: soy_wxid_data (微信id) 多个账号用换行分割
|
||
soy_codetoken_data (微信授权token)
|
||
soy_codeurl_data (微信授权url)
|
||
定时: 一天两次
|
||
cron: 10 11,12 * * *
|
||
------------------------------------------------------------
|
||
更新日志:
|
||
2025/7/22 V1.0 初始化
|
||
2025/7/27 V1.1 适配StarBot Pro
|
||
"""
|
||
|
||
import requests
|
||
import os
|
||
import logging
|
||
import traceback
|
||
from datetime import datetime
|
||
|
||
class WechatCodeAdapter:
|
||
def __init__(self, wx_appid):
|
||
"""
|
||
初始化微信授权适配器
|
||
"""
|
||
self.wx_code_url = os.getenv("soy_codeurl_data")
|
||
self.wx_code_token = os.getenv("soy_codetoken_data")
|
||
self.wx_appid = wx_appid # 微信小程序id
|
||
self.wx_protocol_type = 0 # 微信协议类型
|
||
self.wx_accounts_list = [] # 微信账号列表
|
||
self.log_msgs = [] # 日志收集
|
||
self._init_protocol_type()
|
||
self._init_all_accounts()
|
||
self.setup_logging()
|
||
|
||
def setup_logging(self):
|
||
"""
|
||
配置日志系统
|
||
"""
|
||
logging.basicConfig(
|
||
level=logging.INFO,
|
||
format='%(asctime)s - %(levelname)s\t- %(message)s',
|
||
datefmt='%Y-%m-%d %H:%M:%S',
|
||
handlers=[
|
||
# logging.FileHandler(f'{self.script_name}_{datetime.now().strftime("%Y%m%d")}.log', encoding='utf-8'), # 保存日志
|
||
logging.StreamHandler()
|
||
]
|
||
)
|
||
|
||
def log(self, msg, level="info"):
|
||
if level == "info":
|
||
logging.info(msg)
|
||
elif level == "error":
|
||
logging.error(msg)
|
||
elif level == "warning":
|
||
logging.warning(msg)
|
||
self.log_msgs.append(msg)
|
||
|
||
def get_protocol_type(self):
|
||
"""
|
||
获取协议类型
|
||
:return: 协议类型
|
||
"""
|
||
if self.wx_code_url:
|
||
end_url = self.wx_code_url.split("/")[-1]
|
||
else:
|
||
end_url = ""
|
||
if end_url == "getMiniProgramCode":
|
||
# 养鸡场
|
||
return 1
|
||
elif end_url == "code":
|
||
# 牛子
|
||
return 2
|
||
elif end_url == "GetAllDevices":
|
||
# WeChatPadPro
|
||
return 3
|
||
elif end_url == "GetAuthKey":
|
||
# iwechat
|
||
return 4
|
||
elif end_url == "processor":
|
||
# StarBot Pro
|
||
return 5
|
||
else:
|
||
# 其他不知道的协议
|
||
return 0
|
||
|
||
def _init_protocol_type(self):
|
||
"""
|
||
初始化微信协议类型
|
||
"""
|
||
self.wx_protocol_type = self.get_protocol_type()
|
||
|
||
def dict_keys_to_lower(self, obj):
|
||
"""
|
||
递归将字典的所有键名转为小写
|
||
"""
|
||
if isinstance(obj, dict):
|
||
return {k.lower(): self.dict_keys_to_lower(v) for k, v in obj.items()}
|
||
elif isinstance(obj, list):
|
||
return [self.dict_keys_to_lower(i) for i in obj]
|
||
else:
|
||
return obj
|
||
|
||
def get_code_1(self, wx_id):
|
||
"""
|
||
养鸡场 获取code
|
||
:param wx_id: 微信id
|
||
:return: code
|
||
"""
|
||
try:
|
||
url = self.wx_code_url
|
||
headers = {
|
||
"Authorization": self.wx_code_token,
|
||
"Content-Type": "application/json"
|
||
}
|
||
payload = {"wxid": wx_id, "appid": self.wx_appid}
|
||
response = requests.post(url, headers=headers, json=payload, timeout=5)
|
||
response.raise_for_status()
|
||
# 将所有键名转为小写
|
||
response_json = self.dict_keys_to_lower(response.json())
|
||
if response_json['code'] == 200:
|
||
return response_json['data']['code']
|
||
else:
|
||
self.log(f"[微信授权] 失败,错误信息: {response_json.get('msg', '未知错误')}", level="error")
|
||
return False
|
||
except requests.RequestException as e:
|
||
self.log(f"[微信授权]发生网络错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
except Exception as e:
|
||
self.log(f"[微信授权]发生未知错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
|
||
def get_code_2(self, wx_id):
|
||
"""
|
||
牛子 获取code
|
||
:param wx_id: 微信id
|
||
:return: code
|
||
"""
|
||
try:
|
||
url = self.wx_code_url
|
||
headers = {
|
||
"Content-Type": "application/json"
|
||
}
|
||
payload = {"wxid": wx_id, "appid": self.wx_appid}
|
||
response = requests.post(url, headers=headers, json=payload, timeout=5)
|
||
response.raise_for_status()
|
||
# 将所有键名转为小写
|
||
response_json = self.dict_keys_to_lower(response.json())
|
||
# 直接取授权code,不判断返回码code
|
||
code_value = response_json.get('data', {}).get('code', '')
|
||
if code_value:
|
||
code = code_value
|
||
return code
|
||
else:
|
||
self.log(f"[微信授权] 失败,错误信息: {response_json['message']}", level="error")
|
||
return False
|
||
except requests.RequestException as e:
|
||
self.log(f"[微信授权]发生网络错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
except Exception as e:
|
||
self.log(f"[微信授权]发生未知错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
|
||
def _init_all_accounts(self):
|
||
"""
|
||
初始化微信账号列表
|
||
"""
|
||
if self.wx_protocol_type == 3:
|
||
self.wx_accounts_list = self.get_all_devices()
|
||
elif self.wx_protocol_type == 4:
|
||
self.wx_accounts_list = self.get_auth_keys()
|
||
|
||
def get_all_devices(self):
|
||
"""
|
||
WeChatPadPro 获取账号授权码列表
|
||
:return: 账号授权码列表
|
||
"""
|
||
try:
|
||
url = self.wx_code_url
|
||
params = {
|
||
"key": self.wx_code_token
|
||
}
|
||
response = requests.get(url, params=params, timeout=15)
|
||
response.raise_for_status()
|
||
response_json = response.json()
|
||
if response_json.get('Code') == 200:
|
||
all_devices = response_json.get('Data', {}).get('devices', [])
|
||
if all_devices:
|
||
return all_devices
|
||
else:
|
||
self.log(f"[获取账号授权码列表] 返回信息: {response_json['Text']}", level="error")
|
||
return []
|
||
else:
|
||
self.log(f"[获取账号授权码列表] 失败,错误信息: {response_json['Text']}", level="error")
|
||
return []
|
||
except Exception as e:
|
||
self.log(f"[获取账号授权码列表] 发生错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return []
|
||
|
||
def get_target_key_by_wxid(self, all_keys, wx_id):
|
||
"""
|
||
获取指定微信id的授权码
|
||
:param all_keys: 所有账号授权码列表
|
||
:param wx_id: 微信id
|
||
:return: 指定微信id的授权码
|
||
"""
|
||
for key in all_keys:
|
||
_wx_id = key.get('deviceId') or key.get('wx_id')
|
||
if _wx_id == wx_id:
|
||
return key.get('authKey') or key.get('license')
|
||
return None
|
||
|
||
def get_code_3(self, wx_id):
|
||
"""
|
||
WeChatPadPro 获取code
|
||
:param wx_id: 微信id
|
||
:return: code
|
||
"""
|
||
try:
|
||
all_devices = self.wx_accounts_list
|
||
if not all_devices:
|
||
self.log(f"[获取code] 账号列表为空,未能获取到", level="error")
|
||
return False
|
||
target_key = self.get_target_key_by_wxid(all_devices, wx_id)
|
||
url = self.wx_code_url.split("/admin")[0] + "/applet/JsLogin"
|
||
params = {
|
||
"key": target_key
|
||
}
|
||
payload = {
|
||
"AppId": self.wx_appid,
|
||
"Data": "",
|
||
"Opt": 1,
|
||
"PackageName": "",
|
||
"SdkName": ""
|
||
}
|
||
response = requests.post(url, params=params, json=payload, timeout=5)
|
||
response.raise_for_status()
|
||
response_json = response.json()
|
||
if response_json.get('Code') == 200:
|
||
# self.log(f"[获取code] 成功,code: {response_json.get('Data', {}).get('Code', '')}")
|
||
return response_json.get('Data', {}).get('Code', '')
|
||
else:
|
||
self.log(f"[获取code] 失败,错误信息: {response_json['Text']}", level="error")
|
||
return False
|
||
except Exception as e:
|
||
self.log(f"[获取code] 发生错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
|
||
def get_auth_keys(self):
|
||
"""
|
||
iwechat 获取账号授权码列表
|
||
:return: 账号授权码列表
|
||
"""
|
||
try:
|
||
url = self.wx_code_url
|
||
params = {
|
||
"key": self.wx_code_token
|
||
}
|
||
response = requests.get(url, params=params, timeout=15)
|
||
response.raise_for_status()
|
||
response_json = response.json()
|
||
return response_json
|
||
except Exception as e:
|
||
self.log(f"[获取code] 发生错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
|
||
def get_code_4(self, wx_id):
|
||
"""
|
||
iwechat 获取code
|
||
:param wx_id: 微信id
|
||
:return: code
|
||
"""
|
||
try:
|
||
auth_keys = self.wx_accounts_list
|
||
if not auth_keys:
|
||
self.log(f"[获取code] 账号列表为空,未能获取到", level="error")
|
||
return False
|
||
target_key = self.get_target_key_by_wxid(auth_keys, wx_id)
|
||
url = self.wx_code_url.split("/admin")[0] + "/applet/JsLogin"
|
||
params = {
|
||
"key": target_key
|
||
}
|
||
payload = {
|
||
"AppId": self.wx_appid,
|
||
"Data": "",
|
||
"Opt": 1,
|
||
"PackageName": "",
|
||
"SdkName": ""
|
||
}
|
||
response = requests.post(url, params=params, json=payload, timeout=5)
|
||
response.raise_for_status()
|
||
response_json = response.json()
|
||
if response_json.get('Code') == 200:
|
||
self.log(f"[获取code] 成功,code: {response_json.get('Data', {}).get('Code', '')}")
|
||
return response_json.get('Data', {}).get('Code', '')
|
||
else:
|
||
self.log(f"[获取code] 失败,错误信息: {response_json['Text']}", level="error")
|
||
return False
|
||
except Exception as e:
|
||
self.log(f"[获取code] 发生错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
|
||
def get_code_5(self, wx_id):
|
||
"""
|
||
StarBot Pro 获取code
|
||
:param wx_id: 微信id
|
||
:return: code
|
||
"""
|
||
try:
|
||
url = self.wx_code_url
|
||
headers = {
|
||
"Authorization": self.wx_code_token,
|
||
"Content-Type": "application/json"
|
||
}
|
||
payload = {
|
||
"type": "querySmallProgramCode",
|
||
"params": {
|
||
"robotId": wx_id,
|
||
"appid": self.wx_appid
|
||
}
|
||
}
|
||
response = requests.post(url, headers=headers, json=payload, timeout=5)
|
||
response.raise_for_status()
|
||
response_json = response.json()
|
||
if response_json.get('code') == 200:
|
||
return response_json.get('data', {}).get('code', '')
|
||
else:
|
||
self.log(f"[获取code] 失败,错误信息: {response_json['description']}", level="error")
|
||
return False
|
||
except Exception as e:
|
||
self.log(f"[获取code] 发生错误: {str(e)}\n{traceback.format_exc()}", level="error")
|
||
return False
|
||
|
||
def get_code(self, wx_id):
|
||
"""
|
||
获取code
|
||
:param wx_id: 微信id
|
||
:return: 指定wxid的code
|
||
"""
|
||
protocol_type = self.get_protocol_type()
|
||
if protocol_type == 1:
|
||
return self.get_code_1(wx_id)
|
||
elif protocol_type == 2:
|
||
return self.get_code_2(wx_id)
|
||
elif protocol_type == 3:
|
||
return self.get_code_3(wx_id)
|
||
elif protocol_type == 4:
|
||
return self.get_code_4(wx_id)
|
||
elif protocol_type == 5:
|
||
return self.get_code_5(wx_id)
|
||
else:
|
||
self.log(f"[获取code] 发生错误: 未知协议类型", level="error")
|
||
return False |