update
This commit is contained in:
@@ -14,9 +14,11 @@ from config import (
|
|||||||
BROWSER_WAIT_TIMEOUT,
|
BROWSER_WAIT_TIMEOUT,
|
||||||
BROWSER_SHORT_WAIT,
|
BROWSER_SHORT_WAIT,
|
||||||
BROWSER_HEADLESS,
|
BROWSER_HEADLESS,
|
||||||
|
BROWSER_RANDOM_FINGERPRINT,
|
||||||
AUTH_PROVIDER,
|
AUTH_PROVIDER,
|
||||||
get_random_name,
|
get_random_name,
|
||||||
get_random_birthday
|
get_random_birthday,
|
||||||
|
get_random_fingerprint
|
||||||
)
|
)
|
||||||
from email_service import unified_get_verification_code
|
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
|
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 # 静默处理,不影响主流程
|
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:
|
def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage:
|
||||||
"""初始化 DrissionPage 浏览器 (带重试机制)
|
"""初始化 DrissionPage 浏览器 (带重试机制)
|
||||||
|
|
||||||
@@ -229,6 +309,22 @@ def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage:
|
|||||||
"""
|
"""
|
||||||
log.info("初始化浏览器...", icon="browser")
|
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
|
last_error = None
|
||||||
is_linux = platform.system() == "Linux"
|
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('--no-sandbox') # 服务器环境需要
|
||||||
co.set_argument('--disable-blink-features=AutomationControlled') # 隐藏自动化特征
|
co.set_argument('--disable-blink-features=AutomationControlled') # 隐藏自动化特征
|
||||||
|
|
||||||
# 设置 User-Agent (模拟真实浏览器)
|
# 设置 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')
|
co.set_argument(f'--user-agent={fingerprint["user_agent"]}')
|
||||||
|
|
||||||
|
# 设置语言为中文简体
|
||||||
|
co.set_argument('--lang=zh-CN')
|
||||||
|
|
||||||
# Linux 服务器特殊配置
|
# Linux 服务器特殊配置
|
||||||
if is_linux:
|
if is_linux:
|
||||||
@@ -277,9 +376,10 @@ def init_browser(max_retries: int = BROWSER_MAX_RETRIES) -> ChromiumPage:
|
|||||||
co.auto_port() # Windows 使用自动分配端口
|
co.auto_port() # Windows 使用自动分配端口
|
||||||
|
|
||||||
# 无头模式 (服务器运行)
|
# 无头模式 (服务器运行)
|
||||||
|
screen = fingerprint.get("screen", {"width": 1920, "height": 1080})
|
||||||
if BROWSER_HEADLESS:
|
if BROWSER_HEADLESS:
|
||||||
co.set_argument('--headless=new')
|
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 (无头模式)...")
|
log.step("启动 Chrome (无头模式)...")
|
||||||
else:
|
else:
|
||||||
log.step("启动 Chrome (无痕模式)...")
|
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)
|
co.set_timeouts(base=PAGE_LOAD_TIMEOUT, page_load=PAGE_LOAD_TIMEOUT * 2)
|
||||||
|
|
||||||
page = ChromiumPage(co)
|
page = ChromiumPage(co)
|
||||||
|
|
||||||
|
# 注入指纹伪装脚本 (仅在启用随机指纹时)
|
||||||
|
if BROWSER_RANDOM_FINGERPRINT:
|
||||||
|
_inject_fingerprint(page, fingerprint)
|
||||||
|
|
||||||
log.success("浏览器启动成功")
|
log.success("浏览器启动成功")
|
||||||
return page
|
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))
|
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:
|
def check_and_handle_error(page, max_retries=5) -> bool:
|
||||||
"""检查并处理页面错误 (带自动重试)"""
|
"""检查并处理页面错误 (带自动重试)"""
|
||||||
for attempt in range(max_retries):
|
for attempt in range(max_retries):
|
||||||
@@ -726,8 +899,9 @@ def register_openai_account(page, email: str, password: str) -> bool:
|
|||||||
# 在 chatgpt.com,检查是否有注册按钮
|
# 在 chatgpt.com,检查是否有注册按钮
|
||||||
page_ok = page.ele('css:[data-testid="signup-button"]', timeout=1) or \
|
page_ok = page.ele('css:[data-testid="signup-button"]', timeout=1) or \
|
||||||
page.ele('text:免费注册', timeout=1) or \
|
page.ele('text:免费注册', timeout=1) or \
|
||||||
page.ele('text:Sign up', timeout=1) or \
|
page.ele('text:Sign up for free', timeout=1) or \
|
||||||
page.ele('text:登录', timeout=1) # 也可能显示登录按钮
|
page.ele('text:登录', timeout=1) or \
|
||||||
|
page.ele('text:Log in', timeout=1)
|
||||||
if not page_ok:
|
if not page_ok:
|
||||||
log.warning("页面加载异常,3秒后刷新...")
|
log.warning("页面加载异常,3秒后刷新...")
|
||||||
save_debug_screenshot(page, 'page_load_abnormal')
|
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:
|
if not signup_btn:
|
||||||
signup_btn = wait_for_element(page, 'text:免费注册', timeout=3)
|
signup_btn = wait_for_element(page, 'text:免费注册', timeout=3)
|
||||||
if not signup_btn:
|
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:
|
if signup_btn:
|
||||||
old_url = page.url
|
old_url = page.url
|
||||||
signup_btn.click()
|
signup_btn.click()
|
||||||
@@ -808,7 +982,7 @@ def register_openai_account(page, email: str, password: str) -> bool:
|
|||||||
log.step("重新点击免费注册...")
|
log.step("重新点击免费注册...")
|
||||||
signup_btn = wait_for_element(page, 'css:[data-testid="signup-button"]', timeout=8) or \
|
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:免费注册', 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)
|
wait_for_element(page, 'text:Get started', timeout=2)
|
||||||
if signup_btn:
|
if signup_btn:
|
||||||
signup_btn.click()
|
signup_btn.click()
|
||||||
@@ -995,34 +1169,9 @@ def register_openai_account(page, email: str, password: str) -> bool:
|
|||||||
log.step(f"输入姓名: {random_name}")
|
log.step(f"输入姓名: {random_name}")
|
||||||
type_slowly(page, 'css:input[name="name"], input[autocomplete="name"]', random_name)
|
type_slowly(page, 'css:input[name="name"], input[autocomplete="name"]', random_name)
|
||||||
|
|
||||||
# 输入生日 (与正常注册流程一致)
|
# 输入生日 (使用智能适配函数)
|
||||||
birthday = get_random_birthday()
|
birthday = get_random_birthday()
|
||||||
log.step(f"输入生日: {birthday['year']}/{birthday['month']}/{birthday['day']}")
|
_input_birthday(page, birthday)
|
||||||
|
|
||||||
# 年份
|
|
||||||
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("生日已输入")
|
|
||||||
|
|
||||||
# 点击提交
|
# 点击提交
|
||||||
log.step("点击最终提交...")
|
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)
|
name_input = wait_for_element(page, 'css:input[autocomplete="name"]', timeout=5)
|
||||||
type_slowly(page, 'css:input[name="name"], input[autocomplete="name"]', random_name)
|
type_slowly(page, 'css:input[name="name"], input[autocomplete="name"]', random_name)
|
||||||
|
|
||||||
# 输入生日 (随机 2000-2005)
|
# 输入生日 (使用智能适配函数)
|
||||||
birthday = get_random_birthday()
|
birthday = get_random_birthday()
|
||||||
log.step(f"输入生日: {birthday['year']}/{birthday['month']}/{birthday['day']}")
|
_input_birthday(page, birthday)
|
||||||
|
|
||||||
# 年份
|
|
||||||
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("生日已输入")
|
|
||||||
|
|
||||||
# 最终提交
|
# 最终提交
|
||||||
log.step("点击最终提交...")
|
log.step("点击最终提交...")
|
||||||
|
|||||||
204
config.py
204
config.py
@@ -255,7 +255,8 @@ def reload_config() -> dict:
|
|||||||
|
|
||||||
# 浏览器配置
|
# 浏览器配置
|
||||||
_browser = _cfg.get("browser", {})
|
_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", {})
|
_account = _cfg.get("account", {})
|
||||||
@@ -540,7 +541,8 @@ VERIFICATION_CODE_MAX_RETRIES = _ver.get("max_retries", 20)
|
|||||||
_browser = _cfg.get("browser", {})
|
_browser = _cfg.get("browser", {})
|
||||||
BROWSER_WAIT_TIMEOUT = _browser.get("wait_timeout", 60)
|
BROWSER_WAIT_TIMEOUT = _browser.get("wait_timeout", 60)
|
||||||
BROWSER_SHORT_WAIT = _browser.get("short_wait", 10)
|
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", {})
|
_files = _cfg.get("files", {})
|
||||||
@@ -624,43 +626,203 @@ def get_random_name() -> str:
|
|||||||
|
|
||||||
|
|
||||||
# ==================== 浏览器指纹 ====================
|
# ==================== 浏览器指纹 ====================
|
||||||
|
# 语言统一使用中文简体,只随机化硬件指纹
|
||||||
|
# Chrome 版本范围: 133-144 (2025.02 - 2026.01)
|
||||||
FINGERPRINTS = [
|
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",
|
"platform": "Win32",
|
||||||
"webgl_vendor": "Google Inc. (NVIDIA)",
|
"webgl_vendor": "Google Inc. (NVIDIA)",
|
||||||
"webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0)",
|
"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}
|
"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",
|
"platform": "Win32",
|
||||||
"webgl_vendor": "Google Inc. (AMD)",
|
"webgl_vendor": "Google Inc. (NVIDIA)",
|
||||||
"webgl_renderer": "ANGLE (AMD, AMD Radeon RX 6800 XT Direct3D11 vs_5_0 ps_5_0)",
|
"webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0)",
|
||||||
"language": "en-US",
|
"screen": {"width": 1920, "height": 1080}
|
||||||
"timezone": "America/Los_Angeles",
|
},
|
||||||
|
{
|
||||||
|
"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}
|
"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",
|
"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": "MacIntel",
|
"platform": "Win32",
|
||||||
"webgl_vendor": "Google Inc. (Apple)",
|
"webgl_vendor": "Google Inc. (NVIDIA)",
|
||||||
"webgl_renderer": "ANGLE (Apple, Apple M1 Pro, OpenGL 4.1)",
|
"webgl_renderer": "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0)",
|
||||||
"language": "en-US",
|
"screen": {"width": 1920, "height": 1080}
|
||||||
"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/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",
|
"platform": "Win32",
|
||||||
"webgl_vendor": "Google Inc. (Intel)",
|
"webgl_vendor": "Google Inc. (Intel)",
|
||||||
"webgl_renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0)",
|
"webgl_renderer": "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0)",
|
||||||
"language": "en-GB",
|
"screen": {"width": 1920, "height": 1080}
|
||||||
"timezone": "Europe/London",
|
},
|
||||||
|
{
|
||||||
|
"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}
|
"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}
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -195,8 +195,8 @@ max_retries = 20
|
|||||||
wait_timeout = 60
|
wait_timeout = 60
|
||||||
# 短等待时间,用于快速检查 (秒)
|
# 短等待时间,用于快速检查 (秒)
|
||||||
short_wait = 10
|
short_wait = 10
|
||||||
# 无头模式 (服务器运行时设为 true)
|
# 是否启用随机指纹 (User-Agent, WebGL, 分辨率等)
|
||||||
headless = false
|
random_fingerprint = true
|
||||||
|
|
||||||
# ==================== 文件配置 ====================
|
# ==================== 文件配置 ====================
|
||||||
[files]
|
[files]
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class ProvisionerBot:
|
|||||||
("team", self.cmd_team),
|
("team", self.cmd_team),
|
||||||
("list", self.cmd_list),
|
("list", self.cmd_list),
|
||||||
("config", self.cmd_config),
|
("config", self.cmd_config),
|
||||||
("headless", self.cmd_headless),
|
("fingerprint", self.cmd_fingerprint),
|
||||||
("run", self.cmd_run),
|
("run", self.cmd_run),
|
||||||
("run_all", self.cmd_run_all),
|
("run_all", self.cmd_run_all),
|
||||||
("stop", self.cmd_stop),
|
("stop", self.cmd_stop),
|
||||||
@@ -214,7 +214,7 @@ class ProvisionerBot:
|
|||||||
/stop - 停止当前任务
|
/stop - 停止当前任务
|
||||||
|
|
||||||
<b>⚙️ 配置管理:</b>
|
<b>⚙️ 配置管理:</b>
|
||||||
/headless - 开启/关闭无头模式
|
/fingerprint - 开启/关闭随机指纹
|
||||||
/include_owners - 开启/关闭 Owner 入库
|
/include_owners - 开启/关闭 Owner 入库
|
||||||
/reload - 重载配置文件 (无需重启)
|
/reload - 重载配置文件 (无需重启)
|
||||||
|
|
||||||
@@ -397,8 +397,8 @@ class ProvisionerBot:
|
|||||||
await update.message.reply_text("\n".join(lines), parse_mode="HTML")
|
await update.message.reply_text("\n".join(lines), parse_mode="HTML")
|
||||||
|
|
||||||
@admin_only
|
@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
|
import tomli_w
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -408,13 +408,13 @@ class ProvisionerBot:
|
|||||||
config = tomllib.load(f)
|
config = tomllib.load(f)
|
||||||
|
|
||||||
# 获取当前状态
|
# 获取当前状态
|
||||||
current = config.get("browser", {}).get("headless", False)
|
current = config.get("browser", {}).get("random_fingerprint", True)
|
||||||
new_value = not current
|
new_value = not current
|
||||||
|
|
||||||
# 更新配置
|
# 更新配置
|
||||||
if "browser" not in config:
|
if "browser" not in config:
|
||||||
config["browser"] = {}
|
config["browser"] = {}
|
||||||
config["browser"]["headless"] = new_value
|
config["browser"]["random_fingerprint"] = new_value
|
||||||
|
|
||||||
# 写回文件
|
# 写回文件
|
||||||
with open(CONFIG_FILE, "wb") as f:
|
with open(CONFIG_FILE, "wb") as f:
|
||||||
@@ -422,8 +422,12 @@ class ProvisionerBot:
|
|||||||
|
|
||||||
status = "✅ 已开启" if new_value else "❌ 已关闭"
|
status = "✅ 已开启" if new_value else "❌ 已关闭"
|
||||||
await update.message.reply_text(
|
await update.message.reply_text(
|
||||||
f"<b>🌐 无头模式</b>\n\n"
|
f"<b>🎭 随机指纹</b>\n\n"
|
||||||
f"状态: {status}\n\n"
|
f"状态: {status}\n\n"
|
||||||
|
f"开启后每次启动浏览器将随机使用不同的:\n"
|
||||||
|
f"• User-Agent (Chrome 133-144)\n"
|
||||||
|
f"• WebGL 显卡指纹\n"
|
||||||
|
f"• 屏幕分辨率\n\n"
|
||||||
f"💡 使用 /reload 立即生效",
|
f"💡 使用 /reload 立即生效",
|
||||||
parse_mode="HTML"
|
parse_mode="HTML"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user