mirror of
https://github.com/hlt1995/qlScripts.git
synced 2026-11-05 23:26:44 +08:00
Create 顺丰速运新年活动.py
This commit is contained in:
1 parent
5d6a168403
commit
1436edbe05
1 file changed
+992
+992
@@ -0,0 +1,992 @@
|
|||||||
|
"""
|
||||||
|
顺丰速运新年活动脚本
|
||||||
|
Author: 爱学习的呆子
|
||||||
|
Version: 2.0.0
|
||||||
|
Date: 2026-01-26
|
||||||
|
活动代码: YEAREND_2025
|
||||||
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Dict, Optional, Any, List
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from urllib.parse import unquote
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
|
from threading import Lock
|
||||||
|
import requests
|
||||||
|
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||||
|
|
||||||
|
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||||
|
|
||||||
|
PROXY_TIMEOUT = 15
|
||||||
|
MAX_PROXY_RETRIES = 5
|
||||||
|
REQUEST_RETRY_COUNT = 3
|
||||||
|
|
||||||
|
CONCURRENT_NUM = int(os.getenv('SFBF', '1'))
|
||||||
|
if CONCURRENT_NUM > 20:
|
||||||
|
CONCURRENT_NUM = 20
|
||||||
|
print(f'⚠️ 并发数量超过最大值20,已自动调整为20')
|
||||||
|
elif CONCURRENT_NUM < 1:
|
||||||
|
CONCURRENT_NUM = 1
|
||||||
|
print(f'⚠️ 并发数量小于1,已自动调整为1(串行模式)')
|
||||||
|
|
||||||
|
print_lock = Lock()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Config:
|
||||||
|
"""全局配置"""
|
||||||
|
APP_NAME: str = "顺丰速运新年活动"
|
||||||
|
VERSION: str = "2.0.0"
|
||||||
|
ENV_NAME: str = "sfsyUrl"
|
||||||
|
PROXY_API_URL: str = os.getenv('SF_PROXY_API_URL', '')
|
||||||
|
ACTIVITY_CODE: str = "YEAREND_2025"
|
||||||
|
|
||||||
|
TOKEN: str = 'wwesldfs29aniversaryvdld29'
|
||||||
|
SYS_CODE: str = 'MCS-MIMP-CORE'
|
||||||
|
|
||||||
|
ENABLE_INTEGRAL_EXCHANGE: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
class Logger:
|
||||||
|
"""日志管理器"""
|
||||||
|
|
||||||
|
ICONS = {
|
||||||
|
'info': '📝',
|
||||||
|
'success': '✨',
|
||||||
|
'error': '❌',
|
||||||
|
'warning': '⚠️',
|
||||||
|
'user': '👤',
|
||||||
|
'money': '💰',
|
||||||
|
'gift': '🎁',
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.messages: List[str] = []
|
||||||
|
self.current_account_msg: List[str] = []
|
||||||
|
self.lock = Lock()
|
||||||
|
|
||||||
|
def _format_msg(self, icon: str, content: str) -> str:
|
||||||
|
return f"{icon} {content}"
|
||||||
|
|
||||||
|
def _safe_print(self, msg: str):
|
||||||
|
with print_lock:
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
def info(self, content: str):
|
||||||
|
msg = self._format_msg(self.ICONS['info'], content)
|
||||||
|
self._safe_print(msg)
|
||||||
|
with self.lock:
|
||||||
|
self.current_account_msg.append(msg)
|
||||||
|
self.messages.append(msg)
|
||||||
|
|
||||||
|
def success(self, content: str):
|
||||||
|
msg = self._format_msg(self.ICONS['success'], content)
|
||||||
|
self._safe_print(msg)
|
||||||
|
with self.lock:
|
||||||
|
self.current_account_msg.append(msg)
|
||||||
|
self.messages.append(msg)
|
||||||
|
|
||||||
|
def error(self, content: str):
|
||||||
|
msg = self._format_msg(self.ICONS['error'], content)
|
||||||
|
self._safe_print(msg)
|
||||||
|
with self.lock:
|
||||||
|
self.current_account_msg.append(msg)
|
||||||
|
self.messages.append(msg)
|
||||||
|
|
||||||
|
def warning(self, content: str):
|
||||||
|
msg = self._format_msg(self.ICONS['warning'], content)
|
||||||
|
self._safe_print(msg)
|
||||||
|
with self.lock:
|
||||||
|
self.current_account_msg.append(msg)
|
||||||
|
self.messages.append(msg)
|
||||||
|
|
||||||
|
def user_info(self, account_index: int, mobile: str):
|
||||||
|
msg = self._format_msg(self.ICONS['user'], f"账号{account_index}: 【{mobile}】登录成功")
|
||||||
|
self._safe_print(msg)
|
||||||
|
with self.lock:
|
||||||
|
self.current_account_msg.append(msg)
|
||||||
|
self.messages.append(msg)
|
||||||
|
|
||||||
|
def reset_account_msg(self):
|
||||||
|
self.current_account_msg = []
|
||||||
|
|
||||||
|
def get_all_messages(self) -> str:
|
||||||
|
return '\n'.join(self.messages)
|
||||||
|
|
||||||
|
def get_account_messages(self) -> str:
|
||||||
|
return '\n'.join(self.current_account_msg)
|
||||||
|
|
||||||
|
|
||||||
|
class ProxyManager:
|
||||||
|
"""代理管理器"""
|
||||||
|
|
||||||
|
def __init__(self, api_url: str):
|
||||||
|
self.api_url = api_url
|
||||||
|
|
||||||
|
def get_proxy(self) -> Optional[Dict[str, str]]:
|
||||||
|
try:
|
||||||
|
if not self.api_url:
|
||||||
|
print('⚠️ 未配置代理API地址,将不使用代理')
|
||||||
|
return None
|
||||||
|
|
||||||
|
response = requests.get(self.api_url, timeout=10)
|
||||||
|
if response.status_code == 200:
|
||||||
|
proxy_text = response.text.strip()
|
||||||
|
if ':' in proxy_text:
|
||||||
|
if proxy_text.startswith('http://') or proxy_text.startswith('https://'):
|
||||||
|
proxy = proxy_text
|
||||||
|
else:
|
||||||
|
proxy = f'http://{proxy_text}'
|
||||||
|
|
||||||
|
display_proxy = proxy
|
||||||
|
if '@' in proxy:
|
||||||
|
parts = proxy.split('@')
|
||||||
|
if len(parts) == 2:
|
||||||
|
display_proxy = f"http://***:***@{parts[1]}"
|
||||||
|
|
||||||
|
print(f"✅ 成功获取代理: {display_proxy}")
|
||||||
|
return {'http': proxy, 'https': proxy}
|
||||||
|
|
||||||
|
print(f'❌ 获取代理失败: {response.text}')
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f'❌ 获取代理异常: {str(e)}')
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class SFHttpClient:
|
||||||
|
"""顺丰HTTP客户端"""
|
||||||
|
|
||||||
|
def __init__(self, config: Config, proxy_manager: ProxyManager):
|
||||||
|
self.config = config
|
||||||
|
self.proxy_manager = proxy_manager
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.verify = False
|
||||||
|
|
||||||
|
proxy = self.proxy_manager.get_proxy()
|
||||||
|
if proxy:
|
||||||
|
self.session.proxies = proxy
|
||||||
|
|
||||||
|
self.headers = {
|
||||||
|
'Host': 'mcs-mimp-web.sf-express.com',
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Linux; Android 16; PJE110 Build/TP1A.220905.001; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/134.0.6998.135 Mobile Safari/537.36 mediaCode=SFEXPRESSAPP-Android-ML',
|
||||||
|
'Accept': 'application/json, text/plain, */*',
|
||||||
|
'Accept-Encoding': 'gzip, deflate, br, zstd',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'sec-ch-ua-platform': '"Android"',
|
||||||
|
'sec-ch-ua': '"Chromium";v="134", "Not:A-Brand";v="24", "Android WebView";v="134"',
|
||||||
|
'sec-ch-ua-mobile': '?1',
|
||||||
|
'channel': 'daluapp',
|
||||||
|
'syscode': 'MCS-MIMP-CORE',
|
||||||
|
'platform': 'SFAPP',
|
||||||
|
'origin': 'https://mcs-mimp-web.sf-express.com',
|
||||||
|
'x-requested-with': 'com.sf.activity',
|
||||||
|
'sec-fetch-site': 'same-origin',
|
||||||
|
'sec-fetch-mode': 'cors',
|
||||||
|
'sec-fetch-dest': 'empty',
|
||||||
|
'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||||
|
'priority': 'u=1, i'
|
||||||
|
}
|
||||||
|
|
||||||
|
def _generate_sign(self) -> Dict[str, str]:
|
||||||
|
timestamp = str(int(round(time.time() * 1000)))
|
||||||
|
data = f'token={self.config.TOKEN}×tamp={timestamp}&sysCode={self.config.SYS_CODE}'
|
||||||
|
signature = hashlib.md5(data.encode()).hexdigest()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'timestamp': timestamp,
|
||||||
|
'signature': signature
|
||||||
|
}
|
||||||
|
|
||||||
|
def request(
|
||||||
|
self,
|
||||||
|
url: str,
|
||||||
|
method: str = 'POST',
|
||||||
|
data: Optional[Dict] = None,
|
||||||
|
max_retries: int = REQUEST_RETRY_COUNT
|
||||||
|
) -> Optional[Dict[str, Any]]:
|
||||||
|
sign_data = self._generate_sign()
|
||||||
|
self.headers.update(sign_data)
|
||||||
|
|
||||||
|
retry_count = 0
|
||||||
|
proxy_retry_count = 0
|
||||||
|
|
||||||
|
while proxy_retry_count < MAX_PROXY_RETRIES:
|
||||||
|
try:
|
||||||
|
if retry_count >= 2:
|
||||||
|
print('请求已失败2次,尝试切换代理IP')
|
||||||
|
new_proxy = self.proxy_manager.get_proxy()
|
||||||
|
if new_proxy:
|
||||||
|
self.session.proxies = new_proxy
|
||||||
|
else:
|
||||||
|
print('⚠️ 切换代理失败,无可用代理')
|
||||||
|
retry_count = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
if method.upper() == 'GET':
|
||||||
|
response = self.session.get(url, headers=self.headers, timeout=PROXY_TIMEOUT)
|
||||||
|
elif method.upper() == 'POST':
|
||||||
|
response = self.session.post(url, headers=self.headers, json=data or {}, timeout=PROXY_TIMEOUT)
|
||||||
|
else:
|
||||||
|
raise ValueError(f'不支持的请求方法: {method}')
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
try:
|
||||||
|
res = response.json()
|
||||||
|
if res is None:
|
||||||
|
print(f'响应内容为空,正在重试 ({retry_count + 1}/{max_retries})')
|
||||||
|
retry_count += 1
|
||||||
|
time.sleep(2)
|
||||||
|
continue
|
||||||
|
return res
|
||||||
|
except (json.JSONDecodeError, ValueError) as e:
|
||||||
|
print(f'JSON解析失败: {str(e)}, 响应内容: {response.text[:200]}')
|
||||||
|
retry_count += 1
|
||||||
|
if retry_count < max_retries:
|
||||||
|
print(f'正在进行第{retry_count + 1}次重试...')
|
||||||
|
time.sleep(2)
|
||||||
|
continue
|
||||||
|
return None
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
retry_count += 1
|
||||||
|
print(f'请求失败,正在重试 ({retry_count}/{max_retries}): {str(e)}')
|
||||||
|
if 'ProxyError' in str(e) or 'SSLError' in str(e):
|
||||||
|
proxy_retry_count += 1
|
||||||
|
print(f'代理连接失败,尝试切换代理 ({proxy_retry_count}/{MAX_PROXY_RETRIES})')
|
||||||
|
if proxy_retry_count < MAX_PROXY_RETRIES:
|
||||||
|
new_proxy = self.proxy_manager.get_proxy()
|
||||||
|
if new_proxy:
|
||||||
|
self.session.proxies = new_proxy
|
||||||
|
time.sleep(2)
|
||||||
|
continue
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'请求发生异常: {str(e)}')
|
||||||
|
proxy_retry_count += 1
|
||||||
|
if proxy_retry_count < MAX_PROXY_RETRIES:
|
||||||
|
print(f'尝试切换代理 ({proxy_retry_count}/{MAX_PROXY_RETRIES})')
|
||||||
|
time.sleep(2)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
print('达到最大代理重试次数,返回None')
|
||||||
|
return None
|
||||||
|
|
||||||
|
print('请求最终失败,返回None')
|
||||||
|
return None
|
||||||
|
|
||||||
|
def login(self, url: str, timeout: int = PROXY_TIMEOUT) -> tuple[bool, str, str]:
|
||||||
|
try:
|
||||||
|
decoded_url = unquote(url)
|
||||||
|
self.session.get(decoded_url, headers=self.headers, timeout=timeout)
|
||||||
|
|
||||||
|
cookies = self.session.cookies.get_dict()
|
||||||
|
user_id = cookies.get('_login_user_id_', '')
|
||||||
|
phone = cookies.get('_login_mobile_', '')
|
||||||
|
|
||||||
|
if phone:
|
||||||
|
return True, user_id, phone
|
||||||
|
else:
|
||||||
|
return False, '', ''
|
||||||
|
except Exception as e:
|
||||||
|
print(f'登录异常: {str(e)}')
|
||||||
|
return False, '', ''
|
||||||
|
|
||||||
|
|
||||||
|
class NewYearActivity:
|
||||||
|
"""新年活动任务执行器"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
http_client: SFHttpClient,
|
||||||
|
logger: Logger,
|
||||||
|
config: Config,
|
||||||
|
user_id: str
|
||||||
|
):
|
||||||
|
self.http = http_client
|
||||||
|
self.logger = logger
|
||||||
|
self.config = config
|
||||||
|
self.user_id = user_id
|
||||||
|
|
||||||
|
def init_activity_index(self) -> bool:
|
||||||
|
"""初始化活动索引(必须在所有操作前调用)"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonNoLoginPost/~memberNonactivity~yearEnd2025IndexService~index'
|
||||||
|
|
||||||
|
# 使用随机邀请ID(如果没有则使用空字符串)
|
||||||
|
invite_ids = [
|
||||||
|
'F5E70D771ABD4D86AFB0782313945C91',
|
||||||
|
'16A1E9AF32C1441894D27E0F1453F7CB',
|
||||||
|
'3ED135C9A3254CCFACA88781CD9B3A91',
|
||||||
|
'6931380B6A234074A318CECD9E62089D',
|
||||||
|
'C883BE3AE638494B90BAB440A4CFFDEC'
|
||||||
|
]
|
||||||
|
|
||||||
|
# 随机选择一个邀请ID(排除自己的user_id)
|
||||||
|
available_invites = [inv for inv in invite_ids if inv != self.user_id]
|
||||||
|
invite_user_id = random.choice(available_invites) if available_invites else invite_ids[0]
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"inviteType": 1,
|
||||||
|
"inviteUserId": invite_user_id
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.warning('活动索引初始化失败')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def request_activity_page(self) -> bool:
|
||||||
|
"""请求活动页面(避免活动太火爆错误)"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonNoLoginPost/~cempBase~pageGreyStrategyService~getStrategyByUser'
|
||||||
|
data = {"sceneCode": "year-end-2025"}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.logger.warning('活动页面请求失败')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_sign_status(self) -> tuple[bool, Dict]:
|
||||||
|
"""检查签到状态"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~activitySignService~signStatus'
|
||||||
|
data = {"activityCode": self.config.ACTIVITY_CODE}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
obj = response.get('obj', {})
|
||||||
|
sign_count_cache = obj.get('signCountCache', {})
|
||||||
|
sign_count = sign_count_cache.get('signCount', 0)
|
||||||
|
sign_time = sign_count_cache.get('signTime', '')
|
||||||
|
sign_expired_tm = sign_count_cache.get('signExpiredTm', '')
|
||||||
|
|
||||||
|
self.logger.info(f'累计签到次数: {sign_count}')
|
||||||
|
if sign_time:
|
||||||
|
self.logger.info(f'最后签到时间: {sign_time}')
|
||||||
|
if sign_expired_tm:
|
||||||
|
self.logger.info(f'活动截止时间: {sign_expired_tm}')
|
||||||
|
|
||||||
|
return True, obj
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.error(f'查询签到状态失败: {error_msg}')
|
||||||
|
return False, {}
|
||||||
|
|
||||||
|
def sign_in(self) -> tuple[bool, str]:
|
||||||
|
"""执行签到"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~activitySignService~sign'
|
||||||
|
data = {
|
||||||
|
"activityCode": self.config.ACTIVITY_CODE
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
obj = response.get('obj', {})
|
||||||
|
signed = obj.get('signed', False)
|
||||||
|
sign_count = obj.get('signCount', 0)
|
||||||
|
|
||||||
|
if signed:
|
||||||
|
self.logger.warning('今日已签到')
|
||||||
|
return True, '今日已签到'
|
||||||
|
|
||||||
|
common_sign_packet = obj.get('commonSignPacketDTO', {})
|
||||||
|
if common_sign_packet:
|
||||||
|
gift_bag_name = common_sign_packet.get('giftBagName', '未知奖励')
|
||||||
|
gift_bag_worth = common_sign_packet.get('giftBagWorth', 0)
|
||||||
|
product_list = common_sign_packet.get('commonSignProductList', [])
|
||||||
|
|
||||||
|
reward_details = []
|
||||||
|
for product in product_list:
|
||||||
|
product_name = product.get('productName', '')
|
||||||
|
amount = product.get('amount', 0)
|
||||||
|
if product_name and amount:
|
||||||
|
reward_details.append(f'{product_name} x{amount}')
|
||||||
|
|
||||||
|
reward_text = ', '.join(reward_details) if reward_details else gift_bag_name
|
||||||
|
self.logger.success(f'签到成功!获得: {reward_text}')
|
||||||
|
self.logger.info(f'累计签到: {sign_count} 次')
|
||||||
|
|
||||||
|
return True, ''
|
||||||
|
else:
|
||||||
|
self.logger.success(f'签到成功!累计签到: {sign_count} 次')
|
||||||
|
return True, ''
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.error(f'签到失败: {error_msg}')
|
||||||
|
return False, error_msg
|
||||||
|
|
||||||
|
def get_task_list(self) -> List[Dict]:
|
||||||
|
"""获取任务列表"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~activityTaskService~taskList'
|
||||||
|
data = {
|
||||||
|
"activityCode": self.config.ACTIVITY_CODE,
|
||||||
|
"channelType": "SFAPP"
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
task_list = response.get('obj', [])
|
||||||
|
self.logger.info(f'成功获取任务列表,共 {len(task_list)} 个任务')
|
||||||
|
return task_list
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.error(f'获取任务列表失败: {error_msg}')
|
||||||
|
return []
|
||||||
|
|
||||||
|
def receive_task_reward(self, task_code: str, task_name: str) -> bool:
|
||||||
|
"""领取任务奖励"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~activityTaskService~receiveTaskToken'
|
||||||
|
data = {
|
||||||
|
"activityCode": self.config.ACTIVITY_CODE,
|
||||||
|
"taskCode": task_code
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
self.logger.success(f'[{task_name}] 奖励领取成功')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.warning(f'[{task_name}] 领取奖励失败: {error_msg}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def receive_member_equity(self) -> bool:
|
||||||
|
"""领取寄件会员权益"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberManage~memberEquity~commonEquityReceive'
|
||||||
|
data = {"key": "surprise_benefit"}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
self.logger.success('领取寄件会员权益成功')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.warning(f'领取寄件会员权益失败: {error_msg}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def do_tasks(self) -> int:
|
||||||
|
"""执行所有任务"""
|
||||||
|
|
||||||
|
task_list = self.get_task_list()
|
||||||
|
if not task_list:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
completed_count = 0
|
||||||
|
|
||||||
|
# 需要跳过的任务(无需显示日志)
|
||||||
|
skip_task_names = [
|
||||||
|
'开通家庭8折互寄权益',
|
||||||
|
'去寄快递',
|
||||||
|
'充值新速运通全国卡',
|
||||||
|
'邀好友首次访问活动',
|
||||||
|
'春节寄大件行李'
|
||||||
|
]
|
||||||
|
|
||||||
|
for task in task_list:
|
||||||
|
task_name = task.get('taskName', '未知任务')
|
||||||
|
task_code = task.get('taskCode', '')
|
||||||
|
task_type = task.get('taskType', '')
|
||||||
|
status = task.get('status', 0)
|
||||||
|
process = task.get('process', '0/0')
|
||||||
|
description = task.get('description', '')
|
||||||
|
virtual_token_num = task.get('virtualTokenNum', 0)
|
||||||
|
|
||||||
|
if status == 3:
|
||||||
|
self.logger.success(f'[{task_name}] 已完成 ({process})')
|
||||||
|
completed_count += 1
|
||||||
|
elif status == 2:
|
||||||
|
# 跳过无taskCode且在跳过列表中的任务
|
||||||
|
if not task_code and task_name in skip_task_names:
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.logger.info(f'[{task_name}] 可领取 - {description} (奖励: {virtual_token_num}次)')
|
||||||
|
|
||||||
|
if task_name == '领取寄件会员权益':
|
||||||
|
if self.receive_member_equity():
|
||||||
|
completed_count += 1
|
||||||
|
time.sleep(1)
|
||||||
|
elif task_name == '积分兑冲刺次数':
|
||||||
|
self.logger.info('积分兑换任务将在游戏前自动执行')
|
||||||
|
elif task_name == '套财神游戏':
|
||||||
|
self.logger.info('套财神游戏任务将在后续执行')
|
||||||
|
elif task_code:
|
||||||
|
if self.receive_task_reward(task_code, task_name):
|
||||||
|
completed_count += 1
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
self.logger.info(f'[{task_name}] 未完成 ({process}) - {description}')
|
||||||
|
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
self.logger.success(f'任务执行完成,共完成 {completed_count} 个任务')
|
||||||
|
return completed_count
|
||||||
|
|
||||||
|
def get_forward_status(self) -> tuple[bool, Dict]:
|
||||||
|
"""查询向前冲状态"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~yearEnd2025ForwardService~forwardStatus'
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
obj = response.get('obj', {})
|
||||||
|
return True, obj
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.error(f'查询向前冲状态失败: {error_msg}')
|
||||||
|
return False, {}
|
||||||
|
|
||||||
|
def play_forward_game(self, card_token: str = None) -> tuple[bool, str]:
|
||||||
|
"""执行向前冲游戏
|
||||||
|
|
||||||
|
Args:
|
||||||
|
card_token: 卡片令牌,如果为None则获取新令牌
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple[bool, str]: (是否成功, cardToken)
|
||||||
|
"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~yearEnd2025ForwardService~forward'
|
||||||
|
|
||||||
|
if card_token:
|
||||||
|
data = {"cardToken": card_token}
|
||||||
|
else:
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
obj = response.get('obj', {})
|
||||||
|
new_card_token = obj.get('cardToken', '')
|
||||||
|
current_times = obj.get('currentTimes', 0)
|
||||||
|
total_times = obj.get('totalTimes', 0)
|
||||||
|
current_ratio = obj.get('currentRatio', 0)
|
||||||
|
remain_chance = obj.get('remainChance', 0)
|
||||||
|
result_type = obj.get('resultType', 0)
|
||||||
|
|
||||||
|
if result_type == 5:
|
||||||
|
self.logger.info(f'🎮 向前冲游戏进行中... 进度: {current_times}/{total_times} ({current_ratio:.1f}%) 剩余次数: {remain_chance}')
|
||||||
|
else:
|
||||||
|
self.logger.success(f'🎮 向前冲游戏 - 进度: {current_times}/{total_times} ({current_ratio:.1f}%) 剩余次数: {remain_chance}')
|
||||||
|
|
||||||
|
return True, new_card_token
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.warning(f'向前冲游戏失败: {error_msg}')
|
||||||
|
return False, ''
|
||||||
|
|
||||||
|
def play_game(self) -> bool:
|
||||||
|
"""执行套财神游戏"""
|
||||||
|
self.logger.info('开始执行套财神游戏...')
|
||||||
|
|
||||||
|
url_init = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~yearEnd2025GameService~init'
|
||||||
|
response = self.http.request(url_init, data={})
|
||||||
|
|
||||||
|
if not response or not response.get('success'):
|
||||||
|
self.logger.warning('游戏初始化失败')
|
||||||
|
return False
|
||||||
|
|
||||||
|
obj = response.get('obj', {})
|
||||||
|
if obj.get('alreadyDayPass', False):
|
||||||
|
self.logger.info('今日已通关,跳过游戏')
|
||||||
|
return True
|
||||||
|
|
||||||
|
start_level = obj.get('currentIndex', 0)
|
||||||
|
level_config = obj.get('levelConfig', [])
|
||||||
|
total_levels = len(level_config)
|
||||||
|
|
||||||
|
self.logger.info(f'今日未通关,从第 {start_level} 关开始,共 {total_levels} 关')
|
||||||
|
|
||||||
|
url_win = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~yearEnd2025GameService~win'
|
||||||
|
|
||||||
|
for i in range(start_level, total_levels):
|
||||||
|
self.logger.info(f'正在闯关第 {i} 关...')
|
||||||
|
data = {"levelIndex": i}
|
||||||
|
response = self.http.request(url_win, data=data)
|
||||||
|
|
||||||
|
if response and response.get('success'):
|
||||||
|
award_list = response.get('obj', {}).get('currentAwardList', [])
|
||||||
|
if award_list:
|
||||||
|
for award in award_list:
|
||||||
|
currency = award.get('currency', '')
|
||||||
|
amount = award.get('amount', 0)
|
||||||
|
self.logger.success(f'第 {i} 关通关成功!获得: {currency} x{amount}')
|
||||||
|
else:
|
||||||
|
self.logger.success(f'第 {i} 关通关成功!')
|
||||||
|
|
||||||
|
time.sleep(random.randint(5, 10))
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.error(f'第 {i} 关闯关失败: {error_msg}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
self.logger.success('所有关卡通关完成!')
|
||||||
|
return True
|
||||||
|
|
||||||
|
def fetch_tasks_reward(self) -> int:
|
||||||
|
"""领取任务奖励次数"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~yearEnd2025TaskService~fetchTasksReward'
|
||||||
|
data = {
|
||||||
|
"activityCode": self.config.ACTIVITY_CODE,
|
||||||
|
"channelType": "MINI_PROGRAM"
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
success, status_obj = self.get_forward_status()
|
||||||
|
if success:
|
||||||
|
remain_chance = status_obj.get('remainChance', 0)
|
||||||
|
current_ratio = status_obj.get('currentRatio', 0)
|
||||||
|
current_level = status_obj.get('currentLevel', '')
|
||||||
|
self.logger.info(f'任务奖励领取成功,当前剩余次数: {remain_chance},进度: {current_ratio:.1f}%,等级: {current_level}')
|
||||||
|
return remain_chance
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.warning(f'领取任务奖励失败: {error_msg}')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_accrued_task_award(self) -> bool:
|
||||||
|
"""获取累计任务奖励"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~yearEnd2025TaskService~getAccruedTaskAward'
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
obj = response.get('obj', {})
|
||||||
|
current_progress = obj.get('currentProgress', 0)
|
||||||
|
progress_config = obj.get('progressConfig', {})
|
||||||
|
accrued_award = obj.get('accruedAward', {})
|
||||||
|
|
||||||
|
self.logger.info(f'累计任务进度: {current_progress}')
|
||||||
|
|
||||||
|
if accrued_award:
|
||||||
|
self.logger.success('获得累计任务奖励')
|
||||||
|
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.warning(f'获取累计任务奖励失败: {error_msg}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_user_rest_integral(self) -> int:
|
||||||
|
"""查询用户剩余积分"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~activityTaskService~getUserRestIntegral'
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
integral = response.get('obj', 0)
|
||||||
|
self.logger.info(f'当前可用积分: {integral}')
|
||||||
|
return integral
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.warning(f'查询用户剩余积分失败: {error_msg}')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def integral_exchange(self, exchange_num: int = 1) -> bool:
|
||||||
|
"""积分兑换冲刺次数
|
||||||
|
|
||||||
|
Args:
|
||||||
|
exchange_num: 兑换次数,默认1次(消耗10积分)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: 是否兑换成功
|
||||||
|
"""
|
||||||
|
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~yearEnd2025TaskService~integralExchange'
|
||||||
|
data = {
|
||||||
|
"exchangeNum": exchange_num,
|
||||||
|
"activityCode": self.config.ACTIVITY_CODE
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.http.request(url, data=data)
|
||||||
|
if response and response.get('success'):
|
||||||
|
obj = response.get('obj', {})
|
||||||
|
remain_chance = obj.get('remainChance', 0)
|
||||||
|
self.logger.success(f'💎 积分兑换成功!兑换 {exchange_num} 次冲刺机会,当前剩余: {remain_chance} 次')
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
error_msg = response.get('errorMessage', '未知错误') if response else '请求失败'
|
||||||
|
self.logger.warning(f'积分兑换失败: {error_msg}')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def do_forward_game(self) -> int:
|
||||||
|
"""执行所有向前冲游戏次数"""
|
||||||
|
self.logger.info('开始执行向前冲游戏...')
|
||||||
|
|
||||||
|
if self.config.ENABLE_INTEGRAL_EXCHANGE:
|
||||||
|
self.logger.info('积分兑换功能已启用,尝试兑换冲刺次数...')
|
||||||
|
self.integral_exchange(1)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
success, status_obj = self.get_forward_status()
|
||||||
|
if not success:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
remain_chance = status_obj.get('remainChance', 0)
|
||||||
|
if remain_chance <= 0:
|
||||||
|
self.logger.info('向前冲游戏次数已用完')
|
||||||
|
return 0
|
||||||
|
|
||||||
|
self.logger.info(f'当前剩余游戏次数: {remain_chance}')
|
||||||
|
|
||||||
|
played_count = 0
|
||||||
|
card_token = None
|
||||||
|
|
||||||
|
for i in range(remain_chance):
|
||||||
|
success, card_token = self.play_forward_game(card_token)
|
||||||
|
if success:
|
||||||
|
played_count += 1
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if played_count > 0:
|
||||||
|
self.logger.success(f'向前冲游戏完成,共进行 {played_count} 次')
|
||||||
|
|
||||||
|
return played_count
|
||||||
|
|
||||||
|
def run(self) -> Dict[str, Any]:
|
||||||
|
"""执行新年活动任务"""
|
||||||
|
print('-' * 50)
|
||||||
|
|
||||||
|
self.init_activity_index()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
self.request_activity_page()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
success, status_obj = self.check_sign_status()
|
||||||
|
if not success:
|
||||||
|
return {
|
||||||
|
'success': False,
|
||||||
|
'signed': False,
|
||||||
|
'sign_count': 0,
|
||||||
|
'task_completed': 0,
|
||||||
|
'game_played': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
sign_success, error_msg = self.sign_in()
|
||||||
|
|
||||||
|
sign_count = status_obj.get('signCountCache', {}).get('signCount', 0)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
self.fetch_tasks_reward()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
task_completed = self.do_tasks()
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
self.play_game()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
self.fetch_tasks_reward()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
self.get_accrued_task_award()
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
current_integral = self.get_user_rest_integral()
|
||||||
|
if current_integral >= 10 and self.config.ENABLE_INTEGRAL_EXCHANGE:
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
game_played = self.do_forward_game()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'success': sign_success,
|
||||||
|
'signed': '今日已签到' in error_msg,
|
||||||
|
'sign_count': sign_count,
|
||||||
|
'task_completed': task_completed,
|
||||||
|
'game_played': game_played
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class AccountManager:
|
||||||
|
"""账号管理器"""
|
||||||
|
|
||||||
|
def __init__(self, account_url: str, account_index: int, config: Config):
|
||||||
|
self.account_url = account_url
|
||||||
|
self.account_index = account_index + 1
|
||||||
|
self.config = config
|
||||||
|
self.logger = Logger()
|
||||||
|
self.proxy_manager = ProxyManager(config.PROXY_API_URL)
|
||||||
|
|
||||||
|
self.login_success = False
|
||||||
|
self.user_id = None
|
||||||
|
self.phone = None
|
||||||
|
self.http_client = None
|
||||||
|
|
||||||
|
retry_count = 0
|
||||||
|
while retry_count < MAX_PROXY_RETRIES and not self.login_success:
|
||||||
|
try:
|
||||||
|
self.http_client = SFHttpClient(config, self.proxy_manager)
|
||||||
|
|
||||||
|
success, self.user_id, self.phone = self.http_client.login(account_url)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
masked_phone = self.phone[:3] + "*" * 4 + self.phone[7:]
|
||||||
|
self.logger.user_info(self.account_index, masked_phone)
|
||||||
|
self.login_success = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if retry_count < MAX_PROXY_RETRIES - 1:
|
||||||
|
print(f'账号{self.account_index} 登录失败,尝试重新获取代理 ({retry_count + 1}/{MAX_PROXY_RETRIES})')
|
||||||
|
time.sleep(2)
|
||||||
|
except Exception as e:
|
||||||
|
print(f'账号{self.account_index} 登录异常: {str(e)[:100]}')
|
||||||
|
|
||||||
|
retry_count += 1
|
||||||
|
|
||||||
|
if not self.login_success:
|
||||||
|
self.logger.error(f'账号{self.account_index} 登录失败,已重试{MAX_PROXY_RETRIES}次,所有代理均不可用')
|
||||||
|
|
||||||
|
def run(self) -> Dict[str, Any]:
|
||||||
|
if not self.login_success:
|
||||||
|
return {
|
||||||
|
'success': False,
|
||||||
|
'phone': '',
|
||||||
|
'signed': False,
|
||||||
|
'sign_count': 0,
|
||||||
|
'task_completed': 0,
|
||||||
|
'game_played': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_time = random.randint(1000, 3000) / 1000.0
|
||||||
|
time.sleep(wait_time)
|
||||||
|
|
||||||
|
activity = NewYearActivity(self.http_client, self.logger, self.config, self.user_id)
|
||||||
|
result = activity.run()
|
||||||
|
|
||||||
|
result['phone'] = self.phone
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def run_single_account(account_info: str, index: int, config: Config) -> Dict[str, Any]:
|
||||||
|
try:
|
||||||
|
with print_lock:
|
||||||
|
print(f"🚀 开始执行账号{index + 1}")
|
||||||
|
|
||||||
|
account = AccountManager(account_info, index, config)
|
||||||
|
result = account.run()
|
||||||
|
|
||||||
|
if result['success']:
|
||||||
|
with print_lock:
|
||||||
|
print(f"✅ 账号{index + 1}执行完成")
|
||||||
|
else:
|
||||||
|
with print_lock:
|
||||||
|
print(f"❌ 账号{index + 1}执行失败")
|
||||||
|
|
||||||
|
result['index'] = index
|
||||||
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f"账号{index + 1}执行异常: {str(e)}"
|
||||||
|
with print_lock:
|
||||||
|
print(f"❌ {error_msg}")
|
||||||
|
return {
|
||||||
|
'index': index,
|
||||||
|
'success': False,
|
||||||
|
'phone': '',
|
||||||
|
'signed': False,
|
||||||
|
'sign_count': 0,
|
||||||
|
'task_completed': 0,
|
||||||
|
'game_played': 0,
|
||||||
|
'error': error_msg
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
config = Config()
|
||||||
|
|
||||||
|
env_value = os.getenv(config.ENV_NAME)
|
||||||
|
if not env_value:
|
||||||
|
print(f"❌ 未找到环境变量 {config.ENV_NAME},请检查配置")
|
||||||
|
return
|
||||||
|
|
||||||
|
account_urls = [url.strip() for url in env_value.split('&') if url.strip()]
|
||||||
|
if not account_urls:
|
||||||
|
print(f"❌ 环境变量 {config.ENV_NAME} 为空或格式错误")
|
||||||
|
return
|
||||||
|
|
||||||
|
random.shuffle(account_urls)
|
||||||
|
print(f"🔀 已随机打乱账号执行顺序")
|
||||||
|
|
||||||
|
print("=" * 50)
|
||||||
|
print(f"🎉 {config.APP_NAME} v{config.VERSION}")
|
||||||
|
print(f"👨💻 作者: 爱学习的呆子")
|
||||||
|
print(f"🎊 活动代码: {config.ACTIVITY_CODE}")
|
||||||
|
print(f"📱 共获取到 {len(account_urls)} 个账号")
|
||||||
|
print(f"⚙️ 并发数量: {CONCURRENT_NUM}")
|
||||||
|
print(f"💎 积分兑换: {'✅ 已启用' if config.ENABLE_INTEGRAL_EXCHANGE else '❌ 已禁用'}")
|
||||||
|
print(f"⏰ 执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
all_results = []
|
||||||
|
|
||||||
|
if CONCURRENT_NUM <= 1:
|
||||||
|
print("🔄 使用串行模式执行...")
|
||||||
|
for index, account_url in enumerate(account_urls):
|
||||||
|
account = AccountManager(account_url, index, config)
|
||||||
|
result = account.run()
|
||||||
|
result['index'] = index
|
||||||
|
all_results.append(result)
|
||||||
|
|
||||||
|
if index < len(account_urls) - 1:
|
||||||
|
print("=" * 50)
|
||||||
|
print(f"⏳ 等待 2 秒后执行下一个账号...")
|
||||||
|
time.sleep(2)
|
||||||
|
else:
|
||||||
|
print(f"🔄 使用并发模式执行,并发数: {CONCURRENT_NUM}")
|
||||||
|
|
||||||
|
with ThreadPoolExecutor(max_workers=CONCURRENT_NUM) as executor:
|
||||||
|
future_to_index = {
|
||||||
|
executor.submit(run_single_account, account_url, index, config): index
|
||||||
|
for index, account_url in enumerate(account_urls)
|
||||||
|
}
|
||||||
|
|
||||||
|
for future in as_completed(future_to_index):
|
||||||
|
result = future.result()
|
||||||
|
all_results.append(result)
|
||||||
|
|
||||||
|
all_results.sort(key=lambda x: x['index'])
|
||||||
|
|
||||||
|
success_count = sum(1 for r in all_results if r['success'])
|
||||||
|
fail_count = len(all_results) - success_count
|
||||||
|
signed_count = sum(1 for r in all_results if r.get('signed', False))
|
||||||
|
total_tasks = sum(r.get('task_completed', 0) for r in all_results)
|
||||||
|
total_games = sum(r.get('game_played', 0) for r in all_results)
|
||||||
|
|
||||||
|
print(f"\n" + "=" * 100)
|
||||||
|
print(f"📊 新年活动任务统计")
|
||||||
|
print("=" * 100)
|
||||||
|
print(f"{'序号':<6} {'手机号':<15} {'签到状态':<12} {'累计签到':<10} {'完成任务':<10} {'游戏次数':<10} {'状态':<10}")
|
||||||
|
print("-" * 100)
|
||||||
|
|
||||||
|
for result in all_results:
|
||||||
|
index = result['index'] + 1
|
||||||
|
phone = result['phone'][:3] + "****" + result['phone'][7:] if result['phone'] else "未登录"
|
||||||
|
signed_status = "✅已签到" if result.get('signed', False) else ("🎁新签到" if result['success'] else "❌失败")
|
||||||
|
sign_count = result.get('sign_count', 0)
|
||||||
|
task_completed = result.get('task_completed', 0)
|
||||||
|
game_played = result.get('game_played', 0)
|
||||||
|
status = "✅成功" if result['success'] else "❌失败"
|
||||||
|
|
||||||
|
print(f"{index:<6} {phone:<15} {signed_status:<12} {sign_count:<10} {task_completed:<10} {game_played:<10} {status:<10}")
|
||||||
|
|
||||||
|
print("-" * 100)
|
||||||
|
print(f"{'汇总':<6} {'总数: ' + str(len(all_results)):<15} {'已签: ' + str(signed_count):<12} {'':<10} {'任务: ' + str(total_tasks):<10} {'游戏: ' + str(total_games):<10} {'成功: ' + str(success_count):<10}")
|
||||||
|
print("=" * 100)
|
||||||
|
|
||||||
|
print("\n🎊 所有账号新年活动任务执行完成!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in new issue
Block a user