From 16cdba90d3a375964bdd7aa5164fdf2c1ecba608 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 21 Dec 2025 23:27:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=81=94=E9=80=9A=E9=98=85=E8=AF=BB):=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=81=94=E9=80=9A=E9=98=85=E8=AF=BB=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 woread_task 任务入口,支持自动登录、模拟阅读、抽奖、余额查询 - 实现 AES-CBC 加密(_woread_encode)用于接口数据加密 - 支持设备预登录(woread_auth)获取 accesstoken - 支持账号登录(woread_login)获取 usertoken - 模拟阅读功能:获取书籍信息、章节列表、心跳上报、添加阅读时长 - 每日抽奖功能(活动ID: 8051) - 话费红包余额查询 - 更新 README 文档添加联通阅读功能说明 --- README.md | 17 ++++ 中国联通.py | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 301 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5b37875..29be79d 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,17 @@ │ ├── _cloud_check_lottery_times 查询抽奖次数 │ └── _cloud_lottery ............ 执行抽奖 │ +│ └── 📚 联通阅读 (Woread) +│ ├── woread_task ............... 阅读任务入口 +│ ├── woread_auth ............... 设备预登录获取accesstoken +│ ├── woread_login .............. 账号登录获取usertoken +│ ├── woread_get_book_info ...... 获取书籍信息 +│ ├── woread_read_process ....... 模拟阅读任务 +│ ├── _woread_heartbeat ......... 阅读心跳上报 +│ ├── _woread_add_read_time ..... 添加阅读时长 +│ ├── woread_draw_new ........... 抽奖(活动ID:8051) +│ └── woread_queryTicketAccount . 查询话费红包余额 +│ └── 🚀 main (主程序入口) ............ 并发调度所有账号任务 ``` @@ -165,6 +176,12 @@ - **DeepSeek抽奖**: 通过DeepSeek对话获取抽奖资格并自动抽奖 - **积分统计**: 显示本次运行获得的积分数量 +### 联通阅读 +- **自动登录**: 设备预登录+账号登录双重认证 +- **模拟阅读**: 自动获取书籍信息并模拟阅读(心跳上报+阅读时长) +- **每日抽奖**: 完成阅读任务后自动执行抽奖 +- **余额查询**: 显示话费红包余额 + ## 🚀 快速开始 ### 1. 安装依赖 diff --git a/中国联通.py b/中国联通.py index d1a51e3..e490394 100644 --- a/中国联通.py +++ b/中国联通.py @@ -36,6 +36,12 @@ APP_ID = "86b8be06f56ba55e9fa7dff134c6b16c62ca7f319da4a958dd0afa0bf9f36f1daa9922 CLIENT_ID = "73b138fd-250c-4126-94e2-48cbcc8b9cbe" CLIENT_ID_2 = "1001000003" ANOTHER_API_KEY = "beea1c7edf7c4989b2d3621c4255132f" + +# ==================== Woread Constants ==================== +WOREAD_PRODUCT_ID = "10000002" +WOREAD_SECRET_KEY = "7k1HcDL8RKvc" +WOREAD_PASSWORD = "woreadst^&*12345" +WOREAD_IV = "16-Bytes--String" ANOTHER_ENCRYPTION_KEY = "f4cd4ffeb5554586acf65ba7110534f5" SERVICE_LIFE = "wocareMBHServiceLife1" MIN_RETRIES = "1" @@ -2536,7 +2542,8 @@ class CustomUserService: ) result = res['result'] if result and '0000' in str(result.get('code', '')) and result.get('data', {}).get('score'): - self.logger.log(f"云盘签到: +{result['data']['score']}积分") + #self.logger.log(f"云盘签到: +{result['data']['score']}积分") + pass elif result: self.logger.log(f"云盘签到失败: {result.get('msg', result)}") except Exception as e: @@ -2578,8 +2585,8 @@ class CustomUserService: if match: score = int(match.group(1)) - if score > 0: - self.logger.log(f"云盘任务: +{score}积分") + #if score > 0: + #self.logger.log(f"云盘任务: +{score}积分") return True else: self.logger.log(f"云盘领取奖励失败: {result}") @@ -3059,6 +3066,279 @@ class CustomUserService: except Exception as e: self.logger.log(f"商都福利签到重试异常: {str(e)}") + # ==================== Woread (联通阅读) ==================== + + def _woread_encode(self, data, password=WOREAD_PASSWORD): + """联通阅读AES-CBC加密""" + if not HAS_CRYPTO: + return "" + try: + text = json.dumps(data, separators=(',', ':')) if isinstance(data, (dict, list)) else str(data) + key = password.encode('utf-8') + iv = WOREAD_IV.encode('utf-8') + cipher = AES.new(key, AES.MODE_CBC, iv) + encrypted = cipher.encrypt(pad(text.encode('utf-8'), AES.block_size)) + return base64.b64encode(encrypted).decode('utf-8') + except Exception as e: + self.logger.log(f"联通阅读加密异常: {str(e)}") + return "" + + async def woread_auth(self): + """联通阅读: 设备预登录获取accesstoken""" + try: + timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3] + sign_str = f"{WOREAD_PRODUCT_ID}{timestamp}{WOREAD_SECRET_KEY}" + md5_hash = hashlib.md5(sign_str.encode('utf-8')).hexdigest() + + data = { + 'deviceId': self.random_string(32, '0123456789abcdef'), + 'deviceType': '1', + 'clientVersion': '6.0.0' + } + encrypted_data = self._woread_encode(data) + + res = await self.http.request( + 'POST', + f'https://10010.woread.com.cn/ng_woread_service/rest/app/auth/{WOREAD_PRODUCT_ID}/{timestamp}/{md5_hash}', + headers={ + 'Content-Type': 'text/plain;charset=UTF-8', + 'User-Agent': 'okhttp/3.14.9' + }, + data=encrypted_data + ) + + result = res['result'] + if result and str(result.get('code')) == '0': + self.woread_accesstoken = result.get('accesstoken', '') + return True + return False + except Exception as e: + self.logger.log(f"联通阅读预登录异常: {str(e)}") + return False + + async def woread_login(self): + """联通阅读: 账号登录""" + try: + if not await self.woread_auth(): + return False + + data = { + 'phone': self.mobile, + 'token': self.token_online, + 'productId': WOREAD_PRODUCT_ID, + 'time': datetime.now().strftime("%Y%m%d%H%M%S%f")[:-3] + } + encrypted_data = self._woread_encode(data) + + res = await self.http.request( + 'POST', + 'https://10010.woread.com.cn/ng_woread_service/rest/account/login', + headers={ + 'accesstoken': self.woread_accesstoken, + 'Content-Type': 'text/plain;charset=UTF-8', + 'User-Agent': 'okhttp/3.14.9' + }, + data=encrypted_data + ) + + result = res['result'] + if result and str(result.get('code')) == '0': + self.woread_usertoken = result.get('usertoken', '') + return True + else: + msg = result.get('msg', '') if result else '请求失败' + self.logger.log(f"联通阅读登录失败: {msg}") + return False + except Exception as e: + self.logger.log(f"联通阅读登录异常: {str(e)}") + return False + + async def woread_get_book_info(self): + """联通阅读: 获取书籍信息""" + try: + res = await self.http.request( + 'GET', + 'https://10010.woread.com.cn/ng_woread_service/rest/basics/recommposdetail/14856', + headers={ + 'accesstoken': self.woread_accesstoken, + 'usertoken': self.woread_usertoken, + 'User-Agent': 'okhttp/3.14.9' + } + ) + + result = res['result'] + if result and str(result.get('code')) == '0': + return result.get('recommPos', {}) + return None + except Exception as e: + self.logger.log(f"联通阅读获取书籍异常: {str(e)}") + return None + + async def woread_read_process(self): + """联通阅读: 阅读任务(模拟阅读)""" + try: + book_info = await self.woread_get_book_info() + if not book_info: + self.logger.log("联通阅读: 获取书籍信息失败") + return + + book_id = book_info.get('bookId', '978752838809620240101') + chapter_id = book_info.get('chapterId', '978752838809620240101001') + + # 获取章节列表 + data = {'bookId': book_id, 'chapterId': chapter_id, 'pageNo': 1, 'pageSize': 20} + encrypted_data = self._woread_encode(data) + + res = await self.http.request( + 'POST', + 'https://10010.woread.com.cn/ng_woread_service/rest/cnt/chalist', + headers={ + 'accesstoken': self.woread_accesstoken, + 'usertoken': self.woread_usertoken, + 'Content-Type': 'text/plain;charset=UTF-8', + 'User-Agent': 'okhttp/3.14.9' + }, + data=encrypted_data + ) + + result = res['result'] + if not result or str(result.get('code')) != '0': + self.logger.log("联通阅读: 获取章节列表失败") + return + + chapters = result.get('list', []) + if not chapters: + return + + # 模拟阅读3次 + for i in range(3): + await asyncio.sleep(3) + chapter = chapters[i % len(chapters)] + await self._woread_heartbeat(book_id, chapter.get('chapterId', chapter_id)) + + # 添加阅读时长 + await self._woread_add_read_time(book_id, chapter_id) + + except Exception as e: + self.logger.log(f"联通阅读阅读任务异常: {str(e)}") + + async def _woread_heartbeat(self, book_id, chapter_id): + """联通阅读: 阅读心跳""" + try: + words_detail = [{'chapterId': chapter_id, 'words': random.randint(500, 1500)}] + data = { + 'bookId': book_id, + 'chapterId': chapter_id, + 'wordsDetail': words_detail, + 'readTime': random.randint(60, 180) + } + encrypted_data = self._woread_encode(data) + + await self.http.request( + 'POST', + 'https://10010.woread.com.cn/ng_woread_service/rest/history/heartbeat', + headers={ + 'accesstoken': self.woread_accesstoken, + 'usertoken': self.woread_usertoken, + 'Content-Type': 'text/plain;charset=UTF-8', + 'User-Agent': 'okhttp/3.14.9' + }, + data=encrypted_data + ) + except: + pass + + async def _woread_add_read_time(self, book_id, chapter_id): + """联通阅读: 添加阅读时长""" + try: + data = { + 'bookId': book_id, + 'chapterId': chapter_id, + 'readTime': random.randint(300, 600) + } + encrypted_data = self._woread_encode(data) + + await self.http.request( + 'POST', + 'https://10010.woread.com.cn/ng_woread_service/rest/history/addReadTime', + headers={ + 'accesstoken': self.woread_accesstoken, + 'usertoken': self.woread_usertoken, + 'Content-Type': 'text/plain;charset=UTF-8', + 'User-Agent': 'okhttp/3.14.9' + }, + data=encrypted_data + ) + except: + pass + + async def woread_draw_new(self): + """联通阅读: 抽奖""" + try: + data = {'activeindex': '8051'} + encrypted_data = self._woread_encode(data) + + res = await self.http.request( + 'POST', + 'https://10010.woread.com.cn/ng_woread_service/rest/basics/doDraw', + headers={ + 'accesstoken': self.woread_accesstoken, + 'usertoken': self.woread_usertoken, + 'Content-Type': 'text/plain;charset=UTF-8', + 'User-Agent': 'okhttp/3.14.9' + }, + data=encrypted_data + ) + + result = res['result'] + if result and str(result.get('code')) == '0': + prize = result.get('giftname', '未知奖品') + self.logger.log(f"联通阅读抽奖: {prize}", notify=True) + else: + msg = result.get('msg', '') if result else '请求失败' + if '已抽' in msg or '次数' in msg: + self.logger.log(f"联通阅读: {msg}") + else: + self.logger.log(f"联通阅读抽奖失败: {msg}") + except Exception as e: + self.logger.log(f"联通阅读抽奖异常: {str(e)}") + + async def woread_queryTicketAccount(self): + """联通阅读: 查询话费红包余额""" + try: + data = {'type': '1'} + encrypted_data = self._woread_encode(data) + + res = await self.http.request( + 'POST', + 'https://10010.woread.com.cn/ng_woread_service/rest/phone/vouchers/queryTicketAccount', + headers={ + 'accesstoken': self.woread_accesstoken, + 'usertoken': self.woread_usertoken, + 'Content-Type': 'text/plain;charset=UTF-8', + 'User-Agent': 'okhttp/3.14.9' + }, + data=encrypted_data + ) + + result = res['result'] + if result and str(result.get('code')) == '0': + balance = result.get('balance', 0) + self.logger.log(f"联通阅读话费红包余额: {float(balance)/100:.2f}元", notify=True) + except Exception as e: + self.logger.log(f"联通阅读查询余额异常: {str(e)}") + + async def woread_task(self): + """联通阅读任务入口""" + if not await self.woread_login(): + return + + await self.woread_read_process() + await asyncio.sleep(3) + await self.woread_draw_new() + await asyncio.sleep(3) + await self.woread_queryTicketAccount() + async def user_task(self): #self.logger.log(f"\n------------------ 账号 {self.mobile} ------------------") if not await self.online(): @@ -3073,6 +3353,7 @@ class CustomUserService: await self.security_butler_task() await self.cloud_disk_task() await self.shangdu_task() + await self.woread_task() async def main(): start_time = datetime.now()