feat(权益超市): 添加奖池查询、人机验证及浇花逻辑修复

- 新增 MarketRaffleState 全局奖池状态类,多账号共享查询结果
- 奖池查询改为抽奖完成后执行,仅作为信息展示
- 有效奖品判断:包含月卡/周卡/季卡,排除5G宽视界/沃视频,概率>0
- 新增 market_validate_captcha 人机验证自动处理
- 修复浇花任务逻辑:从只浇一次改为持续浇花直到完成目标次数
- 更新 README 文档
This commit is contained in:
unknown committed 2025-12-12 21:37:26 +08:00
1 parent 202f5f7ac8
commit 3835987dc2
2 files changed
+182 -13

No files matched your search

+48 -3
View File
@@ -6,6 +6,10 @@
```text
中国联通.py
├── 📂 MarketRaffleState (全局奖池状态类)
│ ├── __init__ .................... 初始化奖池状态/锁
│ └── check_prizes ................ 查询奖池(全局单次,多账号共享)
│
├── 📂 Logger (日志管理类)
│ ├── __init__ .................... 初始化日志前缀
│ └── log ......................... 输出带时间戳的日志
@@ -45,7 +49,11 @@
│ │
│ ├── 🛒 权益超市 (Market)
│ ├── market_task ................. 超市任务入口
│ ├── market_login ................ 超市登录
│ ├── market_watering_task ........ 浇花任务(支持多次浇花直到完成)
│ ├── market_watering ............. 执行浇花
│ ├── market_raffle_task .......... 抽奖任务(抽奖后展示奖池信息)
│ ├── market_validate_captcha ..... 人机验证处理
│ └── market_raffle ............... 执行抽奖
│ │
│ ├── 🍇 新疆专区 (Xinjiang)
@@ -66,6 +74,16 @@
└── 🚀 main (主程序入口) ............ 并发调度所有账号任务
```
## ✨ 功能特性
### 权益超市增强功能
- **每日自动抽奖**: 无条件执行抽奖,不受奖池状态影响
- **奖池信息展示**: 抽奖完成后展示今日奖池信息(概率>0的奖品)
- **有效奖品识别**: 自动标记有效奖品(包含月卡/周卡/季卡,排除5G宽视界/沃视频)
- **人机验证处理**: 抽奖触发人机验证时自动处理并继续抽奖
- **浇花任务修复**: 支持多次浇花直到完成目标次数(如60次)
- **全局奖池查询**: 多账号只查询一次奖池,共享结果,节省资源
### 3. 配置账号
脚本通过环境变量 `chinaUnicomCookie` 获取用户登录信息。支持多账号,多个Cookie之间请使用 `@` 符号分隔。
@@ -94,21 +112,43 @@ python 中国联通.py
### 5. 查看运行结果
脚本运行后,将在控制台输出详细的执行日志。
- **登录状态**: 显示登录成功/失败及脱敏后的手机号(如 `138****5678`)。
- **任务进度**: 实时显示各个任务的执行情况(如“签到成功”、“获得0.87元立减金”)。
- **抽奖结果**: 显示具体的奖品名称(如“5元话费券”、“未中奖”)。
- **任务进度**: 实时显示各个任务的执行情况(如"签到成功"、"获得0.87元立减金")。
- **奖池状态**: 抽奖完成后展示今日奖池信息及有效奖品。
- **抽奖结果**: 显示具体的奖品名称(如"5元话费券"、"未中奖")。
#### 奖池查询输出示例
```
============================================================
权益超市奖品池查询
============================================================
今日奖池共 16 个奖品:
✅ [01] 爱奇艺VIP月卡
今日投放: 100 | 总库存: 5000 | 概率: 5.00%
❌ [02] 5G宽视界黄金会员月卡
今日投放: 50 | 总库存: 3000 | 概率: 3.00%
❌ [03] 茶百道6元免配券
今日投放: 5000 | 总库存: 0 | 概率: 15.00%
...
============================================================
结论: 当前已放水!有效奖品 3/16 个,可以抽奖
============================================================
```
## 注意事项
- **HTTP/2**: 为保证稳定性,脚本默认关闭了HTTP/2支持。
- **异常处理**: 脚本内置了完善的异常捕获机制,单个任务的失败不会影响其他任务或账号的执行。
- **隐私安全**: 所有敏感信息(如手机号)在日志输出时均会自动脱敏,保障用户隐私。
- **奖池共享**: 权益超市奖池查询只执行一次,所有账号共享结果,避免重复请求。
## ❓ 常见问题与故障排除
### 1. 登录失败处理
如果遇到登录失败的情况,请尝试以下步骤:
1. 使用抓包工具获取本机实际的 `device_id` 和 `device_code`。
2. 打开 `中国联通.py` 文件,找到 `online` 函数(约第 140 行)。
2. 打开 `中国联通.py` 文件,找到 `online` 函数(约第 220 行)。
3. 将代码中的 `device_id` 和 `device_code` 替换为抓包获取的实际值,保持一致。
### 2. 环境变量设置补充
@@ -116,6 +156,11 @@ python 中国联通.py
- 提取请求体或Header中的 `token_online` 值。
- 将该值设置为环境变量 `chinaUnicomCookie`。
### 3. 权益超市相关
- **浇花状态异常**: 已修复只浇花一次的问题,现在会持续浇花直到完成目标次数。
- **奖池信息**: 抽奖完成后展示今日奖池,仅作为参考信息,不影响抽奖流程。
- **人机验证**: 触发人机验证时会自动处理,无需手动干预。
## ⚠️ 免责声明
1. **仅供学习交流**:本项目仅供编程学习和技术交流使用,请勿用于任何商业用途。
+134 -10
View File
@@ -30,6 +30,91 @@ ANOTHER_ENCRYPTION_KEY = "f4cd4ffeb5554586acf65ba7110534f5"
SERVICE_LIFE = "wocareMBHServiceLife1"
MIN_RETRIES = "1"
# ==================== Global Market Raffle State ====================
# 全局奖池状态,多账号共享,只查询一次
class MarketRaffleState:
def __init__(self):
self.checked = False # 是否已检查
self.has_prizes = False # 是否有奖品可抽
self.prizes = [] # 奖品列表
self.lock = asyncio.Lock() # 异步锁
async def check_prizes(self, http_client, market_token):
"""检查奖池状态,只执行一次"""
async with self.lock:
if self.checked:
return self.has_prizes
print("\n" + "="*60)
print("权益超市奖品池查询")
print("="*60)
try:
res = await http_client.request(
'POST',
'https://backward.bol.wo.cn/prod-api/promotion/home/raffleActivity/prizeList?id=12',
headers={'Authorization': f'Bearer {market_token}'},
data=''
)
result = res['result']
if result and result.get('code') == 200 and isinstance(result.get('data'), list):
self.prizes = result['data']
# 筛选今日奖池(概率>0的奖品)
today_prizes = [p for p in self.prizes if float(p.get('probability', 0)) > 0]
total = len(today_prizes)
print(f"今日奖池共 {total} 个奖品:\n")
# 有效奖品关键词
include_keywords = ['月卡', '周卡', '月度', '季卡']
exclude_keywords = ['5G宽视界', '沃视频']
valid_count = 0
for i, prize in enumerate(today_prizes, 1):
name = prize.get('name', '未知')
try:
daily_limit = int(prize.get('dailyPrizeLimit', 0))
quantity = int(prize.get('quantity', 0))
prob = float(prize.get('probability', 0))
except:
daily_limit = 0
quantity = 0
prob = 0.0
# 判断奖品是否有效:包含指定关键词、不含排除关键词、概率>0
has_include = any(kw in name for kw in include_keywords)
has_exclude = any(kw in name for kw in exclude_keywords)
is_valid = has_include and not has_exclude and prob > 0
status = "✅" if is_valid else "❌"
if is_valid:
valid_count += 1
print(f" {status} [{i:02d}] {name}")
print(f" 今日投放: {daily_limit} | 总库存: {quantity} | 概率: {prob*100:.2f}%")
print(f"\n{'='*60}")
if valid_count > 0:
self.has_prizes = True
print(f"结论: 当前已放水!有效奖品 {valid_count}/{total} 个,可以抽奖")
else:
self.has_prizes = False
print(f"结论: 当前未放水!无有效奖品,跳过抽奖")
print("="*60 + "\n")
else:
print(f"奖品池查询失败: {result}")
self.has_prizes = False
except Exception as e:
print(f"奖品池查询异常: {str(e)}")
self.has_prizes = False
self.checked = True
return self.has_prizes
# 全局奖池状态实例
market_raffle_state = MarketRaffleState()
# ==================== Utils ====================
class Logger:
def __init__(self, prefix=""):
@@ -707,13 +792,15 @@ class CustomUserService:
result = res['result']
if result and result.get('code') == 200:
data = result.get('data', {})
triggered = data.get('triggeredTime', 0)
self.logger.log(f"浇花状态: {triggered}/{data.get('triggerTime')}")
if triggered == 0:
triggered = int(data.get('triggeredTime', 0))
trigger_time = int(data.get('triggerTime', 1))
self.logger.log(f"浇花状态: {triggered}/{trigger_time}")
# 只要未完成全部次数就继续浇花
if triggered < trigger_time:
await self.market_watering()
else:
self.logger.log("今日已完成浇花")
self.logger.log("浇花任务已全部完成")
else:
self.logger.log(f"获取浇花状态失败: {result}")
except Exception as e:
@@ -736,7 +823,29 @@ class CustomUserService:
except Exception as e:
self.logger.log(f"权益超市浇花异常: {str(e)}")
async def market_validate_captcha(self):
"""人机验证"""
try:
res = await self.http.request(
'POST',
'https://backward.bol.wo.cn/prod-api/promotion/home/raffleActivity/validateCaptcha?id=12',
headers={'Authorization': f'Bearer {self.market_token}'},
data=''
)
result = res['result']
if result and result.get('code') == 200:
self.logger.log("权益超市: 人机验证通过,继续抽奖")
return await self.market_raffle()
else:
self.logger.log(f"权益超市: 人机验证失败 {result}")
return False
except Exception as e:
self.logger.log(f"权益超市人机验证异常: {str(e)}")
return False
async def market_raffle_task(self):
"""权益超市抽奖任务"""
try:
y_gdtco4r = "0QDEN3AEqWlrU036_dbyBvP8.68dggpJ9Em3UEzaRWLwzFshel7nj1kEQxCiI.B_fIDMRTiEwAgmaG93mDGPLvSObw_.EMz5QG4wZp7CfpHt4y4WwUioW5NoIaRtTpiyNJN6ncFGlF607_haxxASNFfzwkxRl9XZq9UfHhGY.UCzebcoAawBTyh62PdjF.ka.HIygQuhbb16HitF0IfX_cdZc2wVsIUfLSnSYulZaLnoSo.7..nRFnMyydrDjQE4tfOT08heVczyyR6Bpn.ZazNvmNZD1EgfxCRTcQDUdHFb_XDfPbqvX2N0dtYdKgSV_1s5u8RlyUwXr1HlqKEpKb83uWfIPLaOpm3xFnKupjRqj1UoDz.vB0iRRkkYtAd8nPoY654drckOD7GEQQs79zJyMTZV_ExNU72MAqvZRdRUZZz8oho.t6WzyX5R2pOSrPRgO84hba3Ez52DbM_08n8qRm3bW1TaviGW1VEwQVH74R_Eo0pxoZDfHTbAGC3vAAzz7R8sqLVphu972XyCB72Ba1XGElelViYqGnG3p_SZ_LzzpQMJdGSa"
res = await self.http.request(
@@ -748,16 +857,19 @@ class CustomUserService:
},
data=''
)
result = res['result']
count = 0
if result and result.get('code') == 200:
count = result.get('data', 0)
self.logger.log(f"权益超市可抽奖次数: {count}")
for i in range(count):
await asyncio.sleep(3)
await self.market_raffle()
# 抽奖完成后查询奖池信息(仅展示,全局只查一次)
await market_raffle_state.check_prizes(self.http, self.market_token)
except Exception as e:
self.logger.log(f"权益超市抽奖任务异常: {str(e)}")
@@ -776,12 +888,24 @@ class CustomUserService:
result = res['result']
if result and result.get('code') == 200:
prize = result.get('data', {}).get('prizesName') or '未抽中'
self.logger.log(f"权益超市抽奖: {prize}", notify=True)
data = result.get('data', {})
prize = data.get('prizesName') or '未抽中'
message = data.get('message', '')
if prize and prize != '未抽中':
self.logger.log(f"权益超市抽奖: 恭喜抽中 {prize}", notify=True)
else:
self.logger.log(f"权益超市抽奖: {message or prize}")
return True
elif result and result.get('code') == 500:
# 触发人机验证
self.logger.log("权益超市: 触发人机验证,自动验证中...")
return await self.market_validate_captcha()
else:
self.logger.log(f"权益超市抽奖失败: {result}")
self.logger.log(f"权益超市抽奖失败: {result.get('message', result)}")
return False
except Exception as e:
self.logger.log(f"权益超市抽奖异常: {str(e)}")
return False
# ==================== Xinjiang (xj) ====================
async def xj_task(self):