#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 优化后的 Telegram 客户端代码 """ import asyncio from urllib.parse import unquote from typing import Optional, Dict, Any from loguru import logger from telethon import TelegramClient, functions, events, client from telethon.errors import ( NewSaltInvalidError, NewSettingsInvalidError, PasswordHashInvalidError, FloodWaitError, SessionPasswordNeededError ) from telethon.tl import types from telethon.tl.functions.account import GetAuthorizationsRequest, ResetAuthorizationRequest from telethon.tl.functions.channels import JoinChannelRequest from telethon.tl.functions.messages import RequestAppWebViewRequest, StartBotRequest from telethon.tl.types import InputBotAppShortName from models.tg_phone_devices import TgPhoneDevices class OptimizedTelegramClient: """优化的 Telegram 客户端类""" def __init__(self, server): self.server = server self.client = None self.verification_answers = { "年龄": "25", "职业": "程序员", "目的": "学习交流", "来自": "中国", "兴趣": "编程、阅读", "名字": "张三" } async def create_client(self) -> TelegramClient: """创建并配置 Telegram 客户端""" proxy = { 'proxy_type': self.server.proxy_type, 'addr': self.server.addr, 'port': int(self.server.port), 'username': self.server.user if self.server.user else "", 'password': self.server.pwd if self.server.pwd else "" } self.client = TelegramClient( fr"C:\sessions\{self.server.phone}", api_id=self.server.api_id, api_hash=self.server.api_hash, device_model=self.server.device_model, system_version=self.server.system_version, app_version=self.server.app_version, system_lang_code=self.server.system_lang_code, lang_code=self.server.lang_code, proxy=proxy ) return self.client async def connect_and_auth(self) -> bool: """连接并验证客户端""" try: await self.client.connect() if await self.client.is_user_authorized(): me = await self.client.get_me() logger.info(f'账号 {self.server.phone} -- {me.username} 登录成功!') return True else: logger.error(f'账号 {self.server.phone} 登录失败!') return False except Exception as e: logger.error(f"连接失败: {e}") return False async def setup_verification_handler(self): """设置验证问题处理器""" import re @self.client.on(events.NewMessage) async def handle_verification(event): try: message_text = event.message.text.strip() logger.info(f"收到消息: {message_text}") # ========== 1. 加法验证题处理 ========== match = re.match(r"(\d+)\s*\+\s*(\d+)", message_text) if match: a, b = int(match.group(1)), int(match.group(2)) answer = str(a + b) logger.info(f"检测到加法题: {a}+{b} 答案是 {answer}") # 获取按钮并点击正确答案 if event.buttons: for row in event.buttons: for button in row: if button.text.strip() == answer: await asyncio.sleep(2) # 模拟人工延迟 await event.click(button) logger.info(f"已点击正确答案按钮: {answer}") return # ========== 2. 关键字问答处理 ========== lower_text = message_text.lower() for keyword, answer in self.verification_answers.items(): if keyword in lower_text: logger.info(f"检测到验证问题: {message_text}") logger.info(f"自动回答: {answer}") await asyncio.sleep(2) await event.respond(answer) logger.info("验证答案已发送") return # ========== 3. 泛化验证提示 ========== if any(kw in message_text for kw in ['请回答', '请验证', '回答问题', '验证问题']): logger.info("检测到需要回答验证问题") except Exception as e: logger.error(f"处理验证问题时出错: {e}") async def join_channel(self, channel_name: str) -> bool: """加入频道/群组""" try: await self.client(JoinChannelRequest(channel_name)) logger.info(f"成功加入频道: {channel_name}") return True except FloodWaitError as e: logger.warning(f"需要等待 {e.seconds} 秒后重试") return False except Exception as e: logger.error(f"加入频道失败: {e}") return False async def check_bot_interaction(self, bot_username: str) -> bool: """检查是否与机器人有过交互""" try: async for dialog in self.client.iter_dialogs(): if dialog.is_user and dialog.entity.username == bot_username: logger.info(f'已与机器人交互: @{bot_username}') return True try: for username in dialog.entity.usernames: if username.username == bot_username: logger.info(f'已与机器人交互: @{bot_username}') return True except: pass logger.info(f'尚未与机器人交互: @{bot_username}') return False except Exception as e: logger.error(f"检查机器人交互时出错: {e}") return False async def start_bot_with_invite(self, bot_name: str, invite_code: str) -> bool: """使用邀请码启动机器人""" try: result = await self.client(StartBotRequest( bot=bot_name, peer=bot_name, start_param=invite_code )) logger.info(f"成功启动机器人 {bot_name} 使用邀请码 {invite_code}") return True except Exception as e: logger.error(f"启动机器人失败: {e}") return False async def get_webapp_data(self, bot_name: str, invite_code: Optional[str] = None) -> Optional[str]: """获取 WebApp 数据""" try: await self.client.get_input_entity(bot_name) app_info = await self.client(RequestAppWebViewRequest( 'me', InputBotAppShortName(await self.client.get_input_entity(bot_name), "app"), platform="web", start_param=invite_code if invite_code else None )) tg_data = unquote(app_info.url.split('tgWebAppData=')[1].split('&tgWebAppVersion')[0]) logger.info(f"成功获取 WebApp 数据: {tg_data[:50]}...") return tg_data except Exception as e: logger.error(f"获取 WebApp 数据失败: {e}") return None async def get_authorizations(self) -> list: """获取所有登录设备信息""" try: authorizations = await self.client(GetAuthorizationsRequest()) return authorizations.authorizations except Exception as e: logger.error(f"获取授权信息失败: {e}") return [] async def kick_device(self, target_device_model: str) -> bool: """踢出指定设备""" try: authorizations = await self.get_authorizations() for authorization in authorizations: if authorization.device_model == target_device_model and not authorization.current: await self.client(ResetAuthorizationRequest(hash=authorization.hash)) logger.info(f"已踢出设备: {authorization.device_model} (授权ID: {authorization.hash})") return True logger.warning(f"未找到设备: {target_device_model}") return False except Exception as e: logger.error(f"踢出设备失败: {e}") return False async def click_confirm_button(self, chat_id: int = 777000, limit: int = 5) -> bool: """点击确认按钮""" try: messages = await self.client.get_messages(chat_id, limit=limit) for message in messages: if message.buttons: for row in message.buttons: for button in row: if 'confirm' in button.text.lower(): await button.click() logger.info(f"已点击消息 {message.id} 的 Confirm 按钮") return True logger.warning("未找到包含 Confirm 按钮的消息") return False except Exception as e: logger.error(f"点击确认按钮失败: {e}") return False async def monitor_channel_messages(self, channel_name: str, duration: int = 60): """监控频道消息""" try: # 获取频道实体 entity = await self.get_channel_entity(channel_name) if not entity: logger.error(f"无法获取频道实体: {channel_name}") return logger.info(f"开始监控频道: {entity.title} (ID: {entity.id})") # 设置消息处理器 await self.setup_verification_handler(entity.id) # ✅ 使用 asyncio.wait_for 控制时间 try: await asyncio.wait_for(self.client.run_until_disconnected(), timeout=duration) except asyncio.TimeoutError: logger.info(f"监控 {duration} 秒结束,主动断开连接") await self.client.disconnect() except Exception as e: logger.error(f"监控频道消息时出错: {e}") async def run_with_verification(self, channel_name: str, wait_time: int = 60): """运行客户端并处理验证""" try: # 加入频道 if not await self.join_channel(channel_name): logger.error("加入频道失败") return # 监控频道消息 await self.monitor_channel_messages(channel_name, wait_time) except Exception as e: logger.error(f"运行过程中出错: {e}") finally: if self.client and self.client.is_connected(): await self.client.disconnect() logger.info("客户端已断开连接") async def main(): """主函数""" try: # 获取设备信息 server, server_type = TgPhoneDevices().get_or_create( phone="201285449831", ) # 创建客户端 tg_client = OptimizedTelegramClient(server) client = await tg_client.create_client() # 连接并验证 if not await tg_client.connect_and_auth(): logger.error("客户端验证失败") return # 运行主要功能 await tg_client.run_with_verification('newmoneyai', wait_time=60) except Exception as e: logger.error(f"主函数执行失败: {e}") if __name__ == '__main__': asyncio.run(main())