Files
qinglong/脚本库/微信小程序/抓包版/str_-_bool/2025-09-23_lsym_055c5aab.py
2026-05-24 05:33:05 +00:00

778 lines
25 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Source: https://github.com/3ixi/CodeScripts/blob/main/lsym.py
# Raw: https://raw.githubusercontent.com/3ixi/CodeScripts/main/lsym.py
# Repo: 3ixi/CodeScripts
# Path: lsym.py
# UploadedAt: 2025-09-23T14:07:43+08:00
# SHA256: 055c5aab9a013320b4421b4b0c1d4ea2893639fbc2eee553a66dfb67bcd7d1e6
# Category: 微信小程序/抓包版
# Evidence: appid/openid/session_key/encryptedData等小程序字段
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
零食有鸣小程序签到脚本
脚本作者3iXi
创建时间2025/09/04
此脚本需要配合iPad协议服务使用
小程序:零食有鸣
"""
import time
import json
import re
from typing import Optional, Dict, List
try:
import httpx
except ImportError:
print("错误: 需要安装 httpx[http2] 依赖")
exit(1)
import getCode
# 可以在这里指定门店ID如果为空则自动获取注册时的门店ID
STORE_ID = ""
class LsymSignin:
"""零食有鸣小程序签到类"""
def __init__(self):
"""初始化签到客户端"""
self.base_url = "https://api-pub.lsym.cn"
self.app_id = "wx295a967684523cdd"
self.client = httpx.Client(http2=True, timeout=30.0, verify=False)
self.headers = {
"host": "api-pub.lsym.cn",
"appid": "wx295a967684523cdd",
"authorization": "",
"tenantid": "1001",
"xweb_xhr": "1",
"devicelanguage": "zh-cn",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) UnifiedPCWindowsWechat(0xf254101e) XWEB/16389",
"accept": "*/*",
"content-type": "application/json",
"version": "3.1.0",
"devicemodel": "android",
"sec-fetch-site": "cross-site",
"sec-fetch-mode": "cors",
"sec-fetch-dest": "empty",
"referer": "https://servicewechat.com/wx295a967684523cdd/73/page-frame.html",
"accept-encoding": "gzip, deflate, br",
"accept-language": "zh-CN,zh;q=0.9",
"priority": "u=1, i"
}
self.access_token = None
self.member_id = None
self.lottery_activity_id = None
self.store_id = STORE_ID
def check_response(self, data: dict, operation: str) -> bool:
"""
检查响应是否成功
Args:
data (dict): 响应数据
operation (str): 操作名称
Returns:
bool: 是否成功
"""
if data.get("code") != 200:
print(f"{operation}失败:{data.get('msg', '未知错误')}")
return False
return True
def login(self, code: str) -> bool:
"""
用户登录
Args:
code (str): 微信小程序登录code
Returns:
bool: 登录是否成功
"""
url = f"{self.base_url}/scrm/member-identity/front/miniapp/silentLogin"
payload = {"loginType":0,"code":code}
try:
json_payload = json.dumps(payload, separators=(',', ':'))
headers = self.headers.copy()
headers["Content-Length"] = str(len(json_payload))
response = self.client.post(url, content=json_payload, headers=headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "登录"):
return False
login_data = data.get("data", {})
self.access_token = login_data.get("accessToken")
self.member_id = login_data.get("memberId")
mobile = login_data.get("mobile", "")
if self.access_token and self.member_id:
self.headers["authorization"] = self.access_token
print("登录成功")
return True
else:
print("登录失败未获取到token或memberId")
return False
except Exception as e:
print(f"登录请求失败: {e}")
return False
def get_task_list(self) -> Optional[List[Dict]]:
"""
获取任务列表
Returns:
Optional[List[Dict]]: 任务列表None表示获取失败
"""
url = f"{self.base_url}/scrm/marketing/front/task/batchGetTaskList"
try:
response = self.client.get(url, headers=self.headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "获取任务列表"):
return None
tasks = data.get("data", [])
filtered_tasks = []
for task in tasks:
join_detail = task.get("joinDetailVO", {})
task_state = join_detail.get("taskState")
task_type = task.get("taskType")
if task_type == 8 and task_state in [1, 2]:
filtered_tasks.append(task)
return filtered_tasks
except Exception as e:
print(f"获取任务列表请求失败: {e}")
return None
def register_task(self, activity_id: str, activity_name: str) -> bool:
"""
领取任务
Args:
activity_id (str): 活动ID
activity_name (str): 活动名称
Returns:
bool: 是否成功
"""
url = f"{self.base_url}/scrm/marketing/front/task/registerJoin"
params = {"activityId": activity_id}
try:
response = self.client.get(url, params=params, headers=self.headers)
response.raise_for_status()
data = response.json()
if self.check_response(data, f"领取任务【{activity_name}"):
print(f"任务【{activity_name}】领取成功")
return True
return False
except Exception as e:
print(f"领取任务【{activity_name}】请求失败: {e}")
return False
def visit_page(self, activity_id: str, activity_name: str) -> bool:
"""
提交任务浏览记录
Args:
activity_id (str): 活动ID
activity_name (str): 活动名称
Returns:
bool: 是否成功
"""
url = f"{self.base_url}/scrm/marketing/front/task/visitPage"
payload = {
"activityId": activity_id,
"taskType": 8
}
try:
json_payload = json.dumps(payload, separators=(',', ':'))
headers = self.headers.copy()
headers["Content-Length"] = str(len(json_payload))
response = self.client.post(url, content=json_payload, headers=headers)
response.raise_for_status()
data = response.json()
if self.check_response(data, f"浏览任务【{activity_name}"):
print(f"任务【{activity_name}】浏览成功")
return True
return False
except Exception as e:
print(f"浏览任务【{activity_name}】请求失败: {e}")
return False
def receive_prize(self, activity_id: str, activity_name: str) -> bool:
"""
领取任务奖励
Args:
activity_id (str): 活动ID
activity_name (str): 活动名称
Returns:
bool: 是否成功
"""
url = f"{self.base_url}/scrm/marketing/front/task/receivePrize"
params = {"activityId": activity_id}
try:
response = self.client.get(url, params=params, headers=self.headers)
response.raise_for_status()
data = response.json()
if self.check_response(data, f"领取奖励【{activity_name}"):
print(f"任务【{activity_name}】奖励领取成功")
return True
return False
except Exception as e:
print(f"领取奖励【{activity_name}】请求失败: {e}")
return False
def get_lottery_activity_id(self) -> Optional[str]:
"""
获取抽奖活动ID
Returns:
Optional[str]: 抽奖活动IDNone表示获取失败
"""
if self.lottery_activity_id:
return self.lottery_activity_id
url = f"{self.base_url}/scrm/cms/front/page/redirect/all"
payload = {}
try:
json_payload = json.dumps(payload, separators=(',', ':'))
headers = self.headers.copy()
headers["Content-Length"] = str(len(json_payload))
response = self.client.post(url, content=json_payload, headers=headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "获取抽奖活动ID"):
return None
activities = data.get("data", [])
for activity in activities:
original_title = activity.get("originalTitle", "")
if "" in original_title and "停用" not in original_title:
redirect_url = activity.get("redirectUrl", "")
try:
redirect_data = json.loads(redirect_url)
params = redirect_data.get("params", {})
activity_id = params.get("id")
if activity_id:
self.lottery_activity_id = activity_id
return activity_id
except json.JSONDecodeError:
continue
print("未找到有效的抽奖活动")
return None
except Exception as e:
print(f"获取抽奖活动ID请求失败: {e}")
return None
def get_lottery_quota_rules(self, activity_id: str) -> Optional[Dict]:
"""
获取抽奖任务规则
Args:
activity_id (str): 抽奖活动ID
Returns:
Optional[Dict]: 抽奖任务规则None表示获取失败
"""
url = f"{self.base_url}/scrm/marketing/front/activity/lottery-wheel/get-user-exchange-quota-rule-list"
params = {"activityId": activity_id}
try:
response = self.client.get(url, params=params, headers=self.headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "获取抽奖任务规则"):
return None
return data.get("data", {})
except Exception as e:
print(f"获取抽奖任务规则请求失败: {e}")
return None
def add_browse_record(self, activity_id: str, link_path: str, second: int, title: str) -> bool:
"""
添加浏览记录
Args:
activity_id (str): 抽奖活动ID
link_path (str): 链接路径
second (int): 浏览秒数
title (str): 页面标题
Returns:
bool: 是否成功
"""
url = f"{self.base_url}/scrm/marketing/front/activity/lottery-wheel/add-browse-record"
payload = {
"activityId": activity_id,
"memberId": self.member_id,
"linkPath": link_path,
"second": second
}
try:
json_payload = json.dumps(payload, separators=(',', ':'))
headers = self.headers.copy()
headers["Content-Length"] = str(len(json_payload))
response = self.client.post(url, content=json_payload, headers=headers)
response.raise_for_status()
data = response.json()
if self.check_response(data, f"浏览【{title}{second}"):
print("任务完成")
return True
return False
except Exception as e:
print(f"添加浏览记录请求失败: {e}")
return False
def submit_share_task(self, activity_id: str) -> bool:
"""
提交分享任务
Args:
activity_id (str): 抽奖活动ID
Returns:
bool: 是否成功
"""
url = f"{self.base_url}/scrm/marketing/front/activity/lottery-wheel/user-exchange-quota-operate"
payload = {
"activityId": activity_id,
"type": 2,
"versionId": "7"
}
try:
json_payload = json.dumps(payload, separators=(',', ':'))
headers = self.headers.copy()
headers["Content-Length"] = str(len(json_payload))
response = self.client.post(url, content=json_payload, headers=headers)
response.raise_for_status()
data = response.json()
if self.check_response(data, "分享任务"):
print("分享任务完成")
return True
return False
except Exception as e:
print(f"提交分享任务请求失败: {e}")
return False
def get_lottery_quota(self, activity_id: str) -> Optional[int]:
"""
查询抽奖次数
Args:
activity_id (str): 抽奖活动ID
Returns:
Optional[int]: 抽奖次数None表示获取失败
"""
url = f"{self.base_url}/scrm/marketing/front/activity/lottery-wheel/get-user-lottery-quota"
params = {"activityId": activity_id}
try:
response = self.client.get(url, params=params, headers=self.headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "查询抽奖次数"):
return None
quota = data.get("data", 0)
print(f"可用抽奖次数{quota}")
return quota
except Exception as e:
print(f"查询抽奖次数请求失败: {e}")
return None
def ensure_store_id(self) -> bool:
"""
确保门店ID已设置如未设置则从会员信息中获取
Returns:
bool: 是否成功获取门店ID
"""
if self.store_id:
return True
member_info = self.get_member_info()
if not member_info:
print("获取会员信息失败无法获取门店ID")
return False
register_store_id = member_info.get("registerStoreId")
register_store_name = member_info.get("registerStoreName", "")
if not register_store_id:
print("会员信息中未找到注册门店ID")
return False
self.store_id = register_store_id
print(f"获取到注册门店信息:{register_store_name}({register_store_id})")
return True
def draw_lottery(self, activity_id: str) -> Optional[Dict]:
"""
抽奖
Args:
activity_id (str): 抽奖活动ID
Returns:
Optional[Dict]: 抽奖结果None表示抽奖失败
"""
if not self.ensure_store_id():
print("门店ID获取失败无法进行抽奖")
return None
url = f"{self.base_url}/scrm/marketing/front/activity/lottery-wheel/prize-draw"
payload = {
"activityId": activity_id,
"versionId": "7"
}
try:
json_payload = json.dumps(payload, separators=(',', ':'))
headers = self.headers.copy()
headers["Content-Length"] = str(len(json_payload))
headers["storeid"] = self.store_id
response = self.client.post(url, content=json_payload, headers=headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "抽奖"):
return None
return data.get("data", {})
except Exception as e:
print(f"抽奖请求失败: {e}")
return None
def get_member_info(self) -> Optional[Dict]:
"""
获取会员信息
Returns:
Optional[Dict]: 会员信息None表示获取失败
"""
url = f"{self.base_url}/scrm/member/front/getCurrentMember"
try:
response = self.client.get(url, headers=self.headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "获取会员信息"):
return None
return data.get("data", {})
except Exception as e:
print(f"获取会员信息请求失败: {e}")
return None
def get_coupons(self) -> Optional[List[Dict]]:
"""
获取未使用的优惠券
Returns:
Optional[List[Dict]]: 优惠券列表None表示获取失败
"""
url = f"{self.base_url}/scrm/marketing/front/memberCoupon/page"
params = {
"currPage": 1,
"pageSize": 20,
"couponState": 2
}
try:
response = self.client.get(url, params=params, headers=self.headers)
response.raise_for_status()
data = response.json()
if not self.check_response(data, "获取优惠券"):
return None
records = data.get("data", {}).get("records", [])
return records
except Exception as e:
print(f"获取优惠券请求失败: {e}")
return None
def process_tasks(self) -> bool:
"""
处理任务流程
Returns:
bool: 是否处理成功
"""
# 1. 获取任务列表
tasks = self.get_task_list()
if not tasks:
print("未获取到有效任务")
return False
# 2. 处理任务
for task in tasks:
activity_id = task.get("activityId")
activity_name = task.get("activityName")
join_detail = task.get("joinDetailVO", {})
task_state = join_detail.get("taskState")
# 检查必要字段
if not activity_id or not activity_name:
continue
if task_state == 1: # 未领取
if not self.register_task(activity_id, activity_name):
continue
if task_state in [1, 2]: # 未领取或待完成
# 提交浏览记录
if not self.visit_page(activity_id, activity_name):
continue
# 领取奖励
if not self.receive_prize(activity_id, activity_name):
continue
elif task_state == 3: # 已完成,直接领取奖励
self.receive_prize(activity_id, activity_name)
return True
def process_lottery(self) -> bool:
"""
处理抽奖流程
Returns:
bool: 是否处理成功
"""
# 1. 获取抽奖活动ID
activity_id = self.get_lottery_activity_id()
if not activity_id:
return False
# 2. 获取抽奖任务规则
quota_rules = self.get_lottery_quota_rules(activity_id)
if not quota_rules:
return False
# 3. 处理浏览任务
browse_task = quota_rules.get("browseDesignatedPage", {})
if browse_task.get("valid") and browse_task.get("state") == 1:
thresholds = browse_task.get("thresholds", [])
for threshold in thresholds:
if threshold.get("valid"):
link_url = threshold.get("linkUrl", "")
second = threshold.get("second", 10)
try:
link_data = json.loads(link_url)
title = link_data.get("title", "")
path = link_data.get("path", "")
print(f"可做任务:浏览【{title}{second}")
self.add_browse_record(activity_id, path, second, title)
except json.JSONDecodeError:
continue
# 4. 处理分享任务
share_task = quota_rules.get("share", {})
if share_task.get("valid") and share_task.get("state") == 1:
self.submit_share_task(activity_id)
# 5. 查询抽奖次数并抽奖
time.sleep(2)
quota = self.get_lottery_quota(activity_id)
if quota and quota > 0:
for i in range(quota):
draw_result = self.draw_lottery(activity_id)
if draw_result:
state = draw_result.get("state", 1)
if state == 0: # 中奖
prize = draw_result.get("prize", {})
prize_name = prize.get("prizeName", "")
prize_object = prize.get("prizeObject", {})
coupons = prize_object.get("coupons", [])
if coupons:
count = coupons[0].get("count", 1)
print(f"{i+1}次抽奖抽中了{prize_name}x{count}")
else:
print(f"{i+1}次抽奖抽中了{prize_name}")
if i < quota - 1:
time.sleep(1)
return True
def process_account(self, nick_name: str, code: str) -> bool:
"""
处理单个账号的签到流程
Args:
nick_name (str): 账号昵称
code (str): 微信小程序登录code
Returns:
bool: 是否处理成功
"""
print(f"\n开始处理账号: {nick_name}")
# 1. 登录
if not self.login(code):
print(f"账号 {nick_name} 登录失败")
return False
# 2. 处理任务
self.process_tasks()
# 3. 处理抽奖
self.process_lottery()
# 4. 获取会员信息和积分
member_info = self.get_member_info()
if member_info:
mobile = member_info.get("mobile", "")
balance = member_info.get("balance", "0")
# 手机号打码
if len(mobile) >= 7:
masked_mobile = mobile[:3] + "****" + mobile[7:]
else:
masked_mobile = mobile
print(f"{masked_mobile}当前有{balance}积分")
# 5. 获取优惠券信息
coupons = self.get_coupons()
if coupons:
print("未使用优惠券:")
for coupon in coupons:
coupon_name = coupon.get("couponName", "")
effective_time_end = coupon.get("effectiveTimeEnd", "")
print(f"{coupon_name}({effective_time_end}过期)")
else:
print("暂无未使用优惠券")
return True
def close(self):
"""关闭HTTP客户端"""
self.client.close()
def reset_session(self):
"""
重置/清理会话数据
"""
try:
self.client.close()
except Exception:
pass
self.client = httpx.Client(http2=True, timeout=30.0, verify=False)
self.access_token = None
self.member_id = None
self.headers["authorization"] = ""
self.store_id = STORE_ID
print("已清理会话数据,准备下一个账号...")
def main():
"""主函数"""
try:
print("正在获取登录Code...")
app_id = "wx295a967684523cdd"
codes = getCode.get_wechat_codes(app_id)
if not codes:
print("未获取到任何在线账号的Code")
return
print(f"获取到 {len(codes)} 个账号的Code")
signin = LsymSignin()
try:
for i, (nick_name, code) in enumerate(codes.items(), 1):
print(f"\n{'='*50}")
print(f"处理第 {i}/{len(codes)} 个账号")
print(f"{'='*50}")
try:
signin.process_account(nick_name, code)
except Exception as e:
print(f"处理账号 {nick_name} 时发生错误: {e}")
signin.reset_session()
if i < len(codes):
print(f"等待2秒后处理下一个账号...")
time.sleep(2)
finally:
signin.close()
print("\n所有账号处理完成")
except Exception as e:
print(f"脚本执行失败: {e}")
if __name__ == "__main__":
main()