diff --git a/.env b/.env index f2b145a..4a325b7 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -version=1.0.10 -VERSION=1.0.10 +version=1.1.01 +VERSION=1.1.01 diff --git a/blacklist.txt b/blacklist.txt new file mode 100644 index 0000000..10f9030 --- /dev/null +++ b/blacklist.txt @@ -0,0 +1,5 @@ +fr.nf +yopmail.com +1s.fr +xl.cx +fr.cr \ No newline at end of file diff --git a/browser.py b/browser.py index b613563..b03c4c9 100644 --- a/browser.py +++ b/browser.py @@ -27,12 +27,15 @@ class BrowserManager: try: extension_path = self._get_extension_path() co.add_extension(extension_path) + co.set_argument("--allow-extensions-in-incognito") extension_block_path = self.get_extension_block() co.add_extension(extension_block_path) + co.set_argument("--allow-extensions-in-incognito") extension_recaptcha_path = self.get_extension_recaptcha() co.add_extension(extension_recaptcha_path) + co.set_argument("--allow-extensions-in-incognito") except FileNotFoundError as e: logging.warning(f"警告: {e}") diff --git a/build.spec b/build.spec index 9cd0e46..d5bc2ee 100644 --- a/build.spec +++ b/build.spec @@ -32,7 +32,8 @@ a = Analysis( ('cursor_register.py', '.'), ('browser.py', '.'), ('control.py', '.'), - ('.env', '.') + ('.env', '.'), + ('blacklist.txt', '.') ], hiddenimports=[ 'cursor_auth', diff --git a/control.py b/control.py index 64fda3c..96d36e9 100644 --- a/control.py +++ b/control.py @@ -77,41 +77,53 @@ class BrowserControl: return False def select_email_domain(self, domain_index=None): - """选择邮箱域名,如果不指定index则随机选择。避免选择fr.nf域名""" + """选择邮箱域名,如果不指定index则随机选择""" try: print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}...{Style.RESET_ALL}") + + # 读取黑名单域名 + blacklist = [] + try: + with open('blacklist.txt', 'r', encoding='utf-8') as f: + blacklist = [line.strip().lower() for line in f if line.strip()] + except FileNotFoundError: + # 如果文件不存在,创建一个包含已知黑名单域名的文件 + with open('blacklist.txt', 'w', encoding='utf-8') as f: + f.write("fr.nf\nyopmail.com\n1s.fr\nfr.cr") + blacklist = ["fr.nf", "yopmail.com", "1s.fr", "fr.cr"] + # 找到下拉框 select_element = self.browser.ele('xpath://select[@id="seldom"]') if select_element: - # 获取所有选项,包括两个 optgroup 下的所有 option + # 获取所有选项 all_options = [] - - # 获取 "新的" 组下的选项 new_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 新的 --"]/option') - all_options.extend(new_options) - - # 获取 "其他" 组下的选项 other_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 其他 --"]/option') + all_options.extend(new_options) all_options.extend(other_options) if all_options: - max_attempts = 5 # 最大尝试次数 + max_attempts = 5 attempt = 0 while attempt < max_attempts: - # 如果没有指定索引,随机选择一个 if domain_index is None: domain_index = random.randint(0, len(all_options) - 1) if domain_index < len(all_options): - # 获取选中选项的文本 - selected_domain = all_options[domain_index].text + selected_domain = all_options[domain_index].text.lower() - # 检查是否为fr.nf域名 - if "fr.nf" in selected_domain.lower(): - print(f"{Fore.YELLOW}{EMOJI['INFO']} 检测到fr.nf域名,重新选择...{Style.RESET_ALL}") - domain_index = None # 重置索引以便重新随机选择 - attempt += 1 + # 检查域名是否在黑名单中 + is_blacklisted = False + for blocked_domain in blacklist: + if blocked_domain in selected_domain: + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('control.blocked_domain', domain=blocked_domain)}{Style.RESET_ALL}") + domain_index = None + attempt += 1 + is_blacklisted = True + break + + if is_blacklisted: continue print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}: {selected_domain}{Style.RESET_ALL}") @@ -124,7 +136,7 @@ class BrowserControl: attempt += 1 - print(f"{Fore.RED}{EMOJI['ERROR']} 无法找到合适的非fr.nf域名{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} 无法找到可用的域名{Style.RESET_ALL}") return False print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_available_domain_options', count=len(all_options))}{Style.RESET_ALL}") @@ -132,6 +144,7 @@ class BrowserControl: else: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_domain_select_box')}{Style.RESET_ALL}") return False + except Exception as e: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.select_email_domain_failed', error=str(e))}{Style.RESET_ALL}") return False diff --git a/cursor_register.py b/cursor_register.py index a039cc2..f274013 100644 --- a/cursor_register.py +++ b/cursor_register.py @@ -96,238 +96,51 @@ class CursorRegistration: def register_cursor(self): """注册 Cursor""" - signup_browser_manager = None + browser_tab = None try: print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}") - # 创建新的浏览器实例用于注册 - from browser import BrowserManager - signup_browser_manager = BrowserManager(noheader=False) - self.signup_tab = signup_browser_manager.init_browser() + # 直接使用 new_signup.py 进行注册 + from new_signup import main as new_signup_main - # 访问注册页面 - self.signup_tab.get(self.sign_up_url) - time.sleep(2) - - # 填写注册表单 - if self.signup_tab.ele("@name=first_name"): - print(f"{Fore.CYAN}{EMOJI['FORM']} {self.translator.get('register.filling_form')}...{Style.RESET_ALL}") - - self.signup_tab.ele("@name=first_name").input(self.first_name) - time.sleep(random.uniform(1, 2)) - - self.signup_tab.ele("@name=last_name").input(self.last_name) - time.sleep(random.uniform(1, 2)) - - self.signup_tab.ele("@name=email").input(self.email_address) - time.sleep(random.uniform(1, 2)) - - self.signup_tab.ele("@type=submit").click() - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.basic_info_submitted')}...{Style.RESET_ALL}") - - # 处理 Turnstile 验证 - self._handle_turnstile() - - # 设置密码 - if self.signup_tab.ele("@name=password"): - print(f"{Fore.CYAN}{EMOJI['PASSWORD']} {self.translator.get('register.set_password')}...{Style.RESET_ALL}") - self.signup_tab.ele("@name=password").input(self.password) - time.sleep(random.uniform(1, 2)) - self.signup_tab.ele("@type=submit").click() + # 执行新的注册流程,传入 translator + result, browser_tab = new_signup_main( + email=self.email_address, + password=self.password, + first_name=self.first_name, + last_name=self.last_name, + email_tab=self.email_tab, + controller=self.controller, + translator=self.translator + ) - self._handle_turnstile() - - # 等待并获取验证码 - time.sleep(5) # 等待验证码邮件 - - self.browser.refresh() + if result: + # 使用返回的浏览器实例获取账户信息 + self.signup_tab = browser_tab # 保存浏览器实例 + success = self._get_account_info() + + # 获取信息后关闭浏览器 + if browser_tab: + try: + browser_tab.quit() + except: + pass + + return success - # 获取验证码,设置60秒超时 - verification_code = None - max_attempts = 20 # 增加到10次尝试 - retry_interval = 10 # 每5秒重试一次 - start_time = time.time() - timeout = 160 # 60秒超时 - - print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.start_getting_verification_code')}...{Style.RESET_ALL}") + return False - for attempt in range(max_attempts): - # 检查是否超时 - if time.time() - start_time > timeout: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.get_verification_code_timeout')}...{Style.RESET_ALL}") - break - - verification_code = self.controller.get_verification_code() - if verification_code: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.get_verification_code_success')}: {verification_code}{Style.RESET_ALL}") - break - - remaining_time = int(timeout - (time.time() - start_time)) - print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.try_get_verification_code', attempt=attempt + 1, remaining_time=remaining_time)}...{Style.RESET_ALL}") - - # 刷新邮箱 - self.browser.refresh() - time.sleep(retry_interval) - - if verification_code: - # 在注册页面填写验证码 - for i, digit in enumerate(verification_code): - self.signup_tab.ele(f"@data-index={i}").input(digit) - time.sleep(random.uniform(0.1, 0.3)) - - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.verification_code_filled')}...{Style.RESET_ALL}") - time.sleep(3) - - self._handle_turnstile() - - # 检查当前URL - current_url = self.signup_tab.url - if "authenticator.cursor.sh" in current_url: - print(f"{Fore.CYAN}{EMOJI['VERIFY']} {self.translator.get('register.detect_login_page')}...{Style.RESET_ALL}") - - # 填写邮箱 - email_input = self.signup_tab.ele('@name=email') - if email_input: - email_input.input(self.email_address) - time.sleep(random.uniform(1, 2)) - - # 点击提交 - submit_button = self.signup_tab.ele('@type=submit') - if submit_button: - submit_button.click() - time.sleep(2) - - # 处理 Turnstile 验证 - self._handle_turnstile() - - # 填写密码 - password_input = self.signup_tab.ele('@name=password') - if password_input: - password_input.input(self.password) - time.sleep(random.uniform(1, 2)) - - # 点击提交 - submit_button = self.signup_tab.ele('@type=submit') - if submit_button: - submit_button.click() - time.sleep(2) - - # 处理 Turnstile 验证 - self._handle_turnstile() - - # 等待跳转到设置页面 - max_wait = 30 - start_time = time.time() - while time.time() - start_time < max_wait: - if "cursor.com/settings" in self.signup_tab.url: - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.login_success_and_jump_to_settings_page')}...{Style.RESET_ALL}") - break - time.sleep(1) - - # 获取账户信息 - result = self._get_account_info() - - # 关闭注册窗口 - if signup_browser_manager: - signup_browser_manager.quit() - - return result - else: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.get_verification_code_timeout')}...{Style.RESET_ALL}") - return False - except Exception as e: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}") return False finally: - # 确保在任何情况下都关闭注册窗口 - if signup_browser_manager: - signup_browser_manager.quit() - - def _handle_turnstile(self): - """处理 Turnstile 验证""" - try: - print(f"{Fore.YELLOW}{EMOJI['VERIFY']} {self.translator.get('register.handle_turnstile')}...{Style.RESET_ALL}") - - max_retries = 2 - retry_interval = (1, 2) - retry_count = 0 - - while retry_count < max_retries: - retry_count += 1 - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.turnstile_attempt', attempt=retry_count)}...{Style.RESET_ALL}") - + # 确保在任何情况下都关闭浏览器 + if browser_tab: try: - # 尝试重置 turnstile - self.signup_tab.run_js("try { turnstile.reset() } catch(e) { }") - time.sleep(2) - - # 定位验证框元素 - challenge_check = ( - self.signup_tab.ele("@id=cf-turnstile", timeout=2) - .child() - .shadow_root.ele("tag:iframe") - .ele("tag:body") - .sr("tag:input") - ) - - if challenge_check: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.turnstile_detected')}...{Style.RESET_ALL}") - - # 随机延时后点击验证 - time.sleep(random.uniform(1, 3)) - challenge_check.click() - time.sleep(2) - - # 检查验证结果 - if self._check_verification_success(): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}") - return True - - except Exception as e: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('register.turnstile_attempt_failed', error=str(e))}{Style.RESET_ALL}") - - # 检查是否已经验证成功 - if self._check_verification_success(): - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}") - return True - - # 随机延时后继续下一次尝试 - time.sleep(random.uniform(*retry_interval)) - - # 超出最大重试次数 - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.turnstile_max_retries', max=max_retries)}{Style.RESET_ALL}") - return False - - except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.turnstile_error', error=str(e))}{Style.RESET_ALL}") - return False - - def _check_verification_success(self): - """检查验证是否成功""" - try: - # 检查是否存在后续表单元素,这表示验证已通过 - if (self.signup_tab.ele("@name=password", timeout=0.5) or - self.signup_tab.ele("@name=email", timeout=0.5) or - self.signup_tab.ele("@data-index=0", timeout=0.5) or - self.signup_tab.ele("Account Settings", timeout=0.5)): - return True - - # 检查是否出现错误消息 - error_messages = [ - 'xpath://div[contains(text(), "Can\'t verify the user is human")]', - 'xpath://div[contains(text(), "Error: 600010")]', - 'xpath://div[contains(text(), "Please try again")]' - ] - - for error_xpath in error_messages: - if self.signup_tab.ele(error_xpath): - return False + browser_tab.quit() + except: + pass - return False - except: - return False - def _get_account_info(self): """获取账户信息和 Token""" try: diff --git a/locales/en.json b/locales/en.json index ec73366..d6d1110 100644 --- a/locales/en.json +++ b/locales/en.json @@ -66,12 +66,25 @@ }, "register": { "title": "Cursor Registration Tool", - - "start": "Starting Registration Process", + "handling_turnstile": "Handling Turnstile", + "retry_verification": "Retry Verification", + "detect_turnstile": "Detect Turnstile", + "verification_success": "Verification Success", + "starting_browser": "Starting Browser", + "form_success": "Form Success", + "browser_started": "Browser Started", + "waiting_for_second_verification": "Waiting for Second Verification", + "waiting_for_verification_code": "Waiting for Verification Code", + "password_success": "Password Set Successfully", + "password_error": "Password Set Failed: {error}", + "waiting_for_page_load": "Waiting for Page Load", + "first_verification_passed": "First Verification Passed", "mailbox": "Successfully Entered Mailbox", "register_start": "Start Register", + "form_submitted": "Form Submitted, Start Verification...", "filling_form": "Fill Form", + "visiting_url": "Visiting URL", "basic_info": "Basic Info Submitted", "handle_turnstile": "Handle Turnstile", "no_turnstile": "Not Detect Turnstile", @@ -131,6 +144,7 @@ }, "control": { "generate_email": "Generating New Email", + "blocked_domain": "Blocked Domain", "select_domain": "Selecting Random Domain", "copy_email": "Copying Email Address", "enter_mailbox": "Entering Mailbox", @@ -158,6 +172,7 @@ "get_cursor_session_token_failed": "Get Cursor Session Token Failed", "save_token_failed": "Save Token Failed", "database_updated_successfully": "Database Updated Successfully", - "database_connection_closed": "Database Connection Closed" + "database_connection_closed": "Database Connection Closed", + "no_valid_verification_code": "No Valid Verification Code" } } \ No newline at end of file diff --git a/locales/zh_cn.json b/locales/zh_cn.json index 336fe39..baa3496 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -67,10 +67,25 @@ "register": { "title": "Cursor 注册工具", "start": "开始注册流程", + "browser_started": "浏览器已启动", + "password_success": "密码设置完成", + "password_error": "密码设置失败: {error}", + "waiting_for_page_load": "等待页面加载", "mailbox": "成功进入邮箱", + "waiting_for_second_verification": "等待第二阶段验证", + "waiting_for_verification_code": "等待验证码", + "first_verification_passed": "第一阶段验证通过", "register_start": "开始注册流程", + "form_submitted": "表单已提交,开始验证...", "filling_form": "填写注册信息", + "visiting_url": "访问URL", "basic_info": "基本信息提交完成", + "handling_turnstile": "处理 Turnstile 验证", + "retry_verification": "重试验证", + "detect_turnstile": "检测 Turnstile 验证", + "verification_success": "验证成功", + "starting_browser": "启动浏览器", + "form_success": "表单提交成功", "handle_turnstile": "处理 Turnstile 验证", "no_turnstile": "未检测到 Turnstile 验证", "turnstile_passed": "验证通过", @@ -131,6 +146,7 @@ "select_domain": "选择随机域名", "copy_email": "复制邮箱地址", "enter_mailbox": "进入邮箱", + "blocked_domain": "被屏蔽的域名", "refresh_mailbox": "刷新邮箱", "check_verification": "检查验证码", "verification_found": "找到验证码", @@ -153,6 +169,7 @@ "get_cursor_session_token": "获取Cursor Session Token", "get_cursor_session_token_success": "获取Cursor Session Token成功", "get_cursor_session_token_failed": "获取Cursor Session Token失败", - "save_token_failed": "保存Token失败" + "save_token_failed": "保存Token失败", + "no_valid_verification_code": "没有有效的验证码" } } \ No newline at end of file diff --git a/locales/zh_tw.json b/locales/zh_tw.json index 4d7c04e..7247aac 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -64,21 +64,32 @@ "version_check_passed": "Cursor版本檢查通過", "file_modified": "文件已修改" }, - - - - "register": { "title": "Cursor 註冊工具", "start": "開始註冊流程", "mailbox": "成功進入郵箱", + "browser_started": "瀏覽器已啟動", + "waiting_for_page_load": "等待頁面加載", + "password_success": "密碼設置完成", + "password_error": "密碼設置失敗: {error}", + "visiting_url": "訪問URL", + "first_verification_passed": "第一階段驗證通過", "register_start": "開始註冊流程", + "form_submitted": "表單已提交,開始驗證...", + "waiting_for_second_verification": "等待第二階段驗證", "filling_form": "填寫註冊信息", "basic_info": "基本信息提交完成", "handle_turnstile": "處理 Turnstile 驗證", "no_turnstile": "未檢測到 Turnstile 驗證", "turnstile_passed": "驗證通過", "verification_start": "開始獲取驗證碼", + "waiting_for_verification_code": "等待驗證碼", + "handling_turnstile": "處理 Turnstile 驗證", + "retry_verification": "重試驗證", + "detect_turnstile": "檢測 Turnstile 驗證", + "verification_success": "驗證成功", + "starting_browser": "啟動瀏覽器", + "form_success": "表單提交成功", "verification_timeout": "獲取驗證碼超時", "verification_not_found": "未找到驗證碼", "try_get_code": "第 {attempt} 次嘗試獲取驗證碼 | 剩餘時間: {time}秒", @@ -157,6 +168,8 @@ "get_cursor_session_token": "獲取Cursor Session Token", "get_cursor_session_token_success": "獲取Cursor Session Token成功", "get_cursor_session_token_failed": "獲取Cursor Session Token失敗", - "save_token_failed": "保存Token失敗" + "save_token_failed": "保存Token失敗", + "blocked_domain": "被屏蔽的域名", + "no_valid_verification_code": "沒有有效的驗證碼" } } \ No newline at end of file diff --git a/new_signup.py b/new_signup.py new file mode 100644 index 0000000..5917101 --- /dev/null +++ b/new_signup.py @@ -0,0 +1,468 @@ +from DrissionPage import ChromiumOptions, ChromiumPage +import time +import os +import signal +import random + +# 在文件开头添加全局变量 +_translator = None + +def cleanup_chrome_processes(translator=None): + """清理所有Chrome相关进程""" + print("\n正在清理Chrome进程...") + try: + if os.name == 'nt': + os.system('taskkill /F /IM chrome.exe /T 2>nul') + os.system('taskkill /F /IM chromedriver.exe /T 2>nul') + else: + os.system('pkill -f chrome') + os.system('pkill -f chromedriver') + except Exception as e: + if translator: + print(f"{translator.get('register.cleanup_error', error=str(e))}") + else: + print(f"清理进程时出错: {e}") + +def signal_handler(signum, frame): + """处理Ctrl+C信号""" + global _translator + if _translator: + print(f"{_translator.get('register.exit_signal')}") + else: + print("\n接收到退出信号,正在关闭...") + cleanup_chrome_processes(_translator) + os._exit(0) + +def simulate_human_input(page, url, translator=None): + """访问网址""" + if translator: + print(f"{translator.get('register.visiting_url')}: {url}") + else: + print("正在访问网址...") + + # 先访问空白页面 + page.get('about:blank') + time.sleep(random.uniform(1.0, 2.0)) + + # 访问目标页面 + page.get(url) + time.sleep(random.uniform(2.0, 3.0)) # 等待页面加载 + +def fill_signup_form(page, first_name, last_name, email, translator=None): + """填写注册表单""" + try: + if translator: + print(f"{translator.get('register.filling_form')}") + else: + print("\n正在填写注册表单...") + + # 填写名字 + first_name_input = page.ele("@name=first_name") + if first_name_input: + first_name_input.input(first_name) + time.sleep(random.uniform(0.5, 1.0)) + + # 填写姓氏 + last_name_input = page.ele("@name=last_name") + if last_name_input: + last_name_input.input(last_name) + time.sleep(random.uniform(0.5, 1.0)) + + # 填写邮箱 + email_input = page.ele("@name=email") + if email_input: + email_input.input(email) + time.sleep(random.uniform(0.5, 1.0)) + + # 点击提交按钮 + submit_button = page.ele("@type=submit") + if submit_button: + submit_button.click() + time.sleep(random.uniform(2.0, 3.0)) + + if translator: + print(f"{translator.get('register.form_success')}") + else: + print("表单填写完成") + return True + + except Exception as e: + if translator: + print(f"{translator.get('register.form_error', error=str(e))}") + else: + print(f"填写表单时出错: {e}") + return False + +def setup_driver(translator=None): + """设置浏览器驱动""" + co = ChromiumOptions() + + # 使用无痕模式 + co.set_argument("--incognito") + + # 设置随机端口 + co.auto_port() + + # 使用有头模式 + co.headless(False) + + try: + # 加载插件 + extension_path = os.path.join(os.getcwd(), "turnstilePatch") + if os.path.exists(extension_path): + co.set_argument("--allow-extensions-in-incognito") + co.add_extension(extension_path) + except Exception as e: + if translator: + print(f"{translator.get('register.extension_load_error', error=str(e))}") + else: + print(f"加载插件失败: {e}") + + if translator: + print(f"{translator.get('register.starting_browser')}") + else: + print("正在启动浏览器...") + page = ChromiumPage(co) + + return page + +def handle_turnstile(page, translator=None): + """处理 Turnstile 验证""" + try: + if translator: + print(f"{translator.get('register.handling_turnstile')}") + else: + print("\n正在处理 Turnstile 验证...") + + max_retries = 2 + retry_count = 0 + + while retry_count < max_retries: + retry_count += 1 + if translator: + print(f"{translator.get('register.retry_verification', attempt=retry_count)}") + else: + print(f"第 {retry_count} 次尝试验证...") + + try: + # 尝试重置 turnstile + page.run_js("try { turnstile.reset() } catch(e) { }") + time.sleep(2) + + # 定位验证框元素 + challenge_check = ( + page.ele("@id=cf-turnstile", timeout=2) + .child() + .shadow_root.ele("tag:iframe") + .ele("tag:body") + .sr("tag:input") + ) + + if challenge_check: + if translator: + print(f"{translator.get('register.detect_turnstile')}") + else: + print("检测到验证框...") + + # 随机延时后点击验证 + time.sleep(random.uniform(1, 3)) + challenge_check.click() + time.sleep(2) + + # 检查验证结果 + if check_verification_success(page, translator): + if translator: + print(f"{translator.get('register.verification_success')}") + else: + print("验证通过!") + return True + + except Exception as e: + if translator: + print(f"{translator.get('register.verification_failed')}") + else: + print(f"验证尝试失败: {e}") + + # 检查是否已经验证成功 + if check_verification_success(page, translator): + if translator: + print(f"{translator.get('register.verification_success')}") + else: + print("验证通过!") + return True + + time.sleep(random.uniform(1, 2)) + + if translator: + print(f"{translator.get('register.verification_failed')}") + else: + print("超出最大重试次数") + return False + + except Exception as e: + if translator: + print(f"{translator.get('register.verification_error', error=str(e))}") + else: + print(f"验证过程出错: {e}") + return False + +def check_verification_success(page, translator=None): + """检查验证是否成功""" + try: + # 检查是否存在后续表单元素,这表示验证已通过 + if (page.ele("@name=password", timeout=0.5) or + page.ele("@name=email", timeout=0.5) or + page.ele("@data-index=0", timeout=0.5) or + page.ele("Account Settings", timeout=0.5)): + return True + + # 检查是否出现错误消息 + error_messages = [ + 'xpath://div[contains(text(), "Can\'t verify the user is human")]', + 'xpath://div[contains(text(), "Error: 600010")]', + 'xpath://div[contains(text(), "Please try again")]' + ] + + for error_xpath in error_messages: + if page.ele(error_xpath): + return False + + return False + except: + return False + +def generate_password(length=12): + """生成随机密码""" + chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*" + return ''.join(random.choices(chars, k=length)) + +def fill_password(page, password, translator=None): + """填写密码""" + try: + print("\n正在设置密码...") + password_input = page.ele("@name=password") + if password_input: + password_input.input(password) + time.sleep(random.uniform(0.5, 1.0)) + + submit_button = page.ele("@type=submit") + if submit_button: + submit_button.click() + time.sleep(random.uniform(2.0, 3.0)) + + if translator: + print(f"{translator.get('register.password_success')}") + else: + print(f"密码设置完成: {password}") + return True + + except Exception as e: + if translator: + print(f"{translator.get('register.password_error', error=str(e))}") + else: + print(f"设置密码时出错: {e}") + return False + +def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None): + """处理验证码""" + try: + if translator: + print(f"\n{translator.get('register.waiting_for_verification_code')}") + else: + print("\n等待并获取验证码...") + time.sleep(5) # 等待验证码邮件 + + # 刷新邮箱页面 + email_tab.refresh() + + # 获取验证码,设置超时 + verification_code = None + max_attempts = 20 + retry_interval = 10 + start_time = time.time() + timeout = 160 + + if translator: + print(f"\n{translator.get('register.start_getting_verification_code')}") + else: + print("开始获取验证码...") + + for attempt in range(max_attempts): + # 检查是否超时 + if time.time() - start_time > timeout: + if translator: + print(f"{translator.get('register.verification_timeout')}") + else: + print("获取验证码超时...") + break + + verification_code = controller.get_verification_code() + if verification_code: + if translator: + print(f"{translator.get('register.verification_success')}") + else: + print(f"成功获取验证码: {verification_code}") + break + + remaining_time = int(timeout - (time.time() - start_time)) + if translator: + print(f"{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}") + else: + print(f"第 {attempt + 1} 次尝试获取验证码,剩余时间: {remaining_time}秒...") + + # 刷新邮箱 + email_tab.refresh() + time.sleep(retry_interval) + + if verification_code: + # 在注册页面填写验证码 + for i, digit in enumerate(verification_code): + browser_tab.ele(f"@data-index={i}").input(digit) + time.sleep(random.uniform(0.1, 0.3)) + + if translator: + print(f"{translator.get('register.verification_success')}") + else: + print("验证码填写完成") + time.sleep(3) + + # 处理最后一次 Turnstile 验证 + if handle_turnstile(browser_tab, translator): + if translator: + print(f"{translator.get('register.verification_success')}") + else: + print("最后一次验证通过!") + time.sleep(2) + + # 直接访问设置页面 + if translator: + print(f"{translator.get('register.visiting_url')}: https://www.cursor.com/settings") + else: + print("访问设置页面...") + browser_tab.get("https://www.cursor.com/settings") + time.sleep(3) # 等待页面加载 + + # 直接返回成功,让 cursor_register.py 处理账户信息获取 + return True + + else: + if translator: + print(f"{translator.get('register.verification_failed')}") + else: + print("最后一次验证失败") + return False + + return False + + except Exception as e: + if translator: + print(f"{translator.get('register.verification_error', error=str(e))}") + else: + print(f"处理验证码时出错: {e}") + return False + +def main(email=None, password=None, first_name=None, last_name=None, email_tab=None, controller=None, translator=None): + """主函数,可以接收账号信息、邮箱标签页和翻译器""" + global _translator + _translator = translator # 保存到全局变量 + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + page = None + success = False + try: + page = setup_driver(translator) + if translator: + print(f"{translator.get('register.browser_started')}") + else: + print("浏览器已启动") + + # 访问注册页面 + url = "https://authenticator.cursor.sh/sign-up" + if translator: + print(f"\n{translator.get('register.visiting_url')}: {url}") + else: + print(f"\n正在访问: {url}") + + # 访问页面 + simulate_human_input(page, url, translator) + if translator: + print(f"{translator.get('register.waiting_for_page_load')}") + else: + print("等待页面加载...") + time.sleep(5) + + # 如果没有提供账号信息,则生成随机信息 + if not all([email, password, first_name, last_name]): + first_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize() + last_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize() + email = f"{first_name.lower()}{random.randint(100,999)}@example.com" + password = generate_password() + + # 保存账号信息 + with open('test_accounts.txt', 'a', encoding='utf-8') as f: + f.write(f"\n{'='*50}\n") + f.write(f"Email: {email}\n") + f.write(f"Password: {password}\n") + f.write(f"{'='*50}\n") + + # 填写表单 + if fill_signup_form(page, first_name, last_name, email, translator): + if translator: + print(f"\n{translator.get('register.form_submitted')}") + else: + print("\n表单已提交,开始验证...") + + # 处理第一次 Turnstile 验证 + if handle_turnstile(page, translator): + if translator: + print(f"\n{translator.get('register.first_verification_passed')}") + else: + print("\n第一阶段验证通过!") + + # 填写密码 + if fill_password(page, password, translator): + if translator: + print(f"\n{translator.get('register.waiting_for_second_verification')}") + else: + print("\n等待第二次验证...") + time.sleep(2) + + # 处理第二次 Turnstile 验证 + if handle_turnstile(page, translator): + if translator: + print(f"\n{translator.get('register.waiting_for_verification_code')}") + else: + print("\n开始处理验证码...") + if handle_verification_code(page, email_tab, controller, email, password, translator): + if translator: + print(f"\n{translator.get('register.verification_success')}") + else: + print("\n注册流程完成!") + success = True + return True, page # 返回成功状态和浏览器实例 + else: + print("\n验证码处理失败") + else: + print("\n第二次验证失败") + else: + print("\n密码设置失败") + else: + print("\n第一次验证失败") + + return False, None + + except Exception as e: + print(f"发生错误: {e}") + return False, None + finally: + if page and not success: # 只在失败时清理 + try: + page.quit() + except: + pass + cleanup_chrome_processes(translator) + +if __name__ == "__main__": + main() # 直接运行时不传参数,使用随机生成的信息 \ No newline at end of file