更新 WX_Applet/Applet_JYHS_DDYX.py
This commit is contained in:
@@ -1,530 +1,469 @@
|
||||
# cron: 2 7 * * *
|
||||
# new Env("旧衣回收_铛铛一下")
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
铛铛一下 - 养鸡场版(自动获取账号 + 自动提现 + 推送通知)
|
||||
直接从养鸡场获取微信账号列表,无需手动配置wxid
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import hashlib
|
||||
import random
|
||||
import time
|
||||
import requests
|
||||
import os
|
||||
import logging
|
||||
import traceback
|
||||
import base64
|
||||
import json
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Random import get_random_bytes
|
||||
from datetime import datetime
|
||||
|
||||
print("=" * 50)
|
||||
print("脚本开始加载...")
|
||||
print("=" * 50)
|
||||
# ====================== 养鸡场配置 ======================
|
||||
WX_TOKEN = os.getenv('wx_token') # 养鸡场 Authorization 令牌
|
||||
wx_cloud = os.getenv('wx_cloud', 'http://192.168.31.203:666') # 养鸡场服务地址
|
||||
# ========================================================
|
||||
|
||||
# ==================== 配置 ====================
|
||||
CHICKEN_FARM_URL = os.getenv("wx_cloud", "http://127.0.0.1:666")
|
||||
CHICKEN_FARM_TOKEN = os.getenv("wx_token", "")
|
||||
WX_APPID = "wxe378d2d7636c180e" # 铛铛一下的appid
|
||||
REMOVE_WXIDS = os.getenv("REMOVE_WXIDS", "") # 需要剔除的wxid,逗号分隔
|
||||
DEFAULT_WITHDRAW_BALANCE = float(os.getenv("WITHDRAW_BALANCE", "0.3")) # 默认超过0.3元提现
|
||||
NOTIFY = os.getenv("LY_NOTIFY", "false").lower() == "true" # 是否推送通知
|
||||
remove_wxids1 = ["wxid_11111111111111"] # 需要剔除的多个wxid
|
||||
DEFAULT_WITHDRAW_BALANCE = 0.3 # 默认超过该金额进行提现,需大于等于0.3
|
||||
MULTI_ACCOUNT_SPLIT = ["\n", "@"] # 分隔符列表
|
||||
MULTI_ACCOUNT_PROXY = False # 是否使用多账号代理,默认不使用,True则使用多账号代理
|
||||
|
||||
print(f"养鸡场地址: {CHICKEN_FARM_URL}")
|
||||
print(f"Token状态: {'已配置' if CHICKEN_FARM_TOKEN else '未配置'}")
|
||||
print(f"提现阈值: {DEFAULT_WITHDRAW_BALANCE}元")
|
||||
print(f"通知推送: {'开启' if NOTIFY else '关闭'}")
|
||||
print(f"AppID: {WX_APPID}")
|
||||
# 微信小程序ID(根据实际业务调整)
|
||||
WX_APPID = "wxe378d2d7636c180e"
|
||||
|
||||
# ==================== 通知模块 ====================
|
||||
def send_notify(title, content):
|
||||
"""发送通知"""
|
||||
if not NOTIFY:
|
||||
return
|
||||
|
||||
try:
|
||||
# 尝试导入notify模块
|
||||
notify_path = "/ql/scripts/notify.py"
|
||||
if os.path.exists(notify_path):
|
||||
sys.path.insert(0, "/ql/scripts")
|
||||
import notify
|
||||
notify.send(title, content)
|
||||
print("[通知] 已发送")
|
||||
else:
|
||||
# 尝试下载notify模块
|
||||
print("[通知] notify.py不存在,尝试下载...")
|
||||
url = "https://raw.githubusercontent.com/whyour/qinglong/refs/heads/develop/sample/notify.py"
|
||||
resp = requests.get(url, timeout=10)
|
||||
with open(notify_path, "w", encoding="utf-8") as f:
|
||||
f.write(resp.text)
|
||||
import notify
|
||||
notify.send(title, content)
|
||||
print("[通知] 已发送")
|
||||
except Exception as e:
|
||||
print(f"[通知] 发送失败: {e}")
|
||||
|
||||
# ==================== 从养鸡场获取账号列表 ====================
|
||||
def get_accounts_from_farm():
|
||||
"""从养鸡场获取微信账号列表"""
|
||||
print("[获取账号] 开始从养鸡场获取账号列表...")
|
||||
|
||||
if not CHICKEN_FARM_TOKEN:
|
||||
print("[获取账号] 错误: 未设置wx_token")
|
||||
return []
|
||||
|
||||
url = f"{CHICKEN_FARM_URL}/prod-api/wechat/wechat/list"
|
||||
headers = {
|
||||
"Authorization": CHICKEN_FARM_TOKEN,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
params = {"pageNum": 1, "pageSize": 1000}
|
||||
|
||||
try:
|
||||
print(f"[获取账号] 请求URL: {url}")
|
||||
resp = requests.get(url, headers=headers, params=params, timeout=10)
|
||||
print(f"[获取账号] 响应状态: {resp.status_code}")
|
||||
result = resp.json()
|
||||
|
||||
if result.get("code") == 200:
|
||||
accounts = result.get("rows", [])
|
||||
print(f"[获取账号] 成功,共获取 {len(accounts)} 个账号")
|
||||
|
||||
# 剔除指定wxid
|
||||
if REMOVE_WXIDS:
|
||||
remove_list = [wxid.strip() for wxid in REMOVE_WXIDS.split(",") if wxid.strip()]
|
||||
accounts = [a for a in accounts if a.get("wxId") not in remove_list]
|
||||
print(f"[获取账号] 剔除后剩余 {len(accounts)} 个账号")
|
||||
|
||||
return accounts
|
||||
else:
|
||||
print(f"[获取账号] 失败: {result.get('msg')}")
|
||||
return []
|
||||
except Exception as e:
|
||||
print(f"[获取账号] 异常: {e}")
|
||||
return []
|
||||
|
||||
# ==================== 从养鸡场获取CODE ====================
|
||||
def get_code_from_farm(wxid: str):
|
||||
"""从养鸡场获取code"""
|
||||
print(f"[获取code] 请求: {wxid}")
|
||||
|
||||
if not CHICKEN_FARM_TOKEN:
|
||||
print("[获取code] 错误: 未设置wx_token")
|
||||
return None
|
||||
|
||||
url = f"{CHICKEN_FARM_URL}/prod-api/wechat/api/getMiniProgramCode"
|
||||
headers = {
|
||||
"Authorization": CHICKEN_FARM_TOKEN,
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
data = {"wxid": wxid, "appid": WX_APPID}
|
||||
|
||||
try:
|
||||
resp = requests.post(url, json=data, headers=headers, timeout=10)
|
||||
result = resp.json()
|
||||
|
||||
if result.get("code") == 200 and result.get("data"):
|
||||
code = result["data"]
|
||||
if isinstance(code, dict):
|
||||
code = code.get("code")
|
||||
print(f"[获取code] 成功: {code[:10]}...")
|
||||
return code
|
||||
else:
|
||||
print(f"[获取code] 失败: {result.get('msg')}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"[获取code] 异常: {e}")
|
||||
return None
|
||||
|
||||
# ==================== 铛铛一下业务接口 ====================
|
||||
def wxlogin(session, code):
|
||||
"""微信登录"""
|
||||
try:
|
||||
url = "https://vues.dd1x.cn/wechat/login"
|
||||
params = {"code": code, "channelId": 154}
|
||||
resp = session.get(url, params=params, timeout=10)
|
||||
result = resp.json()
|
||||
|
||||
if result.get('code') == 0:
|
||||
token = result['data']['token']
|
||||
session.headers["Token"] = token
|
||||
tel = result['data'].get('tel', '未知')
|
||||
if len(tel) > 7:
|
||||
tel = tel[:3] + "****" + tel[-4:]
|
||||
print(f"[登录] 成功: {tel}")
|
||||
return True, tel
|
||||
else:
|
||||
print(f"[登录] 失败: {result.get('msg')}")
|
||||
return False, None
|
||||
except Exception as e:
|
||||
print(f"[登录] 异常: {e}")
|
||||
return False, None
|
||||
|
||||
def sign_in(session):
|
||||
"""签到"""
|
||||
try:
|
||||
url = "https://vues.dd1x.cn/api/v2/sign_join"
|
||||
resp = session.get(url, timeout=10)
|
||||
result = resp.json()
|
||||
if result.get('code') == 0:
|
||||
print(f"[签到] 成功")
|
||||
return True
|
||||
else:
|
||||
print(f"[签到] 失败: {result.get('msg')}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"[签到] 异常: {e}")
|
||||
return False
|
||||
|
||||
def lottery(session):
|
||||
"""抽奖"""
|
||||
try:
|
||||
url = "https://vues.dd1x.cn/front/activity/update_lottery_result"
|
||||
params = {"id": 3438615}
|
||||
resp = session.get(url, params=params, timeout=10)
|
||||
result = resp.json()
|
||||
if result.get('code') == 0:
|
||||
good_name = result['data']['goodName']
|
||||
print(f"[抽奖] 获得: {good_name}")
|
||||
return True, good_name
|
||||
else:
|
||||
print(f"[抽奖] 失败: {result.get('msg')}")
|
||||
return False, None
|
||||
except Exception as e:
|
||||
print(f"[抽奖] 异常: {e}")
|
||||
return False, None
|
||||
|
||||
def add_lottery_count(session):
|
||||
"""增加抽奖次数"""
|
||||
try:
|
||||
url = "https://vues.dd1x.cn/front/activity/add_lottery_count"
|
||||
resp = session.get(url, timeout=10)
|
||||
result = resp.json()
|
||||
if result.get('code') == 0:
|
||||
print(f"[增加次数] 成功")
|
||||
return True
|
||||
elif "达到上限" in result.get('msg', ''):
|
||||
print(f"[增加次数] 已达上限")
|
||||
return False
|
||||
else:
|
||||
print(f"[增加次数] 失败: {result.get('msg')}")
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def get_withdrawal_info(session):
|
||||
"""获取提现相关信息(余额和可提现列表)"""
|
||||
try:
|
||||
url = "https://vues.dd1x.cn/api/h/get_withdrawal_trade_list"
|
||||
resp = session.get(url, timeout=10)
|
||||
result = resp.json()
|
||||
if result.get('code') == 0 and result.get('data'):
|
||||
data_list = result['data']
|
||||
if data_list:
|
||||
balance = data_list[0].get('money', 0)
|
||||
print(f"[余额] {balance}元")
|
||||
return balance, data_list
|
||||
except Exception as e:
|
||||
print(f"[余额] 获取失败: {e}")
|
||||
return 0, None
|
||||
|
||||
def withdraw(session, total_money, withdrawal_list):
|
||||
"""执行提现"""
|
||||
try:
|
||||
url = "https://vues.dd1x.cn/api/h/withdrawal"
|
||||
payload = {
|
||||
"totalMoney": total_money,
|
||||
"type": 1,
|
||||
"withdrawalDetailPojoList": withdrawal_list
|
||||
}
|
||||
resp = session.post(url, json=payload, timeout=10)
|
||||
result = resp.json()
|
||||
if result.get('code') == 0:
|
||||
print(f"[提现] 成功!提现 {total_money} 元")
|
||||
return True, result.get('msg', '提现成功')
|
||||
else:
|
||||
print(f"[提现] 失败: {result.get('msg')}")
|
||||
return False, result.get('msg')
|
||||
except Exception as e:
|
||||
print(f"[提现] 异常: {e}")
|
||||
return False, str(e)
|
||||
|
||||
# ==================== 抽奖循环 ====================
|
||||
def do_lottery_loop(session, max_rounds=3):
|
||||
class WXBizDataCryptUtil:
|
||||
"""
|
||||
执行抽奖循环
|
||||
返回中奖记录列表
|
||||
微信小程序加解密工具
|
||||
"""
|
||||
prizes = []
|
||||
def __init__(self, sessionKey):
|
||||
self.sessionKey = sessionKey
|
||||
|
||||
# 先抽3次
|
||||
for i in range(3):
|
||||
success, prize = lottery(session)
|
||||
if success and prize:
|
||||
prizes.append(prize)
|
||||
time.sleep(random.randint(2, 4))
|
||||
|
||||
# 增加抽奖次数并继续抽
|
||||
for i in range(max_rounds):
|
||||
if not add_lottery_count(session):
|
||||
break
|
||||
time.sleep(random.randint(1, 2))
|
||||
success, prize = lottery(session)
|
||||
if success and prize:
|
||||
prizes.append(prize)
|
||||
time.sleep(random.randint(2, 4))
|
||||
|
||||
return prizes
|
||||
|
||||
# ==================== 单个账号执行 ====================
|
||||
def run_account(account, idx, total, results):
|
||||
"""执行单个账号的任务"""
|
||||
wxid = account.get("wxId")
|
||||
name = account.get("wxName", wxid)
|
||||
|
||||
print(f"\n{'='*40}")
|
||||
print(f"账号 {idx}/{total}: {name} ({wxid})")
|
||||
print(f"{'='*40}")
|
||||
|
||||
# 记录结果
|
||||
account_result = {
|
||||
"index": idx,
|
||||
"name": name,
|
||||
"wxid": wxid,
|
||||
"success": False,
|
||||
"phone": "",
|
||||
"sign_success": False,
|
||||
"lottery_count": 0,
|
||||
"prizes": [],
|
||||
"balance": 0,
|
||||
"withdrawn": False,
|
||||
"withdraw_amount": 0,
|
||||
"error_msg": ""
|
||||
}
|
||||
|
||||
# 1. 获取code
|
||||
code = get_code_from_farm(wxid)
|
||||
if not code:
|
||||
print(f"❌ 获取code失败,跳过账号")
|
||||
account_result["error_msg"] = "获取code失败"
|
||||
results.append(account_result)
|
||||
return
|
||||
|
||||
# 2. 创建session
|
||||
session = requests.Session()
|
||||
session.headers["User-Agent"] = "Mozilla/5.0 (Linux; Android 12) AppleWebKit/537.36"
|
||||
|
||||
# 3. 登录
|
||||
login_success, phone = wxlogin(session, code)
|
||||
if not login_success:
|
||||
account_result["error_msg"] = "登录失败"
|
||||
results.append(account_result)
|
||||
return
|
||||
|
||||
account_result["phone"] = phone
|
||||
time.sleep(random.randint(1, 3))
|
||||
|
||||
# 4. 签到
|
||||
sign_success = sign_in(session)
|
||||
account_result["sign_success"] = sign_success
|
||||
time.sleep(random.randint(1, 3))
|
||||
|
||||
# 5. 抽奖
|
||||
prizes = do_lottery_loop(session, max_rounds=3)
|
||||
if prizes:
|
||||
account_result["prizes"] = prizes
|
||||
account_result["lottery_count"] = len(prizes)
|
||||
print(f"[中奖记录] {', '.join(prizes)}")
|
||||
|
||||
# 6. 获取余额并判断是否提现
|
||||
balance, withdrawal_list = get_withdrawal_info(session)
|
||||
account_result["balance"] = balance
|
||||
|
||||
if balance >= DEFAULT_WITHDRAW_BALANCE and withdrawal_list:
|
||||
print(f"[提现判断] 余额 {balance}元 >= {DEFAULT_WITHDRAW_BALANCE}元,开始提现...")
|
||||
withdraw_success, withdraw_msg = withdraw(session, balance, withdrawal_list)
|
||||
account_result["withdrawn"] = withdraw_success
|
||||
account_result["withdraw_amount"] = balance if withdraw_success else 0
|
||||
account_result["withdraw_msg"] = withdraw_msg
|
||||
else:
|
||||
print(f"[提现判断] 余额 {balance}元 < {DEFAULT_WITHDRAW_BALANCE}元,暂不提现")
|
||||
|
||||
account_result["success"] = True
|
||||
results.append(account_result)
|
||||
print(f"\n✅ 账号 {idx} 执行完成")
|
||||
|
||||
# ==================== 生成通知内容 ====================
|
||||
def build_notify_content(results):
|
||||
"""生成详细的通知内容"""
|
||||
total = len(results)
|
||||
success = sum(1 for r in results if r.get("success"))
|
||||
fail = total - success
|
||||
|
||||
total_withdrawn = sum(1 for r in results if r.get("withdrawn"))
|
||||
total_withdraw_amount = sum(r.get("withdraw_amount", 0) for r in results)
|
||||
total_balance = sum(r.get("balance", 0) for r in results)
|
||||
|
||||
# 统计中奖
|
||||
all_prizes = []
|
||||
prize_count = {}
|
||||
for r in results:
|
||||
for prize in r.get("prizes", []):
|
||||
all_prizes.append(prize)
|
||||
prize_count[prize] = prize_count.get(prize, 0) + 1
|
||||
|
||||
# 计算成功率
|
||||
success_rate = (success / total * 100) if total > 0 else 0
|
||||
|
||||
# 构建通知内容
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
content = f"""
|
||||
╔══════════════════════════════════════════════════════════╗
|
||||
║ 铛铛一下 执行报告 ║
|
||||
║ {now} ║
|
||||
╚══════════════════════════════════════════════════════════╝
|
||||
|
||||
📊 整体统计
|
||||
──────────────────────────────────────────────────────────
|
||||
总账号数 : {total}
|
||||
成功账号 : {success}
|
||||
失败账号 : {fail}
|
||||
成功率 : {success_rate:.1f}%
|
||||
|
||||
💰 收益统计
|
||||
──────────────────────────────────────────────────────────
|
||||
当前总余额 : {total_balance:.2f} 元
|
||||
本次提现总额 : {total_withdraw_amount:.2f} 元
|
||||
提现账号数 : {total_withdrawn}
|
||||
|
||||
🎁 中奖统计
|
||||
──────────────────────────────────────────────────────────
|
||||
总中奖次数 : {len(all_prizes)}
|
||||
"""
|
||||
|
||||
if prize_count:
|
||||
content += "\n奖品明细:\n"
|
||||
for prize, count in prize_count.items():
|
||||
content += f" • {prize}: {count}次\n"
|
||||
|
||||
content += """
|
||||
📋 账号详情
|
||||
──────────────────────────────────────────────────────────
|
||||
"""
|
||||
|
||||
for r in results:
|
||||
status = "✅" if r.get("success") else "❌"
|
||||
content += f"\n{status} 【账号{r['index']}】{r['name']}\n"
|
||||
if r.get("phone"):
|
||||
content += f" 手机号: {r['phone']}\n"
|
||||
if r.get("sign_success"):
|
||||
content += f" 签到: 成功\n"
|
||||
def encrypt(self, data, iv=None):
|
||||
"""
|
||||
data: dict或str,若为dict自动转为json字符串
|
||||
iv: base64字符串,若为None自动生成
|
||||
返回: (加密数据base64, iv base64)
|
||||
"""
|
||||
if isinstance(data, dict):
|
||||
data = json.dumps(data, separators=(',', ':'))
|
||||
if iv is None:
|
||||
iv_bytes = get_random_bytes(16)
|
||||
iv = base64.b64encode(iv_bytes).decode('utf-8')
|
||||
else:
|
||||
content += f" 签到: 失败\n"
|
||||
if r.get("prizes"):
|
||||
content += f" 中奖: {', '.join(r['prizes'])}\n"
|
||||
else:
|
||||
content += f" 中奖: 无\n"
|
||||
content += f" 余额: {r.get('balance', 0):.2f}元\n"
|
||||
if r.get("withdrawn"):
|
||||
content += f" 提现: ✅ 成功 {r.get('withdraw_amount', 0):.2f}元\n"
|
||||
elif r.get("balance", 0) >= DEFAULT_WITHDRAW_BALANCE:
|
||||
content += f" 提现: ❌ 失败 ({r.get('withdraw_msg', '未知错误')})\n"
|
||||
else:
|
||||
content += f" 提现: 未达到阈值({DEFAULT_WITHDRAW_BALANCE}元)\n"
|
||||
if r.get("error_msg"):
|
||||
content += f" 错误: {r['error_msg']}\n"
|
||||
iv_bytes = base64.b64decode(iv)
|
||||
sessionKey = base64.b64decode(self.sessionKey)
|
||||
cipher = AES.new(sessionKey, AES.MODE_CBC, iv_bytes)
|
||||
padded = self._pad(data.encode('utf-8'))
|
||||
encrypted = cipher.encrypt(padded)
|
||||
encrypted_b64 = base64.b64encode(encrypted).decode('utf-8')
|
||||
return encrypted_b64, iv
|
||||
|
||||
content += """
|
||||
══════════════════════════════════════════════════════════
|
||||
"""
|
||||
|
||||
return content
|
||||
|
||||
# ==================== 打印控制台汇总 ====================
|
||||
def print_summary(results):
|
||||
"""在控制台打印汇总"""
|
||||
print("\n" + "=" * 60)
|
||||
print(" 执行汇总")
|
||||
print("=" * 60)
|
||||
|
||||
total = len(results)
|
||||
success = sum(1 for r in results if r.get("success"))
|
||||
total_balance = sum(r.get("balance", 0) for r in results)
|
||||
total_withdraw = sum(r.get("withdraw_amount", 0) for r in results)
|
||||
|
||||
print(f"\n📊 统计信息:")
|
||||
print(f" 总账号: {total}")
|
||||
print(f" 成功: {success}")
|
||||
print(f" 失败: {total - success}")
|
||||
print(f" 总余额: {total_balance:.2f}元")
|
||||
print(f" 本次提现: {total_withdraw:.2f}元")
|
||||
|
||||
print(f"\n📋 账号详情:")
|
||||
print("-" * 60)
|
||||
for r in results:
|
||||
status = "✅" if r.get("success") else "❌"
|
||||
prizes_str = ", ".join(r.get("prizes", [])) if r.get("prizes") else "无"
|
||||
print(f"{status} {r['name']}: {r.get('balance', 0):.2f}元 | 中奖: {prizes_str}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
|
||||
# ==================== 主程序 ====================
|
||||
def run():
|
||||
print("=" * 50)
|
||||
print("铛铛一下 - 养鸡场版(自动获取账号 + 自动提现 + 推送通知)")
|
||||
print(f"时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("=" * 50)
|
||||
|
||||
# 检查环境变量
|
||||
if not CHICKEN_FARM_TOKEN:
|
||||
print("❌ 请设置环境变量 wx_token")
|
||||
if NOTIFY:
|
||||
send_notify("铛铛一下 - 执行失败", "未设置 wx_token 环境变量")
|
||||
return
|
||||
|
||||
# 从养鸡场获取账号列表
|
||||
accounts = get_accounts_from_farm()
|
||||
if not accounts:
|
||||
print("❌ 未获取到任何微信账号")
|
||||
if NOTIFY:
|
||||
send_notify("铛铛一下 - 执行失败", "未获取到任何微信账号")
|
||||
return
|
||||
|
||||
print(f"\n共 {len(accounts)} 个账号\n")
|
||||
|
||||
# 存储结果
|
||||
results = []
|
||||
|
||||
# 遍历执行每个账号
|
||||
for idx, account in enumerate(accounts, 1):
|
||||
def decrypt(self, encryptedData, iv):
|
||||
"""
|
||||
encryptedData: base64字符串
|
||||
iv: base64字符串
|
||||
返回: dict或str
|
||||
"""
|
||||
sessionKey = base64.b64decode(self.sessionKey)
|
||||
encryptedData = base64.b64decode(encryptedData)
|
||||
iv = base64.b64decode(iv)
|
||||
cipher = AES.new(sessionKey, AES.MODE_CBC, iv)
|
||||
decrypted = self._unpad(cipher.decrypt(encryptedData))
|
||||
try:
|
||||
run_account(account, idx, len(accounts), results)
|
||||
# 账号间延迟
|
||||
if idx < len(accounts):
|
||||
delay = random.randint(3, 8)
|
||||
print(f"\n⏳ 等待 {delay} 秒后执行下一个账号...")
|
||||
time.sleep(delay)
|
||||
return json.loads(decrypted)
|
||||
except Exception:
|
||||
return decrypted.decode('utf-8')
|
||||
|
||||
def _pad(self, s):
|
||||
pad_len = 16 - len(s) % 16
|
||||
return s + bytes([pad_len] * pad_len)
|
||||
|
||||
def _unpad(self, s):
|
||||
return s[:-s[-1]]
|
||||
|
||||
class AutoTask:
|
||||
def __init__(self, site_name):
|
||||
"""
|
||||
初始化自动任务类
|
||||
:param site_name: 站点名称,用于日志显示
|
||||
"""
|
||||
self.site_name = site_name
|
||||
self.proxy_url = os.getenv("PROXY_API_URL") # 代理api,返回一条txt文本,内容为代理ip:端口
|
||||
self.wx_appid = WX_APPID # 微信小程序id
|
||||
self.host = "vues.dd1x.cn"
|
||||
self.user_agent = "Mozilla/5.0 (Linux; Android 12; M2012K11AC Build/SKQ1.220303.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/134.0.6998.136 Mobile Safari/537.36 XWEB/1340129 MMWEBSDK/20240301 MMWEBID/9871 MicroMessenger/8.0.48.2580(0x28003036) WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 MiniProgramEnv/android"
|
||||
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.StreamHandler()
|
||||
]
|
||||
)
|
||||
|
||||
def get_proxy(self):
|
||||
"""
|
||||
获取代理
|
||||
:return: 代理
|
||||
"""
|
||||
if not self.proxy_url:
|
||||
logging.warning("[获取代理]没有找到环境变量PROXY_API_URL,不使用代理")
|
||||
return None
|
||||
url = self.proxy_url
|
||||
response = requests.get(url)
|
||||
proxy = response.text.strip() # 去除首尾空格和换行
|
||||
logging.info(f"[获取代理]: {proxy}")
|
||||
return proxy
|
||||
|
||||
def check_proxy(self, proxy, session):
|
||||
"""
|
||||
检查代理
|
||||
:param proxy: 代理
|
||||
:param session: session
|
||||
:return: 是否可用
|
||||
"""
|
||||
try:
|
||||
url = f"http://{self.host}/api/v2/get_sign_list"
|
||||
session.headers["Token"] = ""
|
||||
response = session.get(url, timeout=5)
|
||||
if response.status_code == 200:
|
||||
logging.info(f"[检查代理]: {proxy} 应该可用")
|
||||
return True
|
||||
else:
|
||||
logging.info(f"[检查代理]: {response.text}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 账号执行异常: {e}")
|
||||
results.append({
|
||||
"index": idx,
|
||||
"name": account.get("wxName", account.get("wxId")),
|
||||
"success": False,
|
||||
"error_msg": str(e)
|
||||
})
|
||||
continue
|
||||
logging.error(f"[检查代理]代理 {proxy} 不可用: {str(e)}")
|
||||
return False
|
||||
|
||||
# 打印控制台汇总
|
||||
print_summary(results)
|
||||
def get_wechat_account_list(self):
|
||||
"""
|
||||
从养鸡场接口获取账号列表
|
||||
:return: 账号列表/False
|
||||
"""
|
||||
try:
|
||||
if not WX_TOKEN:
|
||||
logging.error("[获取账号列表]未设置环境变量 wx_token")
|
||||
return False
|
||||
|
||||
# 发送通知
|
||||
if NOTIFY:
|
||||
success_count = sum(1 for r in results if r.get("success"))
|
||||
total_balance = sum(r.get("balance", 0) for r in results)
|
||||
title = f"铛铛一下 - 执行完成 (成功{success_count}/{len(results)})"
|
||||
content = build_notify_content(results)
|
||||
send_notify(title, content)
|
||||
url = f"{wx_cloud}/prod-api/wechat/wechat/list?pageNum=1&pageSize=1000"
|
||||
headers = {
|
||||
'Authorization': WX_TOKEN,
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
response.raise_for_status()
|
||||
res_data = response.json()
|
||||
|
||||
if res_data and res_data.get('code') == 200 and isinstance(res_data.get('rows'), list):
|
||||
accounts = res_data['rows']
|
||||
logging.info(f"[获取账号列表]成功获取到 {len(accounts)} 个账号")
|
||||
return accounts
|
||||
else:
|
||||
logging.error(f"[获取账号列表]接口返回异常: {json.dumps(res_data)}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[获取账号列表]发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def get_wx_code_yjc(self, wxid):
|
||||
"""
|
||||
使用养鸡场接口获取微信小程序Code
|
||||
:param wxid: 微信ID
|
||||
:return: code/False
|
||||
"""
|
||||
try:
|
||||
if not WX_TOKEN:
|
||||
logging.error("[获取Code]未设置环境变量 wx_token")
|
||||
return False
|
||||
|
||||
url = f"{wx_cloud}/prod-api/wechat/api/getMiniProgramCode"
|
||||
headers = {
|
||||
'Authorization': WX_TOKEN,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
payload = {
|
||||
"wxid": wxid,
|
||||
"appid": self.wx_appid
|
||||
}
|
||||
|
||||
response = requests.post(url, json=payload, headers=headers, timeout=10)
|
||||
response.raise_for_status()
|
||||
res_data = response.json()
|
||||
|
||||
if res_data and res_data.get('code') == 200 and res_data.get('data', {}).get('code'):
|
||||
code = res_data['data']['code']
|
||||
logging.info(f"[获取Code]成功获取 wxid:{wxid} 的code")
|
||||
return code
|
||||
else:
|
||||
logging.error(f"[获取Code]接口返回异常: {json.dumps(res_data)}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[获取Code]wxid:{wxid} 发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def wxlogin(self, session, code):
|
||||
"""
|
||||
登录
|
||||
:param session: session
|
||||
:param code: 微信code
|
||||
:return: 登录结果
|
||||
"""
|
||||
try:
|
||||
url = f"https://{self.host}/wechat/login"
|
||||
params = {
|
||||
"code": code,
|
||||
"channelId": 154
|
||||
}
|
||||
response = session.get(url, params=params, timeout=10)
|
||||
response.raise_for_status()
|
||||
response_json = response.json()
|
||||
|
||||
if response_json.get('code') == 0:
|
||||
tel = response_json['data'].get('tel', '')
|
||||
# 号码中间4位*号代替
|
||||
if tel:
|
||||
tel = tel[:3] + "****" + tel[-4:]
|
||||
logging.info(f"[登录]成功: 当前账号 {tel}")
|
||||
token = response_json['data']['token']
|
||||
session.headers["Token"] = token
|
||||
return True
|
||||
else:
|
||||
logging.error(f"[登录]发生错误: {response_json.get('msg', '未知错误')}")
|
||||
return False
|
||||
except requests.RequestException as e:
|
||||
logging.error(f"[登录]发生网络错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[登录]发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def sign_in(self, session):
|
||||
"""
|
||||
签到
|
||||
:param session: session
|
||||
:return: 签到结果
|
||||
"""
|
||||
try:
|
||||
url = f"https://{self.host}/api/v2/sign_join"
|
||||
response = session.get(url, timeout=10)
|
||||
response.raise_for_status()
|
||||
response_json = response.json()
|
||||
|
||||
if response_json.get('code') == 0:
|
||||
logging.info(f"[签到]: 成功")
|
||||
return True
|
||||
else:
|
||||
logging.warning(f"[签到]: {response_json.get('msg', '未知错误')}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[签到]发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def add_lottery_count(self, session):
|
||||
"""
|
||||
增加抽奖次数
|
||||
:param session: session
|
||||
:return: 增加抽奖次数结果
|
||||
"""
|
||||
try:
|
||||
url = f"https://{self.host}/front/activity/add_lottery_count"
|
||||
response = session.get(url, timeout=10)
|
||||
response.raise_for_status()
|
||||
response_json = response.json()
|
||||
|
||||
if response_json.get('code') == 0:
|
||||
logging.info(f"[增加抽奖次数]: 成功")
|
||||
return True
|
||||
elif "达到上限" in response_json.get('msg', ''):
|
||||
logging.warning(f"[增加抽奖次数]: {response_json.get('msg')}")
|
||||
return False
|
||||
else:
|
||||
logging.error(f"[增加抽奖次数]发生错误: {response_json.get('msg', '未知错误')}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[增加抽奖次数]发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def update_lottery_result(self, session):
|
||||
"""
|
||||
更新抽奖结果(执行抽奖)
|
||||
:param session: session
|
||||
:return: 抽奖结果
|
||||
"""
|
||||
try:
|
||||
url = f"https://{self.host}/front/activity/update_lottery_result"
|
||||
params = {
|
||||
"id": 3438615
|
||||
}
|
||||
response = session.get(url, params=params, timeout=10)
|
||||
response.raise_for_status()
|
||||
response_json = response.json()
|
||||
|
||||
if response_json.get('code') == 0:
|
||||
good_name = response_json['data'].get('goodName', '未知奖励')
|
||||
logging.info(f"[抽奖]: 获得{good_name}")
|
||||
return True
|
||||
else:
|
||||
logging.warning(f"[抽奖]: {response_json.get('msg', '未知错误')}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[抽奖]发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def get_withdrawal_trade_list(self, session):
|
||||
"""
|
||||
获取提现相关数据
|
||||
:param session: session
|
||||
:return: (余额, 提现数据)/False
|
||||
"""
|
||||
try:
|
||||
url = f"https://{self.host}/api/h/get_withdrawal_trade_list"
|
||||
response = session.get(url, timeout=10)
|
||||
response.raise_for_status()
|
||||
response_json = response.json()
|
||||
|
||||
if response_json.get('code') == 0 and isinstance(response_json.get('data'), list) and len(response_json['data']) > 0:
|
||||
balance = float(response_json['data'][0].get('money', 0))
|
||||
logging.info(f"[余额]: {balance}元")
|
||||
return balance, response_json['data']
|
||||
else:
|
||||
logging.error(f"[获取提现相关数据]发生错误: {response_json.get('msg', '未知错误')}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[获取提现相关数据]发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def withdraw(self, session, balance, withdrawal_trade_list):
|
||||
"""
|
||||
提现
|
||||
:param session: session
|
||||
:param balance: 余额
|
||||
:param withdrawal_trade_list: 提现相关数据
|
||||
:return: 提现结果
|
||||
"""
|
||||
try:
|
||||
url = f"https://{self.host}/api/h/withdrawal"
|
||||
payload = {
|
||||
"totalMoney": balance,
|
||||
"type": 1,
|
||||
"withdrawalDetailPojoList": withdrawal_trade_list
|
||||
}
|
||||
response = session.post(url, json=payload, timeout=10)
|
||||
response.raise_for_status()
|
||||
response_json = response.json()
|
||||
|
||||
if response_json.get('code') == 0:
|
||||
logging.info(f"[提现]: {response_json.get('msg', '提现成功')}")
|
||||
return True
|
||||
else:
|
||||
logging.warning(f"[提现]: {response_json.get('msg', '提现失败')}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"[提现]发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
return False
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
运行任务
|
||||
"""
|
||||
try:
|
||||
logging.info(f"【{self.site_name}】开始执行任务")
|
||||
|
||||
# 从养鸡场获取账号列表
|
||||
accounts = self.get_wechat_account_list()
|
||||
if not accounts:
|
||||
logging.error("【{self.site_name}】获取账号列表失败,任务终止")
|
||||
return
|
||||
|
||||
# 过滤需要剔除的账号
|
||||
combined_remove = set(remove_wxids1)
|
||||
filtered_accounts = [acc for acc in accounts if acc.get('wxId') not in combined_remove]
|
||||
logging.info(f"[账号过滤]剔除后剩余 {len(filtered_accounts)} 个账号")
|
||||
|
||||
# 执行每个账号的任务
|
||||
for index, account in enumerate(filtered_accounts, 1):
|
||||
wxid = account.get('wxId')
|
||||
wxname = account.get('wxName', '未知昵称')
|
||||
|
||||
logging.info("")
|
||||
logging.info(f"------ 【账号{index}: {wxname} ({wxid})】开始执行任务 ------")
|
||||
|
||||
# 初始化session和代理
|
||||
if MULTI_ACCOUNT_PROXY:
|
||||
proxy = self.get_proxy()
|
||||
session = requests.Session()
|
||||
if proxy:
|
||||
session.proxies.update({
|
||||
"http": f"http://{proxy}",
|
||||
"https": f"http://{proxy}"
|
||||
})
|
||||
# 检查代理,不可用则不使用代理
|
||||
if not self.check_proxy(proxy, session):
|
||||
session.proxies.clear()
|
||||
logging.warning("[代理]使用默认网络环境")
|
||||
else:
|
||||
session = requests.Session()
|
||||
|
||||
session.headers["User-Agent"] = self.user_agent
|
||||
|
||||
# 执行微信授权获取code
|
||||
code = self.get_wx_code_yjc(wxid)
|
||||
if code:
|
||||
# 登录
|
||||
login_result = self.wxlogin(session, code)
|
||||
time.sleep(random.randint(1, 3))
|
||||
|
||||
if login_result:
|
||||
# 签到
|
||||
self.sign_in(session)
|
||||
time.sleep(random.randint(1, 3))
|
||||
|
||||
# 抽奖循环
|
||||
lottery_result = self.update_lottery_result(session)
|
||||
while lottery_result:
|
||||
time.sleep(random.randint(3, 5))
|
||||
lottery_result = self.update_lottery_result(session)
|
||||
|
||||
# 增加抽奖次数并继续抽奖
|
||||
add_count_result = self.add_lottery_count(session)
|
||||
while add_count_result:
|
||||
self.update_lottery_result(session)
|
||||
time.sleep(random.randint(3, 5))
|
||||
add_count_result = self.add_lottery_count(session)
|
||||
|
||||
# 提现逻辑
|
||||
withdraw_data = self.get_withdrawal_trade_list(session)
|
||||
if withdraw_data:
|
||||
balance, withdrawal_list = withdraw_data
|
||||
if balance >= DEFAULT_WITHDRAW_BALANCE:
|
||||
self.withdraw(session, balance, withdrawal_list)
|
||||
time.sleep(random.randint(1, 3))
|
||||
else:
|
||||
logging.warning(f"[提现]: 余额{balance}元不足{DEFAULT_WITHDRAW_BALANCE}元,不进行提现")
|
||||
else:
|
||||
logging.warning("[提现]: 获取提现数据失败")
|
||||
else:
|
||||
logging.error(f"[授权]wxid:{wxid} 获取Code失败,跳过该账号")
|
||||
|
||||
logging.info(f"------ 【账号{index}: {wxname} ({wxid})】执行任务完成 ------")
|
||||
# 账号间增加延迟,避免请求过快
|
||||
if index < len(filtered_accounts):
|
||||
time.sleep(random.randint(2, 5))
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"【{self.site_name}】执行过程中发生错误: {str(e)}\n{traceback.format_exc()}")
|
||||
finally:
|
||||
logging.info(f"【{self.site_name}】所有账号任务执行完毕")
|
||||
|
||||
print("\n所有任务执行完成")
|
||||
|
||||
# ==================== 入口 ====================
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
# 检查必要环境变量
|
||||
if not WX_TOKEN:
|
||||
print("错误:请先设置环境变量 wx_token")
|
||||
exit(1)
|
||||
|
||||
auto_task = AutoTask("铛铛一下")
|
||||
auto_task.run()
|
||||
Reference in New Issue
Block a user