diff --git a/auto_gpt_team.py b/auto_gpt_team.py index 8f1c08a..fbdee83 100644 --- a/auto_gpt_team.py +++ b/auto_gpt_team.py @@ -606,6 +606,30 @@ def get_verification_content(target_email, max_retries=90): return None +def _is_shutdown_requested(): + """检查是否收到停止请求""" + try: + import run + return run._shutdown_requested + except Exception: + return False + + +def _is_connection_lost(error_msg): + """检查是否是连接断开错误(通常由 /stop 命令导致)""" + disconnect_keywords = [ + "connection to the page has been disconnected", + "page has been closed", + "target closed", + "session closed", + "browser has disconnected", + "no such window", + "invalid session id" + ] + error_lower = str(error_msg).lower() + return any(kw in error_lower for kw in disconnect_keywords) + + def run_payment_flow(page, email, step_callback=None): """执行 SEPA 支付流程 - 严格按顺序执行,任一步骤失败则终止 @@ -613,11 +637,21 @@ def run_payment_flow(page, email, step_callback=None): page: 浏览器页面对象 email: 邮箱地址 step_callback: 步骤回调函数 (step: str) + + Returns: + dict: 成功时返回 {"token": ..., "account_id": ...} + 被停止时返回 {"stopped": True} + 失败时返回 None """ def step_cb(step): if step_callback: step_callback(step) + # 检查停止请求 + if _is_shutdown_requested(): + log_progress("⚠ 检测到停止请求,中断支付流程") + return {"stopped": True} + log_status("支付流程", "开始处理 Stripe 支付页...") try: @@ -672,6 +706,11 @@ def run_payment_flow(page, email, step_callback=None): step_cb("填写支付邮箱...") log_progress("[步骤1] 填写邮箱...") try: + # 检查停止请求 + if _is_shutdown_requested(): + log_progress("⚠ 检测到停止请求") + return {"stopped": True} + # 如果之前已经找到了,直接使用;否则重新查找 if not email_input: email_input = page.ele('#email', timeout=10) @@ -688,6 +727,10 @@ def run_payment_flow(page, email, step_callback=None): log_progress(f"✓ 已填写邮箱: {email}") time.sleep(1) except Exception as e: + error_msg = str(e) + if _is_connection_lost(error_msg) or _is_shutdown_requested(): + log_progress("⚠ 检测到停止请求,中断支付流程") + return {"stopped": True} log_progress(f"❌ 邮箱填写失败: {e}") log_progress(f"当前URL: {page.url}") return None @@ -944,6 +987,11 @@ def run_payment_flow(page, email, step_callback=None): return None except Exception as e: + error_msg = str(e) + # 检查是否是连接断开(由 /stop 命令导致) + if _is_connection_lost(error_msg) or _is_shutdown_requested(): + log_status("停止", "⚠ 检测到停止请求,支付流程已中断") + return {"stopped": True} log_status("错误", f"[X] 支付流程异常: {e}") return None @@ -1138,22 +1186,29 @@ def run_main_process(): # === 注册流程 === log_status("步骤 1/5", "打开 ChatGPT 注册页...") page.get(TARGET_URL) + log_progress(f"当前URL: {page.url}") # 使用 data-testid 定位登录按钮 login_btn = page.ele('@data-testid=login-button', timeout=30) if not login_btn: login_btn = page.ele('css:button[data-testid*="login"], a[href*="auth"]', timeout=10) login_btn.click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") log_progress("填入邮箱...") email_input = page.ele('@name=email', timeout=30) email_input.input(email) page.ele('xpath://button[@type="submit"]').click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") log_progress("填入密码...") password_input = page.ele('xpath://input[@type="password"]', timeout=30) password_input.input(password) page.ele('xpath://button[@type="submit"]').click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") log_status("步骤 2/5", "等待邮件 (All Mail)...") @@ -1165,6 +1220,7 @@ def run_main_process(): if verify_data['type'] == 'link': page.new_tab(verify_data['val']) time.sleep(5) + log_progress(f"当前URL: {page.url}") elif verify_data['type'] == 'code': code = verify_data['val'] log_progress(f"填入验证码: {code}") @@ -1181,11 +1237,14 @@ def run_main_process(): continue_btn.click() except: log_progress("未找到按钮或已自动跳转...") + time.sleep(2) + log_progress(f"当前URL: {page.url}") except Exception as e: log_progress(f"验证码填入异常: {e}") # === 资料填写 (姓名+生日) === log_status("步骤 4/5", "进入信息填写页...") + log_progress(f"当前URL: {page.url}") try: name_input = page.ele('@name=name', timeout=20) name_input.input(real_name) @@ -1206,6 +1265,8 @@ def run_main_process(): # 点击继续/完成注册(使用 type=submit) final_reg_btn = page.ele('css:button[type="submit"]', timeout=20) final_reg_btn.click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") # ======================================================= # 【关键节点】等待进入主页后再执行 JS 跳转到支付页 @@ -1230,9 +1291,11 @@ def run_main_process(): if not entered_main: log_progress("⚠ 等待主页超时,尝试继续...") + log_progress(f"当前URL: {page.url}") # 尝试直接访问主页 page.get("https://chatgpt.com/") time.sleep(3) + log_progress(f"跳转后URL: {page.url}") # 额外等待页面稳定 time.sleep(3) @@ -1296,13 +1359,16 @@ def run_main_process(): # 等待 JS 执行完成 time.sleep(2) + log_progress(f"当前URL: {page.url}") # 等待跳转到支付页(使用 URL 检测代替固定等待) try: page.wait.url_change('pay.openai.com', timeout=15) log_progress("✓ 已跳转到支付页") + log_progress(f"支付页URL: {page.url}") except: - time.sleep(2) # 兜底等待 + time.sleep(2) + log_progress(f"当前URL: {page.url}") # 执行支付流程 result = run_payment_flow(page, email) @@ -1439,29 +1505,75 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict: page = ChromiumPage(co) if RANDOM_FINGERPRINT: inject_fingerprint(page, fingerprint) + except Exception as e: + log_status("浏览器", f"启动失败: {e},尝试清理后重试...") + cleanup_chrome_processes() + time.sleep(2) - # 注册流程 + # 重新配置 + co2 = ChromiumOptions() + co2.set_argument('--no-first-run') + co2.set_argument('--disable-infobars') + co2.set_argument('--incognito') + co2.set_argument('--disable-gpu') + co2.set_argument('--disable-dev-shm-usage') + co2.set_argument('--no-sandbox') + co2.set_argument('--disable-blink-features=AutomationControlled') + co2.set_argument('--lang=zh-CN') + co2.set_argument(f'--user-agent={fingerprint["user_agent"]}') + co2.set_argument('--headless=new') + co2.set_argument(f'--window-size={screen["width"]},{screen["height"]}') + + if is_linux: + co2.set_argument('--disable-software-rasterizer') + co2.set_argument('--disable-extensions') + co2.set_argument('--disable-setuid-sandbox') + co2.set_argument('--single-process') + co2.set_argument('--remote-debugging-port=0') + for chrome_path in chrome_paths: + if os.path.exists(chrome_path): + co2.set_browser_path(chrome_path) + break + else: + co2.auto_port(True) + co2.set_local_port(random.randint(30000, 39999)) + + try: + page = ChromiumPage(co2) + if RANDOM_FINGERPRINT: + inject_fingerprint(page, fingerprint) + except Exception as e2: + return {"success": False, "error": f"浏览器启动失败: {e2}", "account": email, "password": password} + + try: step_cb("打开注册页面...") log_status("步骤 1/5", "打开 ChatGPT 注册页...") page.get(TARGET_URL) + log_progress(f"当前URL: {page.url}") step_cb("点击登录按钮...") login_btn = page.ele('@data-testid=login-button', timeout=30) if not login_btn: login_btn = page.ele('css:button[data-testid*="login"], a[href*="auth"]', timeout=10) login_btn.click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") step_cb("填写邮箱...") log_progress("填入邮箱...") email_input = page.ele('@name=email', timeout=30) email_input.input(email) page.ele('xpath://button[@type="submit"]').click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") step_cb("填写密码...") log_progress("填入密码...") password_input = page.ele('xpath://input[@type="password"]', timeout=30) password_input.input(password) page.ele('xpath://button[@type="submit"]').click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") step_cb("等待验证邮件...") log_status("步骤 2/5", "等待邮件 (All Mail)...") @@ -1475,6 +1587,7 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict: if verify_data['type'] == 'link': page.new_tab(verify_data['val']) time.sleep(5) + log_progress(f"当前URL: {page.url}") elif verify_data['type'] == 'code': code = verify_data['val'] log_progress(f"填入验证码: {code}") @@ -1488,10 +1601,13 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict: continue_btn.click() except: log_progress("未找到按钮或已自动跳转...") + time.sleep(2) + log_progress(f"当前URL: {page.url}") # 资料填写 step_cb("填写个人信息...") log_status("步骤 4/5", "进入信息填写页...") + log_progress(f"当前URL: {page.url}") name_input = page.ele('@name=name', timeout=20) name_input.input(real_name) log_progress(f"姓名: {real_name}") @@ -1507,6 +1623,8 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict: time.sleep(1.5) final_reg_btn = page.ele('css:button[type="submit"]', timeout=20) final_reg_btn.click() + time.sleep(2) + log_progress(f"当前URL: {page.url}") # 等待进入主页 - 改进检测逻辑 step_cb("等待进入主页...") @@ -1530,9 +1648,11 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict: if not entered_main: log_progress("⚠ 等待主页超时,尝试继续...") + log_progress(f"当前URL: {page.url}") # 尝试直接访问主页 page.get("https://chatgpt.com/") time.sleep(3) + log_progress(f"跳转后URL: {page.url}") # 额外等待页面稳定 time.sleep(3) @@ -1576,18 +1696,25 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict: # 等待 JS 执行完成 time.sleep(2) + log_progress(f"当前URL: {page.url}") try: page.wait.url_change('pay.openai.com', timeout=15) log_progress("✓ 已跳转到支付页") + log_progress(f"支付页URL: {page.url}") except: time.sleep(2) + log_progress(f"当前URL: {page.url}") # 执行支付流程 step_cb("执行 SEPA 支付...") result = run_payment_flow(page, email, step_cb) - if result and result.get("token"): + if result and result.get("stopped"): + # 被 /stop 命令中断 + log_status("停止", "⚠ 注册被用户停止") + return {"success": False, "error": "用户停止", "stopped": True, "account": email, "password": password} + elif result and result.get("token"): step_cb("注册成功!") log_status("完成", "✓ 注册成功!") return { @@ -1602,6 +1729,11 @@ def run_single_registration(progress_callback=None, step_callback=None) -> dict: return {"success": False, "error": "支付流程失败", "account": email, "password": password} except Exception as e: + error_msg = str(e) + # 检查是否是连接断开(由 /stop 命令导致) + if _is_connection_lost(error_msg) or _is_shutdown_requested(): + log_status("停止", "⚠ 注册被用户停止") + return {"success": False, "error": "用户停止", "stopped": True, "account": email, "password": password} log_status("错误", f"注册异常: {e}") return {"success": False, "error": str(e), "account": email, "password": password} finally: diff --git a/telegram_bot.py b/telegram_bot.py index 3719fa3..bb4f900 100644 --- a/telegram_bot.py +++ b/telegram_bot.py @@ -2802,6 +2802,14 @@ class ProvisionerBot: # 开始注册任务 self.current_team = f"GPT Team 注册 ({count}个)" + + # 重置停止标志,确保新任务可以正常运行 + try: + import run + run._shutdown_requested = False + except Exception: + pass + self.current_task = asyncio.create_task( self._run_team_registration(query.message.chat_id, count, output_type) ) @@ -2908,7 +2916,11 @@ class ProvisionerBot: run_with_callback ) - if result.get("success"): + if result.get("stopped"): + # 被 /stop 命令中断,不计入失败 + log.info("注册被用户停止") + break + elif result.get("success"): success_count += 1 results.append({ "account": result["account"],