diff --git a/browser_automation.py b/browser_automation.py index 9cc2349..0748054 100644 --- a/browser_automation.py +++ b/browser_automation.py @@ -14,9 +14,11 @@ from config import ( BROWSER_WAIT_TIMEOUT, BROWSER_SHORT_WAIT, BROWSER_HEADLESS, + BROWSER_RANDOM_FINGERPRINT, AUTH_PROVIDER, get_random_name, - get_random_birthday + get_random_birthday, + get_random_fingerprint ) from email_service import unified_get_verification_code from crs_service import crs_generate_auth_url, crs_exchange_code, crs_add_account, extract_code_from_url @@ -218,6 +220,84 @@ def cleanup_chrome_processes(): pass # 静默处理,不影响主流程 +def _inject_fingerprint(page: ChromiumPage, fingerprint: dict): + """注入浏览器指纹伪装脚本 + + Args: + page: 浏览器页面对象 + fingerprint: 指纹配置字典 + """ + try: + webgl_vendor = fingerprint.get("webgl_vendor", "Google Inc. (NVIDIA)") + webgl_renderer = fingerprint.get("webgl_renderer", "ANGLE (NVIDIA)") + platform = fingerprint.get("platform", "Win32") + screen = fingerprint.get("screen", {"width": 1920, "height": 1080}) + + # 注入指纹伪装脚本 + js_script = f''' + // 伪装 WebGL 指纹 + const getParameterProxyHandler = {{ + apply: function(target, thisArg, args) {{ + const param = args[0]; + const gl = thisArg; + // UNMASKED_VENDOR_WEBGL + if (param === 37445) {{ + return "{webgl_vendor}"; + }} + // UNMASKED_RENDERER_WEBGL + if (param === 37446) {{ + return "{webgl_renderer}"; + }} + return Reflect.apply(target, thisArg, args); + }} + }}; + + // 代理 WebGL getParameter + const originalGetParameter = WebGLRenderingContext.prototype.getParameter; + WebGLRenderingContext.prototype.getParameter = new Proxy(originalGetParameter, getParameterProxyHandler); + + // 代理 WebGL2 getParameter + if (typeof WebGL2RenderingContext !== 'undefined') {{ + const originalGetParameter2 = WebGL2RenderingContext.prototype.getParameter; + WebGL2RenderingContext.prototype.getParameter = new Proxy(originalGetParameter2, getParameterProxyHandler); + }} + + // 伪装 platform + Object.defineProperty(navigator, 'platform', {{ + get: () => "{platform}" + }}); + + // 伪装屏幕分辨率 + Object.defineProperty(screen, 'width', {{ get: () => {screen["width"]} }}); + Object.defineProperty(screen, 'height', {{ get: () => {screen["height"]} }}); + Object.defineProperty(screen, 'availWidth', {{ get: () => {screen["width"]} }}); + Object.defineProperty(screen, 'availHeight', {{ get: () => {screen["height"]} }}); + + // 隐藏 webdriver 特征 + Object.defineProperty(navigator, 'webdriver', {{ + get: () => undefined + }}); + + // 伪装 languages (保持中文) + Object.defineProperty(navigator, 'languages', {{ + get: () => ["zh-CN", "zh", "en-US", "en"] + }}); + + // 伪装 plugins (模拟真实浏览器) + Object.defineProperty(navigator, 'plugins', {{ + get: () => [ + {{ name: "Chrome PDF Plugin", filename: "internal-pdf-viewer" }}, + {{ name: "Chrome PDF Viewer", filename: "mhjfbmdgcfjbbpaeojofohoefgiehjai" }}, + {{ name: "Native Client", filename: "internal-nacl-plugin" }} + ] + }}); + ''' + + page.run_js(js_script) + except Exception as e: + log.warning(f"指纹注入失败: {e}") + + def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage: """初始化 DrissionPage 浏览器 (带重试机制) @@ -229,6 +309,22 @@ def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage: """ log.info("初始化浏览器...", icon="browser") + # 根据配置决定是否使用随机指纹 + fingerprint = None + if BROWSER_RANDOM_FINGERPRINT: + fingerprint = get_random_fingerprint() + log.step(f"随机指纹: {fingerprint['webgl_renderer'][:40]}...") + else: + # 使用默认指纹 + fingerprint = { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + } + log.step("使用默认指纹") + last_error = None is_linux = platform.system() == "Linux" @@ -249,8 +345,11 @@ def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage: co.set_argument('--no-sandbox') # 服务器环境需要 co.set_argument('--disable-blink-features=AutomationControlled') # 隐藏自动化特征 - # 设置 User-Agent (模拟真实浏览器) - co.set_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36') + # 设置 User-Agent + co.set_argument(f'--user-agent={fingerprint["user_agent"]}') + + # 设置语言为中文简体 + co.set_argument('--lang=zh-CN') # Linux 服务器特殊配置 if is_linux: @@ -277,9 +376,10 @@ def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage: co.auto_port() # Windows 使用自动分配端口 # 无头模式 (服务器运行) + screen = fingerprint.get("screen", {"width": 1920, "height": 1080}) if BROWSER_HEADLESS: co.set_argument('--headless=new') - co.set_argument('--window-size=1920,1080') + co.set_argument(f'--window-size={screen["width"]},{screen["height"]}') log.step("启动 Chrome (无头模式)...") else: log.step("启动 Chrome (无痕模式)...") @@ -288,6 +388,11 @@ def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage: co.set_timeouts(base=PAGE_LOAD_TIMEOUT, page_load=PAGE_LOAD_TIMEOUT * 2) page = ChromiumPage(co) + + # 注入指纹伪装脚本 (仅在启用随机指纹时) + if BROWSER_RANDOM_FINGERPRINT: + _inject_fingerprint(page, fingerprint) + log.success("浏览器启动成功") return page @@ -614,6 +719,74 @@ def human_delay(min_sec: float = None, max_sec: float = None): time.sleep(random.uniform(min_sec, max_sec)) +def _detect_page_language(page) -> str: + """检测页面语言 + + Returns: + str: 'zh' 中文, 'en' 英文 + """ + try: + # 检查页面是否包含中文特征 + html = page.html + # 检查中文关键词 + chinese_keywords = ['确认', '继续', '登录', '注册', '验证', '邮箱', '密码', '姓名', '生日'] + for keyword in chinese_keywords: + if keyword in html: + return 'zh' + return 'en' + except Exception: + return 'en' # 默认英文 + + +def _input_birthday(page, birthday: dict): + """智能输入生日 (自动适配中英文界面) + + 中文界面: yyyy/mm/dd (年/月/日) + 英文界面: mm/dd/yyyy (月/日/年) + + Args: + page: 浏览器页面对象 + birthday: {'year': '2000', 'month': '01', 'day': '15'} + """ + # 获取三个输入框 + year_input = wait_for_element(page, 'css:[data-type="year"]', timeout=10) + month_input = wait_for_element(page, 'css:[data-type="month"]', timeout=5) + day_input = wait_for_element(page, 'css:[data-type="day"]', timeout=5) + + if not all([year_input, month_input, day_input]): + log.warning("未找到完整的生日输入框") + return False + + # 检测页面语言 + lang = _detect_page_language(page) + log.step(f"输入生日: {birthday['year']}/{birthday['month']}/{birthday['day']} (界面语言: {lang})") + + # 根据语言决定输入顺序 + if lang == 'zh': + # 中文: 年 -> 月 -> 日 + input_order = [(year_input, birthday['year']), + (month_input, birthday['month']), + (day_input, birthday['day'])] + else: + # 英文: 月 -> 日 -> 年 + input_order = [(month_input, birthday['month']), + (day_input, birthday['day']), + (year_input, birthday['year'])] + + # 按顺序输入 + for input_elem, value in input_order: + try: + input_elem.click() + time.sleep(0.15) + input_elem.input(value, clear=True) + time.sleep(0.2) + except Exception as e: + log.warning(f"生日输入异常: {e}") + + log.success("生日已输入") + return True + + def check_and_handle_error(page, max_retries=5) -> bool: """检查并处理页面错误 (带自动重试)""" for attempt in range(max_retries): @@ -726,8 +899,9 @@ def register_openai_account(page, email: str, password: str) -> bool: # 在 chatgpt.com,检查是否有注册按钮 page_ok = page.ele('css:[data-testid="signup-button"]', timeout=1) or \ page.ele('text:免费注册', timeout=1) or \ - page.ele('text:Sign up', timeout=1) or \ - page.ele('text:登录', timeout=1) # 也可能显示登录按钮 + page.ele('text:Sign up for free', timeout=1) or \ + page.ele('text:登录', timeout=1) or \ + page.ele('text:Log in', timeout=1) if not page_ok: log.warning("页面加载异常,3秒后刷新...") save_debug_screenshot(page, 'page_load_abnormal') @@ -750,7 +924,7 @@ def register_openai_account(page, email: str, password: str) -> bool: if not signup_btn: signup_btn = wait_for_element(page, 'text:免费注册', timeout=3) if not signup_btn: - signup_btn = wait_for_element(page, 'text:Sign up', timeout=3) + signup_btn = wait_for_element(page, 'text:Sign up for free', timeout=3) if signup_btn: old_url = page.url signup_btn.click() @@ -803,12 +977,12 @@ def register_openai_account(page, email: str, password: str) -> bool: page.refresh() wait_for_page_stable(page, timeout=8) log_current_url(page, "刷新后", force=True) - + # 重新点击注册按钮 log.step("重新点击免费注册...") signup_btn = wait_for_element(page, 'css:[data-testid="signup-button"]', timeout=8) or \ wait_for_element(page, 'text:免费注册', timeout=5) or \ - wait_for_element(page, 'text:Sign up', timeout=3) or \ + wait_for_element(page, 'text:Sign up for free', timeout=3) or \ wait_for_element(page, 'text:Get started', timeout=2) if signup_btn: signup_btn.click() @@ -989,40 +1163,15 @@ def register_openai_account(page, email: str, password: str) -> bool: name_input = wait_for_element(page, 'css:input[name="name"]', timeout=5) if not name_input: name_input = wait_for_element(page, 'css:input[autocomplete="name"]', timeout=3) - + # 输入姓名 random_name = get_random_name() log.step(f"输入姓名: {random_name}") type_slowly(page, 'css:input[name="name"], input[autocomplete="name"]', random_name) - # 输入生日 (与正常注册流程一致) + # 输入生日 (使用智能适配函数) birthday = get_random_birthday() - log.step(f"输入生日: {birthday['year']}/{birthday['month']}/{birthday['day']}") - - # 年份 - year_input = wait_for_element(page, 'css:[data-type="year"]', timeout=10) - if year_input: - year_input.click() - time.sleep(0.15) - year_input.input(birthday['year'], clear=True) - time.sleep(0.2) - - # 月份 - month_input = wait_for_element(page, 'css:[data-type="month"]', timeout=5) - if month_input: - month_input.click() - time.sleep(0.15) - month_input.input(birthday['month'], clear=True) - time.sleep(0.2) - - # 日期 - day_input = wait_for_element(page, 'css:[data-type="day"]', timeout=5) - if day_input: - day_input.click() - time.sleep(0.15) - day_input.input(birthday['day'], clear=True) - - log.success("生日已输入") + _input_birthday(page, birthday) # 点击提交 log.step("点击最终提交...") @@ -1171,34 +1320,9 @@ def register_openai_account(page, email: str, password: str) -> bool: name_input = wait_for_element(page, 'css:input[autocomplete="name"]', timeout=5) type_slowly(page, 'css:input[name="name"], input[autocomplete="name"]', random_name) - # 输入生日 (随机 2000-2005) + # 输入生日 (使用智能适配函数) birthday = get_random_birthday() - log.step(f"输入生日: {birthday['year']}/{birthday['month']}/{birthday['day']}") - - # 年份 - year_input = wait_for_element(page, 'css:[data-type="year"]', timeout=10) - if year_input: - year_input.click() - time.sleep(0.15) - year_input.input(birthday['year'], clear=True) - time.sleep(0.2) - - # 月份 - month_input = wait_for_element(page, 'css:[data-type="month"]', timeout=5) - if month_input: - month_input.click() - time.sleep(0.15) - month_input.input(birthday['month'], clear=True) - time.sleep(0.2) - - # 日期 - day_input = wait_for_element(page, 'css:[data-type="day"]', timeout=5) - if day_input: - day_input.click() - time.sleep(0.15) - day_input.input(birthday['day'], clear=True) - - log.success("生日已输入") + _input_birthday(page, birthday) # 最终提交 log.step("点击最终提交...") diff --git a/config.py b/config.py index eebe3dc..944b5a9 100644 --- a/config.py +++ b/config.py @@ -255,7 +255,8 @@ def reload_config() -> dict: # 浏览器配置 _browser = _cfg.get("browser", {}) - BROWSER_HEADLESS = _browser.get("headless", False) + BROWSER_HEADLESS = _browser.get("headless", True) + BROWSER_RANDOM_FINGERPRINT = _browser.get("random_fingerprint", True) # 账号配置 _account = _cfg.get("account", {}) @@ -540,7 +541,8 @@ VERIFICATION_CODE_MAX_RETRIES = _ver.get("max_retries", 20) _browser = _cfg.get("browser", {}) BROWSER_WAIT_TIMEOUT = _browser.get("wait_timeout", 60) BROWSER_SHORT_WAIT = _browser.get("short_wait", 10) -BROWSER_HEADLESS = _browser.get("headless", False) +BROWSER_HEADLESS = _browser.get("headless", True) +BROWSER_RANDOM_FINGERPRINT = _browser.get("random_fingerprint", True) # 文件 _files = _cfg.get("files", {}) @@ -624,43 +626,203 @@ def get_random_name() -> str: # ==================== 浏览器指纹 ==================== +# 语言统一使用中文简体,只随机化硬件指纹 +# Chrome 版本范围: 133-144 (2025.02 - 2026.01) FINGERPRINTS = [ + # ==================== NVIDIA 显卡 ==================== { - "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "platform": "Win32", "webgl_vendor": "Google Inc. (NVIDIA)", "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0)", - "language": "en-US", - "timezone": "America/New_York", "screen": {"width": 1920, "height": 1080} }, { - "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36", + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", "platform": "Win32", - "webgl_vendor": "Google Inc. (AMD)", - "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 6800 XT Direct3D11 vs_5_0 ps_5_0)", - "language": "en-US", - "timezone": "America/Los_Angeles", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0)", "screen": {"width": 2560, "height": 1440} }, { - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", - "platform": "MacIntel", - "webgl_vendor": "Google Inc. (Apple)", - "webgl_renderer": "ANGLE (Apple, Apple M1 Pro, OpenGL 4.1)", - "language": "en-US", - "timezone": "America/Chicago", - "screen": {"width": 1728, "height": 1117} + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} }, { - "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4080 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 3840, "height": 2160} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4090 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 3840, "height": 2160} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce GTX 1080 Ti Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 2560, "height": 1440} + }, + # ==================== AMD 显卡 ==================== + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 6800 XT Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 2560, "height": 1440} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 7900 XTX Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 3840, "height": 2160} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 6700 XT Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 5700 XT Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 7800 XT Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 2560, "height": 1440} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + # ==================== Intel 显卡 ==================== + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "platform": "Win32", "webgl_vendor": "Google Inc. (Intel)", "webgl_renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0)", - "language": "en-GB", - "timezone": "Europe/London", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (Intel)", + "webgl_renderer": "ANGLE (Intel, Intel(R) Iris Xe Graphics Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (Intel)", + "webgl_renderer": "ANGLE (Intel, Intel(R) UHD Graphics 770 Direct3D11 vs_5_0 ps_5_0)", "screen": {"width": 1920, "height": 1200} - } + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (Intel)", + "webgl_renderer": "ANGLE (Intel, Intel(R) UHD Graphics 730 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (Intel)", + "webgl_renderer": "ANGLE (Intel, Intel(R) Arc A770 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 2560, "height": 1440} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (Intel)", + "webgl_renderer": "ANGLE (Intel, Intel(R) HD Graphics 620 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1366, "height": 768} + }, + # ==================== 笔记本常见配置 ==================== + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3050 Laptop GPU Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Laptop GPU Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 2560, "height": 1600} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 6500M Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", + "platform": "Win32", + "webgl_vendor": "Google Inc. (Intel)", + "webgl_renderer": "ANGLE (Intel, Intel(R) Iris Plus Graphics Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + # ==================== Edge 浏览器 ==================== + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0", + "platform": "Win32", + "webgl_vendor": "Google Inc. (NVIDIA)", + "webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Ti Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0", + "platform": "Win32", + "webgl_vendor": "Google Inc. (AMD)", + "webgl_renderer": "ANGLE (AMD, AMD Radeon RX 6900 XT Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 2560, "height": 1440} + }, + { + "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0", + "platform": "Win32", + "webgl_vendor": "Google Inc. (Intel)", + "webgl_renderer": "ANGLE (Intel, Intel(R) UHD Graphics 750 Direct3D11 vs_5_0 ps_5_0)", + "screen": {"width": 1920, "height": 1080} + }, ] diff --git a/config.toml.example b/config.toml.example index 6c5c129..97bd4a9 100644 --- a/config.toml.example +++ b/config.toml.example @@ -195,8 +195,8 @@ max_retries = 20 wait_timeout = 60 # 短等待时间,用于快速检查 (秒) short_wait = 10 -# 无头模式 (服务器运行时设为 true) -headless = false +# 是否启用随机指纹 (User-Agent, WebGL, 分辨率等) +random_fingerprint = true # ==================== 文件配置 ==================== [files] diff --git a/telegram_bot.py b/telegram_bot.py index 8932985..2d00710 100644 --- a/telegram_bot.py +++ b/telegram_bot.py @@ -96,7 +96,7 @@ class ProvisionerBot: ("team", self.cmd_team), ("list", self.cmd_list), ("config", self.cmd_config), - ("headless", self.cmd_headless), + ("fingerprint", self.cmd_fingerprint), ("run", self.cmd_run), ("run_all", self.cmd_run_all), ("stop", self.cmd_stop), @@ -214,7 +214,7 @@ class ProvisionerBot: /stop - 停止当前任务 ⚙️ 配置管理: -/headless - 开启/关闭无头模式 +/fingerprint - 开启/关闭随机指纹 /include_owners - 开启/关闭 Owner 入库 /reload - 重载配置文件 (无需重启) @@ -397,37 +397,41 @@ class ProvisionerBot: await update.message.reply_text("\n".join(lines), parse_mode="HTML") @admin_only - async def cmd_headless(self, update: Update, context: ContextTypes.DEFAULT_TYPE): - """切换无头模式""" + async def cmd_fingerprint(self, update: Update, context: ContextTypes.DEFAULT_TYPE): + """切换随机指纹""" import tomli_w - + try: # 读取当前配置 with open(CONFIG_FILE, "rb") as f: import tomllib config = tomllib.load(f) - + # 获取当前状态 - current = config.get("browser", {}).get("headless", False) + current = config.get("browser", {}).get("random_fingerprint", True) new_value = not current - + # 更新配置 if "browser" not in config: config["browser"] = {} - config["browser"]["headless"] = new_value - + config["browser"]["random_fingerprint"] = new_value + # 写回文件 with open(CONFIG_FILE, "wb") as f: tomli_w.dump(config, f) - + status = "✅ 已开启" if new_value else "❌ 已关闭" await update.message.reply_text( - f"🌐 无头模式\n\n" + f"🎭 随机指纹\n\n" f"状态: {status}\n\n" + f"开启后每次启动浏览器将随机使用不同的:\n" + f"• User-Agent (Chrome 133-144)\n" + f"• WebGL 显卡指纹\n" + f"• 屏幕分辨率\n\n" f"💡 使用 /reload 立即生效", parse_mode="HTML" ) - + except ImportError: await update.message.reply_text( "❌ 缺少 tomli_w 依赖\n"