1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/PfsP97若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/PfsP97
若失效,可用地址
https://www.aliyun.com/activity/wuying/dj?source=5176.29345612&userCode=49hts92d
腾讯云:
https://curl.qcloud.com/wJpWmSfU
若失效,可用地址
https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=ad201ee2ef3b771157f72ee5464b1fea&from=console
华为云
https://activity.huaweicloud.com/cps.html?fromacct=64b5cf7cc11b4840bb4ed2ea0b2f4468&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=201905
2.部署教程
3.代码如下
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
cron "9 15 * * *" script-path=xxx.py,tag=匹配cron用
new Env('顺丰速运签到')
"""
import hashlib
import json
import os
import random
import time
from datetime import datetime, timedelta
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from urllib.parse import unquote
# 禁用安全请求警告
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
hadsend = False
send = None
# 随机延迟配置
max_random_delay = int(os.getenv("MAX_RANDOM_DELAY", "3600"))
random_signin = os.getenv("RANDOM_SIGNIN", "true").lower() == "true"
# 全局日志变量
send_msg = ''
one_msg = ''
def Log(cont=''):
"""记录日志"""
global send_msg, one_msg
print(cont)
if cont:
one_msg += f'{cont}\n'
send_msg += f'{cont}\n'
def format_time_remaining(seconds):
"""格式化时间显示"""
if seconds <= 0:
return "立即执行"
hours = seconds // 3600
minutes = (seconds % 3600) // 60
secs = seconds % 60
if hours > 0:
return f"{hours}小时{minutes}分{secs}秒"
elif minutes > 0:
return f"{minutes}分{secs}秒"
else:
return f"{secs}秒"
def wait_with_countdown(delay_seconds, task_name):
"""带倒计时的随机延迟等待"""
if delay_seconds <= 0:
return
Log(f"{task_name} 需要等待 {format_time_remaining(delay_seconds)}")
remaining = delay_seconds
while remaining > 0:
if remaining <= 10 or remaining % 10 == 0:
Log(f"{task_name} 倒计时: {format_time_remaining(remaining)}")
sleep_time = 1 if remaining <= 10 else min(10, remaining)
time.sleep(sleep_time)
remaining -= sleep_time
inviteId = ['']
class RUN:
def __init__(self, info, index):
"""初始化账号信息"""
global one_msg
one_msg = ''
split_info = info.split('@')
url = split_info[0]
self.send_UID = split_info[-1] if len(split_info) > 1 and "UID_" in split_info[-1] else None
self.index = index + 1
self.s = requests.session()
self.s.verify = False
self.headers = {
'Host': 'mcs-mimp-web.sf-express.com',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x6309092b) XWEB/6763 Flue',
'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',
'sec-fetch-site': 'none',
'sec-fetch-mode': 'navigate',
'sec-fetch-user': '?1',
'sec-fetch-dest': 'document',
'accept-language': 'zh-CN,zh',
'platform': 'MINI_PROGRAM',
}
# 会员日活动相关属性
self.member_day_black = False
self.member_day_red_packet_drew_today = False
self.member_day_red_packet_map = {}
self.today = datetime.now().strftime('%Y-%m-%d')
self.max_level = 8
self.packet_threshold = 1 << (self.max_level - 1)
self.login_res = self.login(url)
def get_deviceId(self, characters='abcdef0123456789'):
"""生成随机设备ID"""
result = ''
for char in 'xxxxxxxx-xxxx-xxxx':
if char == 'x':
result += random.choice(characters)
else:
result += char
return result
def login(self, sfurl):
"""登录顺丰账号"""
try:
ress = self.s.get(sfurl, headers=self.headers)
self.user_id = self.s.cookies.get_dict().get('_login_user_id_', '')
self.phone = self.s.cookies.get_dict().get('_login_mobile_', '')
self.mobile = self.phone[:3] + "*" * 4 + self.phone[7:] if self.phone else ''
if self.phone:
Log(f' 账号{self.index}:【{self.mobile}】登陆成功')
return True
else:
Log(f' 账号{self.index}获取用户信息失败')
return False
except Exception as e:
Log(f' 登录异常: {str(e)}')
return False
def getSign(self):
"""生成请求签名"""
timestamp = str(int(time.time() * 1000))
token = 'wwesldfs29aniversaryvdld29'
sysCode = 'MCS-MIMP-CORE'
data = f'token={token}×tamp={timestamp}&sysCode={sysCode}'
signature = hashlib.md5(data.encode()).hexdigest()
data = {
'sysCode': sysCode,
'timestamp': timestamp,
'signature': signature
}
self.headers.update(data)
return data
def do_request(self, url, data=None, req_type='post', max_retries=3):
"""发送HTTP请求"""
self.getSign()
for retry_count in range(max_retries):
try:
if req_type.lower() == 'get':
response = self.s.get(url, headers=self.headers, timeout=30)
elif req_type.lower() == 'post':
response = self.s.post(url, headers=self.headers, json=data or {}, timeout=30)
else:
raise ValueError(f'Invalid req_type: {req_type}')
response.raise_for_status()
return response.json()
except (requests.exceptions.RequestException, json.JSONDecodeError) as e:
Log(f' 请求失败 ({retry_count + 1}/{max_retries}): {str(e)}')
if retry_count < max_retries - 1:
time.sleep(2)
continue
return {'success': False, 'errorMessage': str(e)}
return {'success': False, 'errorMessage': 'All retries failed'}
def sign(self):
"""执行签到任务"""
Log(' 开始执行签到')
json_data = {"comeFrom": "vioin", "channelFrom": "WEIXIN"}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~integralTaskSignPlusService~automaticSignFetchPackage'
response = self.do_request(url, data=json_data)
if response.get('success'):
count_day = response.get('obj', {}).get('countDay', 0)
if response.get('obj', {}).get('integralTaskSignPackageVOList'):
packet_name = response["obj"]["integralTaskSignPackageVOList"][0]["packetName"]
Log(f' 签到成功,获得【{packet_name}】,本周累计签到【{count_day + 1}】天')
else:
Log(f' 今日已签到,本周累计签到【{count_day + 1}】天')
else:
Log(f' 签到失败!原因:{response.get("errorMessage", "未知错误")}')
def get_SignTaskList(self, end=False):
"""获取签到任务列表"""
Log(' 开始获取签到任务列表' if not end else ' 查询最终积分')
json_data = {"channelType": "1", "deviceId": self.get_deviceId()}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~integralTaskStrategyService~queryPointTaskAndSignFromES'
response = self.do_request(url, data=json_data)
if response.get('success') and response.get('obj'):
totalPoint = response["obj"]["totalPoint"]
Log(f' {"执行前" if not end else "当前"}积分:【{totalPoint}】')
if not end:
for task in response["obj"]["taskTitleLevels"]:
self.taskId = task["taskId"]
self.taskCode = task["taskCode"]
self.strategyId = task["strategyId"]
self.title = task["title"]
status = task["status"]
skip_title = ['用行业模板寄件下单', '去新增一个收件偏好', '参与积分活动']
if status == 3:
Log(f' {self.title}-已完成')
continue
if self.title in skip_title:
Log(f' {self.title}-跳过')
continue
self.doTask()
time.sleep(2)
self.receiveTask()
def doTask(self):
"""完成签到任务"""
Log(f' 开始去完成【{self.title}】任务')
json_data = {"taskCode": self.taskCode}
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonRoutePost/memberEs/taskRecord/finishTask'
response = self.do_request(url, data=json_data)
Log(f'✨ 【{self.title}】任务-{"已完成" if response.get("success") else response.get("errorMessage", "失败")}')
def receiveTask(self):
"""领取签到任务奖励"""
Log(f' 开始领取【{self.title}】任务奖励')
json_data = {
"strategyId": self.strategyId,
"taskId": self.taskId,
"taskCode": self.taskCode,
"deviceId": self.get_deviceId()
}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~integralTaskStrategyService~fetchIntegral'
response = self.do_request(url, data=json_data)
Log(f'✨ 【{self.title}】任务奖励-{"领取成功" if response.get("success") else response.get("errorMessage", "失败")}')
def do_honeyTask(self):
"""完成丰蜜任务"""
Log(f' 开始完成【{self.taskType}】任务')
json_data = {"taskCode": self.taskCode}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberEs~taskRecord~finishTask'
response = self.do_request(url, data=json_data)
Log(f' 【{self.taskType}】任务-{"已完成" if response.get("success") else response.get("errorMessage", "失败")}')
def receive_honeyTask(self):
"""领取丰蜜任务奖励"""
Log(f' 领取【{self.taskType}】丰蜜任务')
self.headers.update({
'syscode': 'MCS-MIMP-CORE',
'channel': 'wxwdsj',
'accept': 'application/json, text/plain, */*',
'content-type': 'application/json;charset=UTF-8',
'platform': 'MINI_PROGRAM'
})
json_data = {"taskType": self.taskType}
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~receiveExchangeIndexService~receiveHoney'
response = self.do_request(url, data=json_data)
Log(f' 收取任务【{self.taskType}】-{"成功" if response.get("success") else response.get("errorMessage", "失败")}')
def get_coupom(self, goods):
"""领取优惠券"""
json_data = {
"from": "Point_Mall",
"orderSource": "POINT_MALL_EXCHANGE",
"goodsNo": goods['goodsNo'],
"quantity": 1,
"taskCode": self.taskCode
}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberGoods~pointMallService~createOrder'
response = self.do_request(url, data=json_data)
return response.get('success')
def get_coupom_list(self):
"""获取优惠券列表"""
json_data = {"memGrade": 2, "categoryCode": "SHTQ", "showCode": "SHTQWNTJ"}
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberGoods~mallGoodsLifeService~list'
response = self.do_request(url, data=json_data)
if response.get('success'):
all_goods = []
for obj in response.get("obj", []):
all_goods.extend(obj.get("goodsList", []))
for goods in all_goods:
if goods.get('exchangeTimesLimit', 0) >= 1:
if self.get_coupom(goods):
Log('✨ 成功领取券,任务结束!')
return
Log('📝 所有券尝试完成,没有可用的券或全部领取失败。')
else:
Log(f'❌ 获取券列表失败!原因:{response.get("errorMessage", "未知错误")}')
def get_honeyTaskListStart(self):
"""获取丰蜜任务列表"""
Log(' 开始获取采蜜换大礼任务列表')
self.headers['channel'] = 'wxwdsj'
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~receiveExchangeIndexService~taskDetail'
response = self.do_request(url, data={})
if response.get('success'):
for item in response["obj"]["list"]:
self.taskType = item["taskType"]
status = item["status"]
if status == 3:
Log(f'✨ 【{self.taskType}】-已完成')
continue
if "taskCode" in item:
self.taskCode = item["taskCode"]
if self.taskType == 'DAILY_VIP_TASK_TYPE':
self.get_coupom_list()
else:
self.do_honeyTask()
if self.taskType == 'BEES_GAME_TASK_TYPE':
self.honey_damaoxian()
time.sleep(2)
def honey_damaoxian(self):
"""执行大冒险任务"""
Log('>>> 执行大冒险任务')
gameNum = 5
for i in range(1, gameNum + 1):
json_data = {"gatherHoney": 20}
Log(f'>> 开始第{i}次大冒险')
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~receiveExchangeGameService~gameReport'
response = self.do_request(url, data=json_data)
if response.get('success'):
gameNum = response.get('obj')['gameNum']
Log(f'> 大冒险成功!剩余次数【{gameNum}】')
time.sleep(2)
elif response.get("errorMessage") == '容量不足':
Log('> 需要扩容')
self.honey_expand()
else:
Log(f'> 大冒险失败!【{response.get("errorMessage", "未知错误")}】')
break
def honey_expand(self):
"""容器扩容"""
Log('>>> 容器扩容')
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~receiveExchangeIndexService~expand'
response = self.do_request(url, data={})
if response.get('success'):
Log(f'> 成功扩容【{response.get("obj", "未知")}】容量')
else:
Log(f'> 扩容失败!【{response.get("errorMessage", "未知错误")}】')
def honey_indexData(self, end=False):
"""执行采蜜换大礼任务"""
Log(' 开始执行采蜜换大礼任务' if not end else '🍯 查询最终丰蜜')
random_invite = random.choice([invite for invite in inviteId if invite != self.user_id])
self.headers['channel'] = 'wxwdsj'
json_data = {"inviteUserId": random_invite}
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~receiveExchangeIndexService~indexData'
response = self.do_request(url, data=json_data)
if response.get('success'):
usableHoney = response.get('obj').get('usableHoney')
activityEndTime = response.get('obj').get('activityEndTime', '')
if not end:
Log(f' 本期活动结束时间【{activityEndTime}】')
Log(f' 执行前丰蜜:【{usableHoney}】')
for task in response.get('obj').get('taskDetail', []):
self.taskType = task['type']
self.receive_honeyTask()
time.sleep(2)
else:
Log(f'🍯 执行后丰蜜:【{usableHoney}】')
def member_day_index(self):
"""执行会员日活动"""
Log(' 会员日活动')
invite_user_id = random.choice([invite for invite in inviteId if invite != self.user_id])
payload = {'inviteUserId': invite_user_id}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~memberDayIndexService~index'
response = self.do_request(url, data=payload)
if response.get('success'):
lottery_num = response.get('obj', {}).get('lotteryNum', 0)
can_receive_invite_award = response.get('obj', {}).get('canReceiveInviteAward', False)
if can_receive_invite_award:
self.member_day_receive_invite_award(invite_user_id)
self.member_day_red_packet_status()
Log(f' 会员日可以抽奖{lottery_num}次')
for _ in range(lottery_num):
self.member_day_lottery()
if self.member_day_black:
return
self.member_day_task_list()
if self.member_day_black:
return
self.member_day_red_packet_status()
else:
error_message = response.get('errorMessage', '无返回')
Log(f' 查询会员日失败: {error_message}')
if '没有资格参与活动' in error_message:
self.member_day_black = True
Log(' 会员日任务风控')
def member_day_receive_invite_award(self, invite_user_id):
"""领取会员日邀请奖励"""
payload = {'inviteUserId': invite_user_id}
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~memberDayIndexService~receiveInviteAward'
response = self.do_request(url, data=payload)
if response.get('success'):
product_name = response.get('obj', {}).get('productName', '空气')
Log(f' 会员日奖励: {product_name}')
else:
error_message = response.get('errorMessage', '无返回')
Log(f' 领取会员日奖励失败: {error_message}')
if '没有资格参与活动' in error_message:
self.member_day_black = True
Log(' 会员日任务风控')
def member_day_lottery(self):
"""会员日抽奖"""
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~memberDayLotteryService~lottery'
response = self.do_request(url, data={})
if response.get('success'):
product_name = response.get('obj', {}).get('productName', '空气')
Log(f' 会员日抽奖: {product_name}')
else:
error_message = response.get('errorMessage', '无返回')
Log(f' 会员日抽奖失败: {error_message}')
if '没有资格参与活动' in error_message:
self.member_day_black = True
Log(' 会员日任务风控')
def member_day_task_list(self):
"""获取会员日任务列表"""
payload = {'activityCode': 'MEMBER_DAY', 'channelType': 'MINI_PROGRAM'}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~activityTaskService~taskList'
response = self.do_request(url, data=payload)
if response.get('success'):
task_list = response.get('obj', [])
for task in task_list:
if task['status'] == 1:
if self.member_day_black:
return
self.member_day_fetch_mix_task_reward(task)
elif task['status'] == 2 and task['taskType'] not in [
'SEND_SUCCESS', 'INVITEFRIENDS_PARTAKE_ACTIVITY', 'OPEN_SVIP',
'OPEN_NEW_EXPRESS_CARD', 'OPEN_FAMILY_CARD', 'CHARGE_NEW_EXPRESS_CARD',
'INTEGRAL_EXCHANGE', 'OPEN_SUPER_CARD' # 添加购买至尊会员到跳过列表
]:
for _ in range(task['restFinishTime']):
if self.member_day_black:
return
self.member_day_finish_task(task)
else:
error_message = response.get('errorMessage', '无返回')
Log(f'📝 查询会员日任务失败: {error_message}')
if '没有资格参与活动' in error_message:
self.member_day_black = True
Log('📝 会员日任务风控')
def member_day_finish_task(self, task):
"""完成会员日任务 - 修复版本"""
task_name = task.get("taskName", "未知任务")
task_type = task.get("taskType", "")
# 检查任务是否应该被跳过
skip_task_types = [
'SEND_SUCCESS', 'INVITEFRIENDS_PARTAKE_ACTIVITY', 'OPEN_SVIP',
'OPEN_NEW_EXPRESS_CARD', 'OPEN_FAMILY_CARD', 'CHARGE_NEW_EXPRESS_CARD',
'INTEGRAL_EXCHANGE', 'OPEN_SUPER_CARD'
]
if task_type in skip_task_types:
Log(f' 会员日任务[{task_name}]-跳过执行({task_type})')
return
# 智能获取任务代码
task_code = None
if 'taskCode' in task:
task_code = task['taskCode']
elif 'taskType' in task:
task_code = task['taskType'] # 某些任务使用taskType作为taskCode
else:
Log(f' 任务[{task_name}]缺少必要字段,跳过执行')
Log(f' 任务详情: {json.dumps(task, ensure_ascii=False, indent=2)}')
return
# 执行任务
payload = {'taskCode': task_code}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberEs~taskRecord~finishTask'
response = self.do_request(url, data=payload)
if response.get('success'):
Log(f' 完成会员日任务[{task_name}]: 成功')
self.member_day_fetch_mix_task_reward(task)
else:
error_message = response.get('errorMessage', '无返回')
Log(f' 完成会员日任务[{task_name}]: {error_message}')
if '没有资格参与活动' in error_message:
self.member_day_black = True
Log(' 会员日任务风控')
def member_day_fetch_mix_task_reward(self, task):
"""领取会员日任务奖励"""
task_name = task.get("taskName", "未知任务")
payload = {'taskType': task['taskType'], 'activityCode': 'MEMBER_DAY', 'channelType': 'MINI_PROGRAM'}
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~activityTaskService~fetchMixTaskReward'
response = self.do_request(url, data=payload)
if response.get('success'):
Log(f' 领取会员日任务[{task_name}]: 成功')
else:
error_message = response.get('errorMessage', '失败')
Log(f' 领取会员日任务[{task_name}]: {error_message}')
def member_day_receive_red_packet(self, hour):
"""领取会员日红包"""
payload = {'receiveHour': hour}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~memberDayTaskService~receiveRedPacket'
response = self.do_request(url, data=payload)
Log(f' 会员日领取{hour}点红包-{"成功" if response.get("success") else response.get("errorMessage", "失败")}')
def member_day_red_packet_status(self):
"""查询会员日红包状态"""
url = 'https://mcs-mimp-web.sf-express.com/mcs-mimp/commonPost/~memberNonactivity~memberDayPacketService~redPacketStatus'
response = self.do_request(url, data={})
if response.get('success'):
packet_list = response.get('obj', {}).get('packetList', [])
self.member_day_red_packet_map = {packet['level']: packet['count'] for packet in packet_list}
for level in range(1, self.max_level):
count = self.member_day_red_packet_map.get(level, 0)
while count >= 2:
self.member_day_red_packet_merge(level)
count -= 2
packet_summary = [f"[{level}]X{count}" for level, count in self.member_day_red_packet_map.items() if count > 0]
Log(f" 会员日合成列表: {', '.join(packet_summary) or '无红包'}")
if self.member_day_red_packet_map.get(self.max_level):
Log(f" 会员日已拥有[{self.max_level}级]红包X{self.member_day_red_packet_map[self.max_level]}")
self.member_day_red_packet_draw(self.max_level)
else:
remaining_needed = sum(1 << (int(level) - 1) for level, count in self.member_day_red_packet_map.items() if count > 0)
remaining = self.packet_threshold - remaining_needed
Log(f" 会员日距离[{self.max_level}级]红包还差: [1级]红包X{remaining}")
else:
error_message = response.get('errorMessage', '无返回')
Log(f' 查询会员日合成失败: {error_message}')
if '没有资格参与活动' in error_message:
self.member_day_black = True
Log(' 会员日任务风控')
def member_day_red_packet_merge(self, level):
"""合成会员日红包"""
payload = {'level': level, 'num': 2}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~memberDayPacketService~redPacketMerge'
response = self.do_request(url, data=payload)
if response.get('success'):
Log(f' 会员日合成: [{level}级]红包X2 -> [{level + 1}级]红包')
self.member_day_red_packet_map[level] = self.member_day_red_packet_map.get(level, 0) - 2
self.member_day_red_packet_map[level + 1] = self.member_day_red_packet_map.get(level + 1, 0) + 1
else:
Log(f' 会员日合成[{level}级]红包失败: {response.get("errorMessage", "无返回")}')
def member_day_red_packet_draw(self, level):
"""提取会员日红包"""
payload = {'level': str(level)}
url = 'https://sf-express.com/mcs-mimp/commonPost/~memberNonactivity~memberDayPacketService~redPacketDraw'
response = self.do_request(url, data=payload)
if response.get('success'):
coupon_names = [item['couponName'] for item in response.get('obj', [])] or ['空气']
Log(f" 会员日提取[{level}级]红包: {', '.join(coupon_names)}")
else:
Log(f" 会员日提取[{level}级]红包失败: {response.get('errorMessage', '无返回')}")
def main(self):
"""主执行逻辑"""
if not self.login_res:
return False
time.sleep(random.uniform(1, 3))
# 执行签到任务
self.sign()
# 注释掉超值福利签到(经常失败,影响体验)
# self.superWelfare_receiveRedPacket()
self.get_SignTaskList()
self.get_SignTaskList(True)
# 执行丰蜜任务
self.get_honeyTaskListStart()
self.honey_indexData()
self.honey_indexData(True)
# 检查活动截止时间
activity_end_date = get_quarter_end_date()
days_left = (activity_end_date - datetime.now()).days
Log(f"⏰ 采蜜活动截止兑换还有{days_left}天,请及时进行兑换!!")
# 会员日任务(每月26-28日)
if 26 <= datetime.now().day <= 28:
self.member_day_index()
else:
Log(' 未到指定时间不执行会员日任务')
self.sendMsg()
return True
def sendMsg(self, help=False):
"""发送通知(实现真正的通知功能)"""
global one_msg
if hadsend and one_msg:
try:
# 限制消息长度,避免过长
if len(one_msg) > 4000:
one_msg = one_msg[-4000:]
one_msg = "...(消息过长,已截取后半部分)\n" + one_msg
send(f'顺丰速运账号{self.index}', one_msg.strip())
print(f' 账号{self.index}通知发送完成')
except Exception as e:
print(f' 账号{self.index}通知发送失败: {e}')
def get_quarter_end_date():
"""计算当前季度结束日期"""
current_date = datetime.now()
current_month = current_date.month
current_year = current_date.year
next_quarter_first_day = datetime(current_year, ((current_month - 1) // 3 + 1) * 3 + 1, 1)
return next_quarter_first_day - timedelta(days=1)
if __name__ == '__main__':
"""主程序入口"""
APP_NAME = '顺丰速运'
ENV_NAME = 'sfsyUrl'
print(f"==== 顺丰速运签到开始 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ====")
# 随机延迟(整体延迟)
if random_signin:
delay_seconds = random.randint(0, max_random_delay)
if delay_seconds > 0:
signin_time = datetime.now() + timedelta(seconds=delay_seconds)
print(f" 随机模式: 延迟 {format_time_remaining(delay_seconds)} 后开始")
print(f" 预计开始时间: {signin_time.strftime('%H:%M:%S')}")
wait_with_countdown(delay_seconds, "顺丰签到")
token = os.getenv(ENV_NAME)
tokens = token.split('\n') if token else []
if tokens:
Log(f"🚚 共获取到{len(tokens)}个账号")
for index, infos in enumerate(tokens):
Log(f" 处理账号{index + 1}")
RUN(infos, index).main()
# 多账号间随机等待
if index < len(tokens) - 1: # 不是最后一个账号
delay = random.uniform(10, 30)
print(f"💤 随机等待 {delay:.1f} 秒后处理下一个账号...")
time.sleep(delay)
# 最终汇总通知
if hadsend and send_msg:
try:
# 汇总所有账号的结果
summary_msg = f"""🚚 顺丰速运签到汇总
📊 总计处理: {len(tokens)}个账号
📅 执行时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
详细结果请查看各账号单独通知"""
send('顺丰速运汇总', summary_msg)
print(' 汇总通知发送完成')
except Exception as e:
print(f' 汇总通知发送失败: {e}')
else:
Log(" 未获取到sfsyUrl环境变量")
print(f"==== 顺丰速运签到完成 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} ====")
解析
该脚本为顺丰速运自动化脚本,主要作用包括:
自动化登录并签到:基于你抓到并传入的跳转 URL(
sfsyUrl
环境变量),自动完成顺丰会员日常签到。自动做任务拿积分/丰蜜:批量遍历"积分任务""采蜜换大礼"任务,自动完成并领取奖励。
自动领券:在"生活特权"专区里循环尝试适配的券并兑换。
会员日玩法:每月 26–28 日自动跑会员日任务、红包合成/抽取/提取。
多账号+随机延迟+通知:支持多账号(换行分隔)、随机等待防风控、通知汇总。
运行与配置
环境变量:
sfsyUrl
(必填,支持多行多账号;抓包后 URL 要做 URL 编码)。随机延迟:
MAX_RANDOM_DELAY
、RANDOM_SIGNIN
控制启动前整体随机等待。
关键方法
通用工具
Log()
:统一日志累加(兼顾控制台输出、最终消息拼接)。format_time_remaining() / wait_with_countdown()
:格式化倒计时 & 循环打印倒计时(用于随机延迟可视化)。get_quarter_end_date()
:计算当季结束日,用于提示"采蜜兑换截止时间"。
账号执行主线:class RUN
初始化与登录
__init__(info, index)
解析单账号参数、初始化会话与请求头、设置会员日状态变量 → 调login()
。login(sfurl)
直接 GET 你的抓包 URL,服务器会写回_login_user_id_
、_login_mobile_
等 cookie,据此判断是否登录成功。
成功会打印掩码手机号作为提示。
通用请求封装
getSign()
构造并追加签名头(sysCode/timestamp/signature
),用于后续所有接口。do_request(url, data=None, req_type='post', max_retries=3)
统一的请求发送与 JSON 解析、自动重试与错误封装。
每日积分任务线
sign()
自动签到接口,成功会提示本周连签天数/礼包名。get_SignTaskList(end=False)
拉取"积分任务+签到状态"。end=False
:打印当前总积分、过滤已完成/需跳过的任务,逐条执行:doTask()
→receiveTask()
;end=True
:只打印执行后的积分。doTask()
/receiveTask()
分别是完成任务与领取奖励。
优惠券
get_coupom_list()
→get_coupom(goods)
拉取"生活特权"券清单,遍历可兑换的券,命中即下单兑换并提示成功。
采蜜换大礼(丰蜜)
get_honeyTaskListStart()
拉取"采蜜换大礼任务列表",对不同taskType
:DAILY_VIP_TASK_TYPE
→ 去券中心领券;BEES_GAME_TASK_TYPE
→ 触发大冒险honey_damaoxian()
;其他 →
do_honeyTask()
完成。do_honeyTask()
/receive_honeyTask()
完成单条丰蜜任务与领取丰蜜。honey_damaoxian()
/honey_expand()
批量上报大冒险获得的丰蜜;容量不足时自动扩容。honey_indexData(end=False)
采蜜首页:end=False
:打印活动结束时间与执行前丰蜜,遍历任务逐一receive_honeyTask()
;end=True
:打印执行后丰蜜。
(支持随机inviteUserId
互助,避免自填自身)
会员日(26–28 日)
member_day_index()
入口:查抽奖次数、邀请奖励、红包状态 → 抽奖 → 做任务 → 合成/提取红包。遇"无资格"自动标记member_day_black
终止分支。member_day_receive_invite_award()
/member_day_lottery()
领取邀请奖励、抽奖。member_day_task_list()
→member_day_finish_task(task)
→member_day_fetch_mix_task_reward(task)
拉任务 → 完成(自动选择taskCode
)→ 领取奖励;不自动做需要下单/付费类任务(已在白名单跳过)。红包相关:
member_day_red_packet_status()
:统计各等级红包数量,能合就合;凑满 8 级阈值后自动member_day_red_packet_draw()
提取;member_day_red_packet_merge(level)
:两两合成升级;member_day_receive_red_packet(hour)
:按小时领取(脚本主线里主要是状态/合成/抽取)。
执行编排
main()
登录→
sign()
→get_SignTaskList()
(前后两次,分别统计积分)采蜜任务→采蜜前后统计
提醒兑换截止天数
会员日(26–28 日)才执行会员日链路
末尾
sendMsg()
发送本账号汇报。
通知
sendMsg()
对单账号输出结果发送通知;主程序退出前也会发送汇总通知。
程序入口
读取
sfsyUrl
,支持多账号(按行分割)。若启用随机模式:整体随机延迟再开始。
逐个账号执行
RUN(...).main()
;账号间再随机间隔 10–30s。最后发送汇总通知。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
【相关文章】
没有评论:
发表评论