This commit is contained in:
2026-01-27 09:25:04 +08:00
parent 935531955f
commit e14aabd0e2
3 changed files with 113 additions and 93 deletions

View File

@@ -198,41 +198,51 @@ def inject_fingerprint(page, fingerprint: dict):
plat = fingerprint.get("platform", "Win32") plat = fingerprint.get("platform", "Win32")
screen = fingerprint.get("screen", {"width": 1920, "height": 1080}) screen = fingerprint.get("screen", {"width": 1920, "height": 1080})
# 使用 try-catch 包裹每个属性定义,避免 Linux 上属性不可重定义的错误
js_script = f''' js_script = f'''
// 伪装 WebGL 指纹 (function() {{
const getParameterProxyHandler = {{ // 伪装 WebGL 指纹
apply: function(target, thisArg, args) {{ try {{
const param = args[0]; const getParameterProxyHandler = {{
if (param === 37445) {{ return "{webgl_vendor}"; }} apply: function(target, thisArg, args) {{
if (param === 37446) {{ return "{webgl_renderer}"; }} const param = args[0];
return Reflect.apply(target, thisArg, args); if (param === 37445) return "{webgl_vendor}";
}} if (param === 37446) return "{webgl_renderer}";
}}; return Reflect.apply(target, thisArg, args);
const originalGetParameter = WebGLRenderingContext.prototype.getParameter; }}
WebGLRenderingContext.prototype.getParameter = new Proxy(originalGetParameter, getParameterProxyHandler); }};
if (typeof WebGL2RenderingContext !== 'undefined') {{ const originalGetParameter = WebGLRenderingContext.prototype.getParameter;
const originalGetParameter2 = WebGL2RenderingContext.prototype.getParameter; WebGLRenderingContext.prototype.getParameter = new Proxy(originalGetParameter, getParameterProxyHandler);
WebGL2RenderingContext.prototype.getParameter = new Proxy(originalGetParameter2, getParameterProxyHandler); if (typeof WebGL2RenderingContext !== 'undefined') {{
}} const originalGetParameter2 = WebGL2RenderingContext.prototype.getParameter;
// 伪装 platform WebGL2RenderingContext.prototype.getParameter = new Proxy(originalGetParameter2, getParameterProxyHandler);
Object.defineProperty(navigator, 'platform', {{ get: () => "{plat}" }}); }}
// 伪装屏幕分辨率 }} catch(e) {{}}
Object.defineProperty(screen, 'width', {{ get: () => {screen["width"]} }}); // 伪装 platform
Object.defineProperty(screen, 'height', {{ get: () => {screen["height"]} }}); try {{ Object.defineProperty(navigator, 'platform', {{ get: () => "{plat}", configurable: true }}); }} catch(e) {{}}
Object.defineProperty(screen, 'availWidth', {{ get: () => {screen["width"]} }}); // 伪装屏幕分辨率
Object.defineProperty(screen, 'availHeight', {{ get: () => {screen["height"]} }}); try {{
// 隐藏 webdriver 特征 Object.defineProperty(screen, 'width', {{ get: () => {screen["width"]}, configurable: true }});
Object.defineProperty(navigator, 'webdriver', {{ get: () => undefined }}); Object.defineProperty(screen, 'height', {{ get: () => {screen["height"]}, configurable: true }});
// 伪装 languages Object.defineProperty(screen, 'availWidth', {{ get: () => {screen["width"]}, configurable: true }});
Object.defineProperty(navigator, 'languages', {{ get: () => ["zh-CN", "zh", "en-US", "en"] }}); Object.defineProperty(screen, 'availHeight', {{ get: () => {screen["height"]}, configurable: true }});
// 伪装 plugins }} catch(e) {{}}
Object.defineProperty(navigator, 'plugins', {{ // 隐藏 webdriver 特征
get: () => [ try {{ Object.defineProperty(navigator, 'webdriver', {{ get: () => undefined, configurable: true }}); }} catch(e) {{}}
{{ name: "Chrome PDF Plugin", filename: "internal-pdf-viewer" }}, // 伪装 languages
{{ name: "Chrome PDF Viewer", filename: "mhjfbmdgcfjbbpaeojofohoefgiehjai" }}, try {{ Object.defineProperty(navigator, 'languages', {{ get: () => ["zh-CN", "zh", "en-US", "en"], configurable: true }}); }} catch(e) {{}}
{{ name: "Native Client", filename: "internal-nacl-plugin" }} // 伪装 plugins
] try {{
}}); 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" }}
],
configurable: true
}});
}} catch(e) {{}}
}})();
''' '''
page.run_js(js_script) page.run_js(js_script)

View File

@@ -297,64 +297,62 @@ def _inject_fingerprint(page: ChromiumPage, fingerprint: dict):
platform = fingerprint.get("platform", "Win32") platform = fingerprint.get("platform", "Win32")
screen = fingerprint.get("screen", {"width": 1920, "height": 1080}) screen = fingerprint.get("screen", {"width": 1920, "height": 1080})
# 注入指纹伪装脚本 # 注入指纹伪装脚本 (使用 try-catch 避免属性不可重定义的错误)
js_script = f''' js_script = f'''
// 伪装 WebGL 指纹 (function() {{
const getParameterProxyHandler = {{ // 伪装 WebGL 指纹
apply: function(target, thisArg, args) {{ try {{
const param = args[0]; const getParameterProxyHandler = {{
const gl = thisArg; apply: function(target, thisArg, args) {{
// UNMASKED_VENDOR_WEBGL const param = args[0];
if (param === 37445) {{ if (param === 37445) return "{webgl_vendor}";
return "{webgl_vendor}"; if (param === 37446) return "{webgl_renderer}";
return Reflect.apply(target, thisArg, args);
}}
}};
const originalGetParameter = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = new Proxy(originalGetParameter, getParameterProxyHandler);
if (typeof WebGL2RenderingContext !== 'undefined') {{
const originalGetParameter2 = WebGL2RenderingContext.prototype.getParameter;
WebGL2RenderingContext.prototype.getParameter = new Proxy(originalGetParameter2, getParameterProxyHandler);
}} }}
// UNMASKED_RENDERER_WEBGL }} catch(e) {{}}
if (param === 37446) {{
return "{webgl_renderer}";
}}
return Reflect.apply(target, thisArg, args);
}}
}};
// 代理 WebGL getParameter // 伪装 platform
const originalGetParameter = WebGLRenderingContext.prototype.getParameter; try {{
WebGLRenderingContext.prototype.getParameter = new Proxy(originalGetParameter, getParameterProxyHandler); Object.defineProperty(navigator, 'platform', {{ get: () => "{platform}", configurable: true }});
}} catch(e) {{}}
// 代理 WebGL2 getParameter // 伪装屏幕分辨率
if (typeof WebGL2RenderingContext !== 'undefined') {{ try {{
const originalGetParameter2 = WebGL2RenderingContext.prototype.getParameter; Object.defineProperty(screen, 'width', {{ get: () => {screen["width"]}, configurable: true }});
WebGL2RenderingContext.prototype.getParameter = new Proxy(originalGetParameter2, getParameterProxyHandler); Object.defineProperty(screen, 'height', {{ get: () => {screen["height"]}, configurable: true }});
}} Object.defineProperty(screen, 'availWidth', {{ get: () => {screen["width"]}, configurable: true }});
Object.defineProperty(screen, 'availHeight', {{ get: () => {screen["height"]}, configurable: true }});
}} catch(e) {{}}
// 伪装 platform // 隐藏 webdriver 特征
Object.defineProperty(navigator, 'platform', {{ try {{
get: () => "{platform}" Object.defineProperty(navigator, 'webdriver', {{ get: () => undefined, configurable: true }});
}}); }} catch(e) {{}}
// 伪装屏幕分辨率 // 伪装 languages
Object.defineProperty(screen, 'width', {{ get: () => {screen["width"]} }}); try {{
Object.defineProperty(screen, 'height', {{ get: () => {screen["height"]} }}); Object.defineProperty(navigator, 'languages', {{ get: () => ["zh-CN", "zh", "en-US", "en"], configurable: true }});
Object.defineProperty(screen, 'availWidth', {{ get: () => {screen["width"]} }}); }} catch(e) {{}}
Object.defineProperty(screen, 'availHeight', {{ get: () => {screen["height"]} }});
// 隐藏 webdriver 特征 // 伪装 plugins
Object.defineProperty(navigator, 'webdriver', {{ try {{
get: () => undefined Object.defineProperty(navigator, 'plugins', {{
}}); get: () => [
{{ name: "Chrome PDF Plugin", filename: "internal-pdf-viewer" }},
// 伪装 languages (保持中文) {{ name: "Chrome PDF Viewer", filename: "mhjfbmdgcfjbbpaeojofohoefgiehjai" }},
Object.defineProperty(navigator, 'languages', {{ {{ name: "Native Client", filename: "internal-nacl-plugin" }}
get: () => ["zh-CN", "zh", "en-US", "en"] ],
}}); configurable: true
}});
// 伪装 plugins (模拟真实浏览器) }} catch(e) {{}}
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) page.run_js(js_script)

28
run.py
View File

@@ -773,6 +773,8 @@ def process_accounts_concurrent(
if max_workers is None: if max_workers is None:
max_workers = CONCURRENT_WORKERS max_workers = CONCURRENT_WORKERS
stagger_delay = 2.0 # 线程错开启动间隔 (秒)
# 过滤已完成的账号 # 过滤已完成的账号
pending_accounts = [acc for acc in accounts if acc.get("status") != "completed"] pending_accounts = [acc for acc in accounts if acc.get("status") != "completed"]
@@ -784,7 +786,7 @@ def process_accounts_concurrent(
total = len(pending_accounts) total = len(pending_accounts)
actual_workers = min(max_workers, total) actual_workers = min(max_workers, total)
log.section(f"并发处理 {total} 个账号 (并发数: {actual_workers})") log.section(f"并发处理 {total} 个账号 (并发数: {actual_workers}, 间隔: {stagger_delay}s)")
# 启动进度跟踪 # 启动进度跟踪
progress_start(team_name, total, team_index, teams_total, include_owner) progress_start(team_name, total, team_index, teams_total, include_owner)
@@ -793,16 +795,26 @@ def process_accounts_concurrent(
completed_count = 0 completed_count = 0
with ThreadPoolExecutor(max_workers=actual_workers) as executor: with ThreadPoolExecutor(max_workers=actual_workers) as executor:
# 提交所有任务 # 错开提交任务,每个任务间隔 stagger_delay 秒
future_to_account = { future_to_account = {}
executor.submit( for i, account in enumerate(pending_accounts):
if _shutdown_requested:
break
worker_id = i % actual_workers + 1
log.info(f"[Worker-{worker_id}] 启动任务: {account['email']}", icon="start")
future = executor.submit(
_process_single_account_worker, _process_single_account_worker,
account, account,
team_name, team_name,
i % actual_workers + 1 worker_id
): account )
for i, account in enumerate(pending_accounts) future_to_account[future] = account
}
# 错开启动,最后一个不需要等待
if i < len(pending_accounts) - 1:
time.sleep(stagger_delay)
# 收集结果 # 收集结果
for future in as_completed(future_to_account): for future in as_completed(future_to_account):