@skrillex1224/playwright-toolkit 2.0.14 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -2
- package/dist/index.cjs +92 -2
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +92 -2
- package/dist/index.js.map +2 -2
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -9,10 +9,86 @@
|
|
|
9
9
|
## 📦 安装
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npm install @skrillex1224/
|
|
12
|
+
npm install @skrillex1224/playwright-toolkit
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## 🛡️ 反检测功能 (Anti-Detection)
|
|
16
|
+
|
|
17
|
+
本工具库提供多层次的反检测能力,帮助绕过常见的爬虫检测机制。
|
|
18
|
+
|
|
19
|
+
### 反检测层次架构
|
|
20
|
+
|
|
21
|
+
| 层次 | 问题 | 解决方案 | 相关库 |
|
|
22
|
+
|------|------|----------|--------|
|
|
23
|
+
| **指纹层 (JS)** | navigator.webdriver, plugins, webgl | Stealth 插件 | `puppeteer-extra-plugin-stealth` |
|
|
24
|
+
| **行为层** | 机械输入/点击/滚动 | 人类化模拟 | `ghost-cursor-playwright` |
|
|
25
|
+
| **页面层** | 验证码/风控检测 | 监控器 | toolkit 内置 |
|
|
26
|
+
|
|
27
|
+
> **注意**: `rebrowser-playwright` 与 `playwright-extra` 不兼容,如需要 CDP 层反检测,需要选择其一。
|
|
28
|
+
|
|
29
|
+
### 快速开始
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
import { chromium } from 'playwright-extra';
|
|
33
|
+
import stealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
34
|
+
import { createCursor } from 'ghost-cursor-playwright';
|
|
35
|
+
import { usePlaywrightToolKit } from '@skrillex1224/playwright-toolkit';
|
|
36
|
+
|
|
37
|
+
const { Launch, Humanize, Captcha, Stealth } = usePlaywrightToolKit();
|
|
38
|
+
|
|
39
|
+
// 1. 创建 Stealth 浏览器
|
|
40
|
+
const stealthChromium = Launch.createStealthChromium(chromium, stealthPlugin);
|
|
41
|
+
|
|
42
|
+
// 2. 在 Crawler 中使用
|
|
43
|
+
const crawler = new PlaywrightCrawler({
|
|
44
|
+
launchContext: {
|
|
45
|
+
launcher: stealthChromium,
|
|
46
|
+
launchOptions: Launch.getAdvancedLaunchOptions(), // 增强版启动参数
|
|
47
|
+
},
|
|
48
|
+
preNavigationHooks: [
|
|
49
|
+
async ({ page }) => {
|
|
50
|
+
// 3. 同步视口 (防指纹检测)
|
|
51
|
+
await Stealth.syncViewportWithScreen(page);
|
|
52
|
+
|
|
53
|
+
// 4. 启动验证码监控
|
|
54
|
+
Captcha.useCaptchaMonitor(page, {
|
|
55
|
+
domSelector: '#captcha_container',
|
|
56
|
+
onDetected: async () => { /* 处理验证码 */ }
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
requestHandler: async ({ page }) => {
|
|
61
|
+
// 5. 创建 Ghost Cursor
|
|
62
|
+
const cursor = await Launch.createGhostCursor(page, createCursor);
|
|
63
|
+
|
|
64
|
+
// 6. 页面预热 (模拟人类浏览)
|
|
65
|
+
await Humanize.warmUpBrowsing(page, cursor, 3000);
|
|
66
|
+
|
|
67
|
+
// 7. 人类化输入
|
|
68
|
+
await Humanize.humanType(page, 'input', '搜索内容');
|
|
69
|
+
|
|
70
|
+
// 8. 人类化点击
|
|
71
|
+
await Humanize.humanClick(page, cursor, '#submit-btn');
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 反检测 API 一览
|
|
77
|
+
|
|
78
|
+
| 模块 | 方法 | 说明 |
|
|
79
|
+
|------|------|------|
|
|
80
|
+
| `Launch` | `createStealthChromium(chromium, stealthPlugin)` | 创建已注册 Stealth 的 Chromium |
|
|
81
|
+
| `Launch` | `createGhostCursor(page, createCursor)` | 创建 Ghost Cursor 实例 |
|
|
82
|
+
| `Launch` | `getAdvancedLaunchOptions()` | 获取增强版反检测启动参数 |
|
|
83
|
+
| `Stealth` | `syncViewportWithScreen(page)` | 同步视口与屏幕指纹 |
|
|
84
|
+
| `Stealth` | `hideWebdriver(page)` | 隐藏 navigator.webdriver |
|
|
85
|
+
| `Humanize` | `humanType(page, selector, text)` | 人类化输入 (节奏变化) |
|
|
86
|
+
| `Humanize` | `humanClick(page, cursor, selector)` | 人类化点击 (贝塞尔曲线) |
|
|
87
|
+
| `Humanize` | `warmUpBrowsing(page, cursor, durationMs)` | 页面预热浏览 |
|
|
88
|
+
| `Humanize` | `naturalScroll(page, direction, distance)` | 自然滚动 (带惯性) |
|
|
89
|
+
| `Captcha` | `useCaptchaMonitor(page, options)` | 验证码监控 (DOM/URL) |
|
|
90
|
+
|
|
91
|
+
|
|
16
92
|
|
|
17
93
|
### 1. Live View (实时截图展示)
|
|
18
94
|
|
package/dist/index.cjs
CHANGED
|
@@ -309,7 +309,7 @@ var Humanize = {
|
|
|
309
309
|
while (Date.now() - startTime < durationMs) {
|
|
310
310
|
const x = Math.random() * 800;
|
|
311
311
|
const y = Math.random() * 600;
|
|
312
|
-
await cursor.
|
|
312
|
+
await cursor.actions.move({ x, y });
|
|
313
313
|
await (0, import_delay.rangeDelay)(200, 800);
|
|
314
314
|
}
|
|
315
315
|
},
|
|
@@ -370,7 +370,7 @@ var Humanize = {
|
|
|
370
370
|
if (action < 0.4) {
|
|
371
371
|
const x = 100 + Math.random() * (viewportSize.width - 200);
|
|
372
372
|
const y = 100 + Math.random() * (viewportSize.height - 200);
|
|
373
|
-
await cursor.
|
|
373
|
+
await cursor.actions.move({ x, y });
|
|
374
374
|
await (0, import_delay.rangeDelay)(200, 500);
|
|
375
375
|
} else if (action < 0.7) {
|
|
376
376
|
const scrollY = (Math.random() - 0.5) * 200;
|
|
@@ -399,6 +399,50 @@ var Humanize = {
|
|
|
399
399
|
const delayTime = 50 + i * 30;
|
|
400
400
|
await (0, import_delay.default)(delayTime);
|
|
401
401
|
}
|
|
402
|
+
},
|
|
403
|
+
/**
|
|
404
|
+
* 人类化点击 - 使用 ghost-cursor 模拟人类鼠标移动轨迹并点击
|
|
405
|
+
*
|
|
406
|
+
* 封装了常见的 ghost-cursor 点击模式:定位元素 -> 移动鼠标 -> 随机延迟 -> 点击
|
|
407
|
+
*
|
|
408
|
+
* @param {import('playwright').Page} page
|
|
409
|
+
* @param {import('ghost-cursor-playwright').GhostCursor} cursor - 由 createCursor(page) 创建
|
|
410
|
+
* @param {string} selector - CSS 选择器
|
|
411
|
+
* @param {Object} [options]
|
|
412
|
+
* @param {number} [options.delayBefore=300] - 点击前最小延迟 (ms)
|
|
413
|
+
* @param {number} [options.delayAfter=800] - 点击前最大延迟 (ms)
|
|
414
|
+
* @param {boolean} [options.throwOnMissing=true] - 元素不存在时是否抛出错误
|
|
415
|
+
*/
|
|
416
|
+
async humanClick(page, cursor, selector, options = {}) {
|
|
417
|
+
const {
|
|
418
|
+
delayBefore = 300,
|
|
419
|
+
delayAfter = 800,
|
|
420
|
+
throwOnMissing = true
|
|
421
|
+
} = options;
|
|
422
|
+
const element = await page.$(selector);
|
|
423
|
+
if (!element) {
|
|
424
|
+
if (throwOnMissing) {
|
|
425
|
+
throw new Error(`[Humanize] humanClick: \u627E\u4E0D\u5230\u5143\u7D20 ${selector}`);
|
|
426
|
+
}
|
|
427
|
+
import_crawlee3.log.warning(`[Humanize] humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
const box = await element.boundingBox();
|
|
431
|
+
if (!box) {
|
|
432
|
+
if (throwOnMissing) {
|
|
433
|
+
throw new Error(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u5143\u7D20\u4F4D\u7F6E ${selector}`);
|
|
434
|
+
}
|
|
435
|
+
import_crawlee3.log.warning(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
const offsetX = (Math.random() - 0.5) * box.width * 0.3;
|
|
439
|
+
const offsetY = (Math.random() - 0.5) * box.height * 0.3;
|
|
440
|
+
const x = box.x + box.width / 2 + offsetX;
|
|
441
|
+
const y = box.y + box.height / 2 + offsetY;
|
|
442
|
+
await cursor.actions.move({ x, y });
|
|
443
|
+
await (0, import_delay.rangeDelay)(delayBefore, delayAfter);
|
|
444
|
+
await cursor.actions.click();
|
|
445
|
+
return true;
|
|
402
446
|
}
|
|
403
447
|
};
|
|
404
448
|
|
|
@@ -413,6 +457,18 @@ var Launch = {
|
|
|
413
457
|
ignoreDefaultArgs: ["--enable-automation"]
|
|
414
458
|
};
|
|
415
459
|
},
|
|
460
|
+
/**
|
|
461
|
+
* 获取增强版启动选项(用于高风险反爬场景)
|
|
462
|
+
*/
|
|
463
|
+
getAdvancedLaunchOptions(customArgs = []) {
|
|
464
|
+
return {
|
|
465
|
+
args: [
|
|
466
|
+
...Stealth.getAdvancedStealthArgs(),
|
|
467
|
+
...customArgs
|
|
468
|
+
],
|
|
469
|
+
ignoreDefaultArgs: ["--enable-automation"]
|
|
470
|
+
};
|
|
471
|
+
},
|
|
416
472
|
/**
|
|
417
473
|
* 推荐的 Fingerprint Generator 选项
|
|
418
474
|
* 确保生成的是桌面端、较新的 Chrome,以匹配我们的脚本逻辑
|
|
@@ -424,6 +480,40 @@ var Launch = {
|
|
|
424
480
|
operatingSystems: ["windows", "linux"]
|
|
425
481
|
// 包含 Linux 兼容容器
|
|
426
482
|
};
|
|
483
|
+
},
|
|
484
|
+
/**
|
|
485
|
+
* 创建已注册 Stealth 插件的 Chromium 实例
|
|
486
|
+
*
|
|
487
|
+
* 封装了 `chromium.use(stealthPlugin())` 的常用模式
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```javascript
|
|
491
|
+
* import { chromium } from 'playwright-extra';
|
|
492
|
+
* import stealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
493
|
+
*
|
|
494
|
+
* const stealthChromium = Launch.createStealthChromium(chromium, stealthPlugin);
|
|
495
|
+
* // 现在 stealthChromium 已注册 stealth 插件,可用于 launchContext.launcher
|
|
496
|
+
* ```
|
|
497
|
+
*
|
|
498
|
+
* @param {import('playwright-extra').ChromiumExtra} chromium - playwright-extra 的 chromium
|
|
499
|
+
* @param {Function} stealthPlugin - puppeteer-extra-plugin-stealth 的默认导出
|
|
500
|
+
* @returns {import('playwright-extra').ChromiumExtra} 已注册 stealth 的 chromium
|
|
501
|
+
*/
|
|
502
|
+
createStealthChromium(chromium, stealthPlugin) {
|
|
503
|
+
chromium.use(stealthPlugin());
|
|
504
|
+
return chromium;
|
|
505
|
+
},
|
|
506
|
+
/**
|
|
507
|
+
* 创建 Ghost Cursor 实例
|
|
508
|
+
*
|
|
509
|
+
* 对 ghost-cursor-playwright 的简单封装
|
|
510
|
+
*
|
|
511
|
+
* @param {import('playwright').Page} page
|
|
512
|
+
* @param {Function} createCursor - ghost-cursor-playwright 的 createCursor 函数
|
|
513
|
+
* @returns {Promise<import('ghost-cursor-playwright').Cursor>}
|
|
514
|
+
*/
|
|
515
|
+
async createGhostCursor(page, createCursor) {
|
|
516
|
+
return await createCursor(page);
|
|
427
517
|
}
|
|
428
518
|
};
|
|
429
519
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../index.js", "../src/apify-kit.js", "../src/constants.js", "../src/utils.js", "../src/stealth.js", "../src/humanize.js", "../src/launch.js", "../src/live-view.js", "../src/captcha-monitor.js"],
|
|
4
|
-
"sourcesContent": ["import { ApifyKit } from './src/apify-kit.js';\nimport { Utils } from './src/utils.js';\nimport { Stealth } from './src/stealth.js';\nimport { Humanize } from './src/humanize.js';\nimport { Launch } from './src/launch.js';\nimport { LiveView } from './src/live-view.js';\nimport { Captcha } from './src/captcha-monitor.js';\nimport * as Constants from './src/constants.js';\n\n// Unified Entry Point\nexport const usePlaywrightToolKit = () => {\n return {\n ApifyKit,\n Stealth,\n Humanize,\n Launch,\n LiveView,\n Constants,\n Utils,\n Captcha\n };\n};\n", "import { log } from 'crawlee';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants';\n\n/**\n * \u521B\u5EFA ApifyKit \u5B9E\u4F8B\n * \u5982\u679C apify \u53EF\u7528\uFF0C\u8FD4\u56DE\u5B8C\u6574\u529F\u80FD\u7684 ApifyKit\n * \u5982\u679C apify \u4E0D\u53EF\u7528\uFF0C\u8FD4\u56DE\u964D\u7EA7\u7248\u672C\uFF08\u975E apify \u76F8\u5173\u529F\u80FD\u4ECD\u53EF\u7528\uFF09\n */\nasync function createApifyKit() {\n let apify = null;\n\n // \u5C1D\u8BD5\u52A0\u8F7D apify\n try {\n apify = await import('apify');\n } catch (error) {\n // apify \u4E0D\u53EF\u7528\uFF0C\u5C06\u4F7F\u7528\u964D\u7EA7\u7248\u672C\n throw new Error('\u26A0\uFE0F apify \u5E93\u672A\u5B89\u88C5\uFF0CApifyKit \u7684 Actor \u76F8\u5173\u529F\u80FD\u4E0D\u53EF\u7528')\n }\n\n const { Actor } = apify;\n\n return {\n /**\n * \u5305\u88C5 Step Name\n */\n wrapStepNameWithFailedKey(key, stepName) {\n return `${key}${FAILED_KEY_SEPARATOR}${stepName}`;\n },\n\n /**\n * \u89E3\u5305 Step Name\n */\n unwrapStepName(stepName) {\n const splitIndex = stepName.indexOf(FAILED_KEY_SEPARATOR);\n if (splitIndex === -1) {\n return ['-', stepName];\n }\n const key = stepName.substring(0, splitIndex);\n const value = stepName.substring(splitIndex + FAILED_KEY_SEPARATOR.length);\n return [key, value];\n },\n\n /**\n * \u6838\u5FC3\u5C01\u88C5\uFF1A\u6267\u884C\u6B65\u9AA4\uFF0C\u5E26\u81EA\u52A8\u65E5\u5FD7\u786E\u8BA4\u548C\u5931\u8D25\u622A\u56FE\u5904\u7406\n */\n async runStep(pendingStepName, page, actionFn, options = {}) {\n const { failActor = true } = options; // \u9ED8\u8BA4\u8C03\u7528 Actor.fail\n const [failedKey, stepName] = this.unwrapStepName(pendingStepName);\n\n log.info(`\uD83D\uDD04 [\u6B63\u5728\u6267\u884C] ${stepName}...`);\n\n try {\n const result = await actionFn();\n log.info(`\u2705 [\u6267\u884C\u6210\u529F] ${stepName}`);\n return result;\n } catch (error) {\n log.error(`\u274C [\u6267\u884C\u5931\u8D25] ${stepName}: ${error.message}`);\n\n let screenshotBase64 = '\u622A\u56FE\u5931\u8D25';\n try {\n if (page) {\n const buffer = await page.screenshot({ fullPage: true, type: 'jpeg', quality: 60 });\n screenshotBase64 = `data:image/jpeg;base64,${buffer.toString('base64')}`;\n }\n } catch (snapErr) {\n log.warning(`\u622A\u56FE\u751F\u6210\u5931\u8D25: ${snapErr.message}`);\n }\n\n // \u4F7F\u7528 pushFailed \u65B9\u6CD5\u63A8\u9001\u5931\u8D25\u6570\u636E\uFF08\u79C1\u6709\u4F7F\u7528\uFF09\n await this.pushFailed(error, {\n failedStep: stepName,\n failedKey: failedKey,\n errorMessage: error.message,\n errorStack: error.stack,\n screenshotBase64: screenshotBase64\n });\n\n // \u6839\u636E failActor \u51B3\u5B9A\u662F\u5426\u8C03\u7528 Actor.fail\n if (failActor) {\n await Actor.fail(`Run Step ${stepName} \u5931\u8D25: ${error.message}`);\n } else {\n // \u4E0D\u8C03\u7528 Actor.fail\uFF0C\u76F4\u63A5\u629B\u51FA\u9519\u8BEF\n throw error;\n }\n }\n },\n\n /**\n * \u5BBD\u677E\u7248runStep\uFF1A\u5931\u8D25\u65F6\u4E0D\u8C03\u7528Actor.fail\uFF0C\u53EA\u629B\u51FA\u5F02\u5E38\n */\n async runStepLoose(stepName, page, fn) {\n return await this.runStep(stepName, page, fn, { failActor: false });\n },\n\n /**\n * \u63A8\u9001\u6210\u529F\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\n * @param {Object} data - \u8981\u63A8\u9001\u7684\u6570\u636E\u5BF9\u8C61\n */\n async pushSuccess(data) {\n await Actor.pushData({\n code: StatusCode.Success,\n status: Status.Success,\n timestamp: new Date().toISOString(),\n ...data\n });\n },\n\n /**\n * \u63A8\u9001\u5931\u8D25\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\uFF08\u79C1\u6709\u65B9\u6CD5\uFF0C\u4EC5\u4F9BrunStep\u5185\u90E8\u4F7F\u7528\uFF09\n * @param {Error|Object} error - \u9519\u8BEF\u5BF9\u8C61\uFF08\u53EF\u5305\u542B\u5176\u4ED6\u7684\u9519\u8BEF/\u6216\u90E8\u5206\u5904\u7406\u6210\u529F\u7684\u989D\u5916\u4FE1\u606F\uFF09\n * @param {Object} [meta] - \u989D\u5916\u7684\u6570\u636E\uFF08\u5982failedStep, screenshotBase64\u7B49\uFF0C\u4EC5runStep\u4F7F\u7528\uFF09\n * @private\n */\n async pushFailed(error, meta = {}) {\n await Actor.pushData({\n code: StatusCode.Failed,\n status: Status.Failed,\n // \u8FD9\u91CC\u53EF\u80FD\u5E26\u5176\u4ED6\u9519\u8BEF\u4FE1\u606F\n error,\n timestamp: new Date().toISOString(),\n ...meta\n });\n }\n };\n}\n\n// \u61D2\u52A0\u8F7D\u5355\u4F8B\nlet instance = null;\n\n/**\n * \u83B7\u53D6 ApifyKit \u5B9E\u4F8B\uFF08\u61D2\u52A0\u8F7D\uFF09\n * @returns {Promise<Object>} ApifyKit \u5B9E\u4F8B\n */\nasync function useApifyKit() {\n if (!instance) {\n instance = await createApifyKit();\n }\n return instance;\n}\n\n// \u4E5F\u5BFC\u51FA\u521D\u59CB\u5316\u51FD\u6570\uFF0C\u4F9B\u9700\u8981\u7684\u7528\u6237\u4F7F\u7528\nexport const ApifyKit = {\n useApifyKit\n};\n", "export const ErrorKeygen = {\n NotLogin: 30000001,\n Chaptcha: 30000002,\n}\n\nexport const Status = {\n Success: 'SUCCESS',\n Failed: 'FAILED'\n}\n\nexport const StatusCode = {\n Success: 0,\n Failed: -1\n}\n\nexport const FAILED_KEY_SEPARATOR = '::<@>::';\n\nexport const PresetOfLiveViewKey = 'LIVE_VIEW_SCREENSHOT';\n", "export const Utils = {\n /**\n * \u89E3\u6790 SSE \u6D41\u6587\u672C\n */\n parseSseStream(sseStreamText) {\n const events = [];\n const lines = sseStreamText.split('\\n');\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const jsonContent = line.substring(6).trim();\n if (jsonContent && jsonContent !== '[DONE]') {\n events.push(JSON.parse(jsonContent));\n }\n } catch (e) {\n // Ignore lines that are not valid JSON\n }\n }\n }\n return events;\n }\n}\n", "import { log } from 'crawlee';\n\nexport const Stealth = {\n /**\n * \u5173\u952E\u4FEE\u590D\uFF1A\u5C06 Page \u89C6\u53E3\u8C03\u6574\u4E3A\u4E0E\u6D4F\u89C8\u5668\u6307\u7EB9 (window.screen) \u4E00\u81F4\u3002\n * \u9632\u6B62 \"Viewport Mismatch\" \u7C7B\u578B\u7684\u53CD\u722C\u68C0\u6D4B\u3002\n * @param {import('playwright').Page} page \n */\n async syncViewportWithScreen(page) {\n try {\n // \u83B7\u53D6\u6307\u7EB9\u4E2D\u7684\u5C4F\u5E55\u5C3A\u5BF8\n const screen = await page.evaluate(() => ({\n width: window.screen.width,\n height: window.screen.height,\n availWidth: window.screen.availWidth,\n availHeight: window.screen.availHeight,\n }));\n\n // \u8C03\u6574\u89C6\u53E3\n await page.setViewportSize({\n width: screen.width,\n height: screen.height\n });\n\n log.info(`[Stealth] Viewport synced to fingerprint: ${screen.width}x${screen.height}`);\n } catch (e) {\n log.warning(`[Stealth] Failed to sync viewport: ${e.message}. Fallback to 1920x1080.`);\n await page.setViewportSize({ width: 1920, height: 1080 });\n }\n },\n\n /**\n * \u786E\u4FDD navigator.webdriver \u9690\u85CF (\u901A\u5E38 Playwright Stealth \u63D2\u4EF6\u5DF2\u5904\u7406\uFF0C\u4F46\u53CC\u91CD\u4FDD\u9669)\n */\n async hideWebdriver(page) {\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', {\n get: () => false,\n });\n });\n },\n\n /**\n * \u901A\u7528\u7684 Playwright \u8D44\u6E90\u62E6\u622A\u5668\uFF0C\u7528\u4E8E\u5C4F\u853D\u4E0D\u5FC5\u8981\u7684\u8D44\u6E90\u4EE5\u52A0\u901F\u52A0\u8F7D\n * @param {import('playwright').Page} page\n * @param {string[]} [resourceTypes] - \u8981\u5C4F\u853D\u7684\u8D44\u6E90\u7C7B\u578B\uFF0C\u9ED8\u8BA4\u4E3A ['font', 'image', 'media']\n */\n async setupBlockingResources(page, resourceTypes = ['font', 'image', 'media']) {\n await page.route('**/*', (route) => {\n const request = route.request();\n const type = request.resourceType();\n if (resourceTypes.includes(type)) {\n return route.abort();\n }\n return route.continue();\n });\n },\n\n /**\n * \u83B7\u53D6\u63A8\u8350\u7684 Stealth \u542F\u52A8\u53C2\u6570\n */\n getStealthLaunchArgs() {\n return [\n '--disable-blink-features=AutomationControlled',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-infobars',\n '--window-position=0,0',\n '--ignore-certificate-errors',\n '--disable-web-security',\n // \u6CE8\u610F\uFF1A\u4E0D\u5EFA\u8BAE\u8FD9\u91CC\u5F3A\u5236\u6307\u5B9A window-size\uFF0C\u8BA9 syncViewportWithScreen \u53BB\u52A8\u6001\u8C03\u6574\n // '--window-size=1920,1080' \n ];\n },\n\n /**\n * \u83B7\u53D6\u589E\u5F3A\u7248 Stealth \u542F\u52A8\u53C2\u6570 (\u63A8\u8350\u7528\u4E8E\u9AD8\u98CE\u9669\u53CD\u722C\u573A\u666F)\n * \u5305\u542B\u66F4\u591A\u9488\u5BF9\u81EA\u52A8\u5316\u68C0\u6D4B\u7684\u9632\u62A4\n */\n getAdvancedStealthArgs() {\n return [\n ...this.getStealthLaunchArgs(),\n // \u7981\u7528\u5404\u79CD\u53EF\u80FD\u66B4\u9732\u81EA\u52A8\u5316\u7684\u7279\u5F81\n '--disable-dev-shm-usage',\n '--disable-accelerated-2d-canvas',\n '--disable-gpu-sandbox',\n '--disable-background-networking',\n '--disable-default-apps',\n '--disable-extensions',\n '--disable-sync',\n '--disable-translate',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-first-run',\n // \u6A21\u62DF\u771F\u5B9E\u7528\u6237\u914D\u7F6E\n '--lang=zh-CN,zh',\n ];\n }\n}\n", "import delay, { rangeDelay } from 'delay';\nimport { log } from 'crawlee';\n\nexport const Humanize = {\n /**\n * \u968F\u673A\u5EF6\u8FDF\u4E00\u6BB5\u6BEB\u79D2\u6570 (API Wrapper for 'delay' package)\n * @param {number} min - \u6700\u5C0F\u6BEB\u79D2\n * @param {number} max - \u6700\u5927\u6BEB\u79D2\n */\n async randomSleep(min, max) {\n const ms = typeof max === 'number'\n ? rangeDelay(min, max)\n : delay(min); // \u5982\u679C\u53EA\u4F20\u4E00\u4E2A\u53C2\u6570\uFF0C\u89C6\u4E3A\u56FA\u5B9A\u5EF6\u8FDF\u6216\u6700\u5C0F\u5EF6\u8FDF\n\n // log.debug(`[Humanize] Sleeping for ${await ms} ms...`); // delay return promise acts like number somewhat but best await it\n // The delay package returns a promise that resolves after the delay.\n // delay.range() returns a promise too.\n\n await ms;\n },\n\n /**\n * \u6A21\u62DF\u4EBA\u7C7B\u201C\u6CE8\u89C6\u201D\u6216\u201C\u9605\u8BFB\u201D\u884C\u4E3A\uFF1A\u9F20\u6807\u5728\u9875\u9762\u4E0A\u968F\u673A\u5FAE\u52A8\u3002\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor \n * @param {number} durationMs - \u6301\u7EED\u65F6\u95F4\n */\n async simulateGaze(cursor, durationMs = 2000) {\n const startTime = Date.now();\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u5C0F\u5E45\u5EA6\u79FB\u52A8\n const x = Math.random() * 800;\n const y = Math.random() * 600;\n await cursor.moveTo({ x, y });\n await rangeDelay(200, 800);\n }\n },\n\n /**\n * \u4EBA\u7C7B\u5316\u8F93\u5165 - \u5E26\u8282\u594F\u53D8\u5316\uFF08\u5FEB-\u6162-\u505C\u987F-\u5076\u5C14\u52A0\u901F\uFF09\n * @param {import('playwright').Page} page\n * @param {string} selector - \u8F93\u5165\u6846\u9009\u62E9\u5668\n * @param {string} text - \u8981\u8F93\u5165\u7684\u6587\u672C\n * @param {Object} [options]\n * @param {number} [options.minDelay=50] - \u6700\u5C0F\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.maxDelay=200] - \u6700\u5927\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.pauseProbability=0.1] - \u505C\u987F\u6982\u7387 (0-1)\n * @param {number} [options.pauseMin=300] - \u505C\u987F\u6700\u5C0F\u65F6\u957F (ms)\n * @param {number} [options.pauseMax=800] - \u505C\u987F\u6700\u5927\u65F6\u957F (ms)\n */\n async humanType(page, selector, text, options = {}) {\n const {\n minDelay = 50,\n maxDelay = 200,\n pauseProbability = 0.1,\n pauseMin = 300,\n pauseMax = 800\n } = options;\n\n const locator = page.locator(selector);\n await locator.click();\n await rangeDelay(100, 300);\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n\n // \u8BA1\u7B97\u5F53\u524D\u5B57\u7B26\u7684\u5EF6\u8FDF\uFF08\u6A21\u62DF\u6253\u5B57\u8282\u594F\u53D8\u5316\uFF09\n let charDelay;\n if (char === ' ') {\n // \u7A7A\u683C\u901A\u5E38\u6253\u5F97\u5FEB\n charDelay = minDelay + Math.random() * 50;\n } else if (/[,.!?;:]/.test(char)) {\n // \u6807\u70B9\u540E\u901A\u5E38\u6709\u505C\u987F\n charDelay = maxDelay + Math.random() * 100;\n } else {\n // \u666E\u901A\u5B57\u7B26\u968F\u673A\u5EF6\u8FDF\n charDelay = minDelay + Math.random() * (maxDelay - minDelay);\n }\n\n await locator.press(char);\n await delay(charDelay);\n\n // \u968F\u673A\u505C\u987F\uFF08\u6A21\u62DF\u601D\u8003\u6216\u770B\u5C4F\u5E55\uFF09\n if (Math.random() < pauseProbability && i < text.length - 1) {\n const pauseTime = pauseMin + Math.random() * (pauseMax - pauseMin);\n log.debug(`[Humanize] \u505C\u987F ${Math.round(pauseTime)}ms...`);\n await delay(pauseTime);\n }\n }\n },\n\n /**\n * \u9875\u9762\u9884\u70ED\u6D4F\u89C8 - \u6A21\u62DF\u4EBA\u7C7B\u8FDB\u5165\u9875\u9762\u540E\u7684\u63A2\u7D22\u884C\u4E3A\n * @param {import('playwright').Page} page\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor\n * @param {number} [durationMs=3000] - \u9884\u70ED\u65F6\u957F (ms)\n */\n async warmUpBrowsing(page, cursor, durationMs = 3000) {\n log.info(`[Humanize] \u5F00\u59CB\u9875\u9762\u9884\u70ED\u6D4F\u89C8 (${durationMs}ms)...`);\n const startTime = Date.now();\n const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };\n\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u52A8\u4F5C\u9009\u62E9\n const action = Math.random();\n\n if (action < 0.4) {\n // 40% \u6982\u7387\uFF1A\u9F20\u6807\u968F\u673A\u79FB\u52A8\n const x = 100 + Math.random() * (viewportSize.width - 200);\n const y = 100 + Math.random() * (viewportSize.height - 200);\n await cursor.moveTo({ x, y });\n await rangeDelay(200, 500);\n } else if (action < 0.7) {\n // 30% \u6982\u7387\uFF1A\u5C0F\u5E45\u6EDA\u52A8\n const scrollY = (Math.random() - 0.5) * 200; // -100 \u5230 +100\n await page.mouse.wheel(0, scrollY);\n await rangeDelay(300, 700);\n } else {\n // 30% \u6982\u7387\uFF1A\u505C\u987F\u89C2\u770B\n await rangeDelay(500, 1000);\n }\n }\n\n log.info('[Humanize] \u9875\u9762\u9884\u70ED\u5B8C\u6210');\n },\n\n /**\n * \u81EA\u7136\u6EDA\u52A8 - \u5E26\u60EF\u6027\u548C\u51CF\u901F\u6548\u679C\n * @param {import('playwright').Page} page\n * @param {'up' | 'down'} [direction='down'] - \u6EDA\u52A8\u65B9\u5411\n * @param {number} [distance=300] - \u603B\u6EDA\u52A8\u8DDD\u79BB (px)\n * @param {number} [steps=5] - \u5206\u51E0\u6B65\u5B8C\u6210\n */\n async naturalScroll(page, direction = 'down', distance = 300, steps = 5) {\n const sign = direction === 'down' ? 1 : -1;\n const stepDistance = distance / steps;\n\n // \u6A21\u62DF\u51CF\u901F\u6548\u679C\uFF1A\u5F00\u59CB\u5FEB\uFF0C\u7ED3\u675F\u6162\n for (let i = 0; i < steps; i++) {\n // \u6BCF\u6B65\u6EDA\u52A8\u91CF\u9012\u51CF\n const factor = 1 - (i / steps) * 0.5; // 1 -> 0.5 \u9012\u51CF\n const scrollAmount = stepDistance * factor * sign;\n\n await page.mouse.wheel(0, scrollAmount);\n\n // \u5EF6\u8FDF\u4E5F\u9012\u589E\uFF08\u6A21\u62DF\u51CF\u901F\uFF09\n const delayTime = 50 + i * 30;\n await delay(delayTime);\n }\n }\n}\n", "// \u96C6\u4E2D\u7BA1\u7406\u542F\u52A8\u914D\u7F6E\uFF0C\u6682\u65F6\u4E3B\u8981\u7531 Stealth \u6A21\u5757\u63D0\u4F9B Args\uFF0C\u8FD9\u91CC\u4F5C\u4E3A\u6269\u5C55\u70B9\nimport { Stealth } from './stealth.js';\n\nexport const Launch = {\n getLaunchOptions(customArgs = []) {\n return {\n args: [\n ...Stealth.getStealthLaunchArgs(),\n ...customArgs\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n };\n },\n\n /**\n * \u63A8\u8350\u7684 Fingerprint Generator \u9009\u9879\n * \u786E\u4FDD\u751F\u6210\u7684\u662F\u684C\u9762\u7AEF\u3001\u8F83\u65B0\u7684 Chrome\uFF0C\u4EE5\u5339\u914D\u6211\u4EEC\u7684\u811A\u672C\u903B\u8F91\n */\n getFingerprintGeneratorOptions() {\n return {\n browsers: [{ name: 'chrome', minVersion: 110 }],\n devices: ['desktop'],\n operatingSystems: ['windows', 'linux'], // \u5305\u542B Linux \u517C\u5BB9\u5BB9\u5668\n };\n }\n}\n", "import express from 'express';\nimport { log } from 'crawlee';\nimport { Actor } from 'apify';\nimport { PresetOfLiveViewKey } from './constants';\n\n/**\n * \u542F\u52A8\u4E00\u4E2A Web \u670D\u52A1\u5668\u4EE5\u5728 Live View \u9009\u9879\u5361\u4E2D\u663E\u793A\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\u3002\n */\nasync function startLiveViewServer(liveViewKey) {\n const app = express();\n\n app.get('/', async (req, res) => {\n try {\n // \u4ECE\u9ED8\u8BA4\u7684 Key-Value Store \u4E2D\u8BFB\u53D6\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\n const screenshotBuffer = await Actor.getValue(liveViewKey);\n\n if (!screenshotBuffer) {\n // \u5982\u679C\u8FD8\u6CA1\u6709\u622A\u56FE\uFF0C\u53D1\u9001\u4E00\u4E2A\u81EA\u52A8\u5237\u65B0\u7684\u5360\u4F4D\u9875\u9762\n res.send('<html><head><meta http-equiv=\"refresh\" content=\"2\"></head><body>\u7B49\u5F85\u7B2C\u4E00\u4E2A\u5C4F\u5E55\u622A\u56FE...</body></html>');\n return;\n }\n\n // \u5C06 Buffer \u8F6C\u6362\u4E3A Base64 \u5B57\u7B26\u4E32\n const screenshotBase64 = screenshotBuffer.toString('base64');\n\n // \u53D1\u9001\u4E00\u4E2A HTML \u9875\u9762\uFF0C\u8BE5\u9875\u9762\u6BCF 1 \u79D2\u81EA\u52A8\u5237\u65B0\u4E00\u6B21\uFF0C\u5E76\u663E\u793A\u622A\u56FE\n res.send(`\n <html>\n <head>\n <title>Live View (\u622A\u56FE)</title>\n <meta http-equiv=\"refresh\" content=\"1\">\n </head>\n <body style=\"margin:0; padding:0;\">\n <img src=\"data:image/png;base64,${screenshotBase64}\" \n alt=\"Live View Screenshot\" \n style=\"width: 100%; height: auto;\" />\n </body>\n </html>\n `);\n } catch (error) {\n log.error(`Live View \u670D\u52A1\u5668\u9519\u8BEF: ${error.message}`);\n res.status(500).send(`\u65E0\u6CD5\u52A0\u8F7D\u5C4F\u5E55\u622A\u56FE: ${error.message}`);\n }\n });\n\n // \u76D1\u542C Apify \u5BB9\u5668\u7AEF\u53E3 \n const port = process.env.APIFY_CONTAINER_PORT || 4321;\n app.listen(port, () => { log.info(`Live View \u670D\u52A1\u5668\u5DF2\u542F\u52A8\uFF0C\u76D1\u542C\u7AEF\u53E3 ${port}\u3002\u8BF7\u6253\u5F00 \"Live View\" \u9009\u9879\u5361\u67E5\u770B\u3002`); });\n}\n\n/**\n * \u62CD\u6444\u5F53\u524D\u9875\u9762\u7684\u5C4F\u5E55\u622A\u56FE\u5E76\u5C06\u5176\u4FDD\u5B58\u5230 Key-Value Store\u3002\n * @param {import('playwright').Page} page\n * @param {string} [logMessage] - \u53EF\u9009\u7684\u65E5\u5FD7\u6D88\u606F\u3002\n */\nasync function takeLiveScreenshot(liveViewKey, page, logMessage) {\n try {\n const buffer = await page.screenshot({ type: 'png' });\n await Actor.setValue(liveViewKey, buffer, { contentType: 'image/png' });\n if (logMessage) {\n log.info(`(\u622A\u56FE): ${logMessage}`);\n }\n } catch (e) {\n log.warning(`\u65E0\u6CD5\u6355\u83B7 Live View \u5C4F\u5E55\u622A\u56FE: ${e.message}`);\n }\n}\n\nconst useLiveView = (liveViewKey = PresetOfLiveViewKey) => {\n return {\n takeLiveScreenshot: async (page, logMessage) => {\n return await takeLiveScreenshot(liveViewKey, page, logMessage)\n },\n startLiveViewServer: async () => {\n return await startLiveViewServer(liveViewKey);\n }\n }\n}\n\nexport const LiveView = {\n useLiveView,\n};\n", "import { log } from 'crawlee';\n\n/**\n * \u521B\u5EFA\u9A8C\u8BC1\u7801\u76D1\u63A7\u5668 - \u652F\u6301 DOM \u9009\u62E9\u5668 \u548C URL \u6A21\u5F0F \u4E24\u79CD\u68C0\u6D4B\u65B9\u5F0F\n * \n * \u6CE8\u610F\uFF1A\u76D1\u63A7\u5668\u968F\u9875\u9762\u751F\u547D\u5468\u671F\u81EA\u52A8\u6E05\u7406\uFF0C\u65E0\u9700\u624B\u52A8 cleanup\n * \n * @param {import('playwright').Page} page\n * @param {Object} options\n * @param {string} [options.domSelector] - DOM \u5143\u7D20\u9009\u62E9\u5668 (\u5982 '#captcha_container')\n * @param {string} [options.urlPattern] - URL \u5339\u914D\u6A21\u5F0F (\u5982 '/captcha')\n * @param {Function} options.onDetected - \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\u65F6\u7684\u56DE\u8C03 (async function)\n */\nexport function useCaptchaMonitor(page, options) {\n const { domSelector, urlPattern, onDetected } = options;\n\n if (!domSelector && !urlPattern) {\n throw new Error('[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector \u6216 urlPattern \u81F3\u5C11\u4E00\u4E2A');\n }\n\n if (!onDetected || typeof onDetected !== 'function') {\n throw new Error('[CaptchaMonitor] onDetected \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570');\n }\n\n let isHandled = false;\n let frameHandler = null;\n let exposedFunctionName = null;\n\n const triggerDetected = async () => {\n if (isHandled) return;\n isHandled = true;\n log.error('[CaptchaMonitor] \uD83D\uDED1 \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\uFF01');\n await onDetected();\n };\n\n // ============================================================\n // \u6A21\u5F0F1: DOM \u76D1\u63A7 (\u4F7F\u7528 MutationObserver)\n // ============================================================\n if (domSelector) {\n // \u751F\u6210\u552F\u4E00\u7684\u51FD\u6570\u540D\u907F\u514D\u51B2\u7A81\n exposedFunctionName = `__c_d_${Date.now()}`;\n\n // \u66B4\u9732\u56DE\u8C03\u51FD\u6570\u7ED9\u9875\u9762\n page.exposeFunction(exposedFunctionName, triggerDetected).catch(() => {\n // \u5FFD\u7565\u91CD\u590D\u66B4\u9732\u9519\u8BEF\n });\n\n // \u6CE8\u5165 MutationObserver \u76D1\u542C\u811A\u672C\n page.addInitScript(({ selector, callbackName }) => {\n (() => {\n let observer = null;\n\n const checkAndReport = () => {\n const element = document.querySelector(selector);\n if (element) {\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n if (window[callbackName]) {\n window[callbackName]();\n }\n return true;\n }\n return false;\n };\n\n // 1. \u7ACB\u5373\u68C0\u67E5\u4E00\u6B21\n if (checkAndReport()) return;\n\n // 2. \u542F\u52A8 MutationObserver\n observer = new MutationObserver((mutations) => {\n let shouldCheck = false;\n for (const mutation of mutations) {\n if (mutation.addedNodes.length > 0) {\n shouldCheck = true;\n break;\n }\n }\n if (shouldCheck && observer) {\n checkAndReport();\n }\n });\n\n // 3. \u6302\u8F7D\u76D1\u542C\uFF08\u786E\u4FDD DOM \u51C6\u5907\u5C31\u7EEA\uFF09\n const mountObserver = () => {\n const target = document.documentElement;\n if (target && observer) {\n observer.observe(target, { childList: true, subtree: true });\n }\n };\n\n if (document.readyState === 'loading') {\n window.addEventListener('DOMContentLoaded', mountObserver);\n } else {\n mountObserver();\n }\n })();\n }, { selector: domSelector, callbackName: exposedFunctionName });\n\n log.info(`[CaptchaMonitor] DOM \u76D1\u63A7\u5DF2\u542F\u7528: ${domSelector}`);\n }\n\n // ============================================================\n // \u6A21\u5F0F2: URL \u76D1\u63A7 (\u76D1\u542C framenavigated)\n // ============================================================\n if (urlPattern) {\n frameHandler = async (frame) => {\n if (frame === page.mainFrame()) {\n const currentUrl = page.url();\n if (currentUrl.includes(urlPattern)) {\n await triggerDetected();\n }\n }\n };\n\n page.on('framenavigated', frameHandler);\n log.info(`[CaptchaMonitor] URL \u76D1\u63A7\u5DF2\u542F\u7528: ${urlPattern}`);\n }\n\n // \u6CE8\u610F\uFF1A\u4E0D\u63D0\u4F9B cleanup \u51FD\u6570\n // - DOM \u6A21\u5F0F\uFF1AaddInitScript \u6CE8\u5165\u7684\u4EE3\u7801\u65E0\u6CD5\u4ECE Node \u7AEF\u6E05\u7406\n // - URL \u6A21\u5F0F\uFF1Aframenavigated \u76D1\u542C\u901A\u5E38\u8DDF\u968F\u9875\u9762\u751F\u547D\u5468\u671F\uFF0C\u65E0\u9700\u624B\u52A8\u6E05\u7406\n // \u5982\u679C\u9700\u8981\u63D0\u524D\u7EC8\u6B62\u76D1\u63A7\uFF0C\u8BBE\u8BA1\u4E0A\u5E94\u8BE5\u8BA9 onDetected \u5904\u7406\u540E\u7EED\u903B\u8F91\uFF08\u5982 Actor.fail\uFF09\n}\n\n// \u6309\u7167 toolkit \u7EDF\u4E00\u7684\u5BFC\u51FA\u6A21\u5F0F\nexport const Captcha = {\n useCaptchaMonitor\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { ApifyKit } from './src/apify-kit.js';\nimport { Utils } from './src/utils.js';\nimport { Stealth } from './src/stealth.js';\nimport { Humanize } from './src/humanize.js';\nimport { Launch } from './src/launch.js';\nimport { LiveView } from './src/live-view.js';\nimport { Captcha } from './src/captcha-monitor.js';\nimport * as Constants from './src/constants.js';\n\n// Unified Entry Point\nexport const usePlaywrightToolKit = () => {\n return {\n ApifyKit,\n Stealth,\n Humanize,\n Launch,\n LiveView,\n Constants,\n Utils,\n Captcha\n };\n};\n", "import { log } from 'crawlee';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants';\n\n/**\n * \u521B\u5EFA ApifyKit \u5B9E\u4F8B\n * \u5982\u679C apify \u53EF\u7528\uFF0C\u8FD4\u56DE\u5B8C\u6574\u529F\u80FD\u7684 ApifyKit\n * \u5982\u679C apify \u4E0D\u53EF\u7528\uFF0C\u8FD4\u56DE\u964D\u7EA7\u7248\u672C\uFF08\u975E apify \u76F8\u5173\u529F\u80FD\u4ECD\u53EF\u7528\uFF09\n */\nasync function createApifyKit() {\n let apify = null;\n\n // \u5C1D\u8BD5\u52A0\u8F7D apify\n try {\n apify = await import('apify');\n } catch (error) {\n // apify \u4E0D\u53EF\u7528\uFF0C\u5C06\u4F7F\u7528\u964D\u7EA7\u7248\u672C\n throw new Error('\u26A0\uFE0F apify \u5E93\u672A\u5B89\u88C5\uFF0CApifyKit \u7684 Actor \u76F8\u5173\u529F\u80FD\u4E0D\u53EF\u7528')\n }\n\n const { Actor } = apify;\n\n return {\n /**\n * \u5305\u88C5 Step Name\n */\n wrapStepNameWithFailedKey(key, stepName) {\n return `${key}${FAILED_KEY_SEPARATOR}${stepName}`;\n },\n\n /**\n * \u89E3\u5305 Step Name\n */\n unwrapStepName(stepName) {\n const splitIndex = stepName.indexOf(FAILED_KEY_SEPARATOR);\n if (splitIndex === -1) {\n return ['-', stepName];\n }\n const key = stepName.substring(0, splitIndex);\n const value = stepName.substring(splitIndex + FAILED_KEY_SEPARATOR.length);\n return [key, value];\n },\n\n /**\n * \u6838\u5FC3\u5C01\u88C5\uFF1A\u6267\u884C\u6B65\u9AA4\uFF0C\u5E26\u81EA\u52A8\u65E5\u5FD7\u786E\u8BA4\u548C\u5931\u8D25\u622A\u56FE\u5904\u7406\n */\n async runStep(pendingStepName, page, actionFn, options = {}) {\n const { failActor = true } = options; // \u9ED8\u8BA4\u8C03\u7528 Actor.fail\n const [failedKey, stepName] = this.unwrapStepName(pendingStepName);\n\n log.info(`\uD83D\uDD04 [\u6B63\u5728\u6267\u884C] ${stepName}...`);\n\n try {\n const result = await actionFn();\n log.info(`\u2705 [\u6267\u884C\u6210\u529F] ${stepName}`);\n return result;\n } catch (error) {\n log.error(`\u274C [\u6267\u884C\u5931\u8D25] ${stepName}: ${error.message}`);\n\n let screenshotBase64 = '\u622A\u56FE\u5931\u8D25';\n try {\n if (page) {\n const buffer = await page.screenshot({ fullPage: true, type: 'jpeg', quality: 60 });\n screenshotBase64 = `data:image/jpeg;base64,${buffer.toString('base64')}`;\n }\n } catch (snapErr) {\n log.warning(`\u622A\u56FE\u751F\u6210\u5931\u8D25: ${snapErr.message}`);\n }\n\n // \u4F7F\u7528 pushFailed \u65B9\u6CD5\u63A8\u9001\u5931\u8D25\u6570\u636E\uFF08\u79C1\u6709\u4F7F\u7528\uFF09\n await this.pushFailed(error, {\n failedStep: stepName,\n failedKey: failedKey,\n errorMessage: error.message,\n errorStack: error.stack,\n screenshotBase64: screenshotBase64\n });\n\n // \u6839\u636E failActor \u51B3\u5B9A\u662F\u5426\u8C03\u7528 Actor.fail\n if (failActor) {\n await Actor.fail(`Run Step ${stepName} \u5931\u8D25: ${error.message}`);\n } else {\n // \u4E0D\u8C03\u7528 Actor.fail\uFF0C\u76F4\u63A5\u629B\u51FA\u9519\u8BEF\n throw error;\n }\n }\n },\n\n /**\n * \u5BBD\u677E\u7248runStep\uFF1A\u5931\u8D25\u65F6\u4E0D\u8C03\u7528Actor.fail\uFF0C\u53EA\u629B\u51FA\u5F02\u5E38\n */\n async runStepLoose(stepName, page, fn) {\n return await this.runStep(stepName, page, fn, { failActor: false });\n },\n\n /**\n * \u63A8\u9001\u6210\u529F\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\n * @param {Object} data - \u8981\u63A8\u9001\u7684\u6570\u636E\u5BF9\u8C61\n */\n async pushSuccess(data) {\n await Actor.pushData({\n code: StatusCode.Success,\n status: Status.Success,\n timestamp: new Date().toISOString(),\n ...data\n });\n },\n\n /**\n * \u63A8\u9001\u5931\u8D25\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\uFF08\u79C1\u6709\u65B9\u6CD5\uFF0C\u4EC5\u4F9BrunStep\u5185\u90E8\u4F7F\u7528\uFF09\n * @param {Error|Object} error - \u9519\u8BEF\u5BF9\u8C61\uFF08\u53EF\u5305\u542B\u5176\u4ED6\u7684\u9519\u8BEF/\u6216\u90E8\u5206\u5904\u7406\u6210\u529F\u7684\u989D\u5916\u4FE1\u606F\uFF09\n * @param {Object} [meta] - \u989D\u5916\u7684\u6570\u636E\uFF08\u5982failedStep, screenshotBase64\u7B49\uFF0C\u4EC5runStep\u4F7F\u7528\uFF09\n * @private\n */\n async pushFailed(error, meta = {}) {\n await Actor.pushData({\n code: StatusCode.Failed,\n status: Status.Failed,\n // \u8FD9\u91CC\u53EF\u80FD\u5E26\u5176\u4ED6\u9519\u8BEF\u4FE1\u606F\n error,\n timestamp: new Date().toISOString(),\n ...meta\n });\n }\n };\n}\n\n// \u61D2\u52A0\u8F7D\u5355\u4F8B\nlet instance = null;\n\n/**\n * \u83B7\u53D6 ApifyKit \u5B9E\u4F8B\uFF08\u61D2\u52A0\u8F7D\uFF09\n * @returns {Promise<Object>} ApifyKit \u5B9E\u4F8B\n */\nasync function useApifyKit() {\n if (!instance) {\n instance = await createApifyKit();\n }\n return instance;\n}\n\n// \u4E5F\u5BFC\u51FA\u521D\u59CB\u5316\u51FD\u6570\uFF0C\u4F9B\u9700\u8981\u7684\u7528\u6237\u4F7F\u7528\nexport const ApifyKit = {\n useApifyKit\n};\n", "export const ErrorKeygen = {\n NotLogin: 30000001,\n Chaptcha: 30000002,\n}\n\nexport const Status = {\n Success: 'SUCCESS',\n Failed: 'FAILED'\n}\n\nexport const StatusCode = {\n Success: 0,\n Failed: -1\n}\n\nexport const FAILED_KEY_SEPARATOR = '::<@>::';\n\nexport const PresetOfLiveViewKey = 'LIVE_VIEW_SCREENSHOT';\n", "export const Utils = {\n /**\n * \u89E3\u6790 SSE \u6D41\u6587\u672C\n */\n parseSseStream(sseStreamText) {\n const events = [];\n const lines = sseStreamText.split('\\n');\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const jsonContent = line.substring(6).trim();\n if (jsonContent && jsonContent !== '[DONE]') {\n events.push(JSON.parse(jsonContent));\n }\n } catch (e) {\n // Ignore lines that are not valid JSON\n }\n }\n }\n return events;\n }\n}\n", "import { log } from 'crawlee';\n\nexport const Stealth = {\n /**\n * \u5173\u952E\u4FEE\u590D\uFF1A\u5C06 Page \u89C6\u53E3\u8C03\u6574\u4E3A\u4E0E\u6D4F\u89C8\u5668\u6307\u7EB9 (window.screen) \u4E00\u81F4\u3002\n * \u9632\u6B62 \"Viewport Mismatch\" \u7C7B\u578B\u7684\u53CD\u722C\u68C0\u6D4B\u3002\n * @param {import('playwright').Page} page \n */\n async syncViewportWithScreen(page) {\n try {\n // \u83B7\u53D6\u6307\u7EB9\u4E2D\u7684\u5C4F\u5E55\u5C3A\u5BF8\n const screen = await page.evaluate(() => ({\n width: window.screen.width,\n height: window.screen.height,\n availWidth: window.screen.availWidth,\n availHeight: window.screen.availHeight,\n }));\n\n // \u8C03\u6574\u89C6\u53E3\n await page.setViewportSize({\n width: screen.width,\n height: screen.height\n });\n\n log.info(`[Stealth] Viewport synced to fingerprint: ${screen.width}x${screen.height}`);\n } catch (e) {\n log.warning(`[Stealth] Failed to sync viewport: ${e.message}. Fallback to 1920x1080.`);\n await page.setViewportSize({ width: 1920, height: 1080 });\n }\n },\n\n /**\n * \u786E\u4FDD navigator.webdriver \u9690\u85CF (\u901A\u5E38 Playwright Stealth \u63D2\u4EF6\u5DF2\u5904\u7406\uFF0C\u4F46\u53CC\u91CD\u4FDD\u9669)\n */\n async hideWebdriver(page) {\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', {\n get: () => false,\n });\n });\n },\n\n /**\n * \u901A\u7528\u7684 Playwright \u8D44\u6E90\u62E6\u622A\u5668\uFF0C\u7528\u4E8E\u5C4F\u853D\u4E0D\u5FC5\u8981\u7684\u8D44\u6E90\u4EE5\u52A0\u901F\u52A0\u8F7D\n * @param {import('playwright').Page} page\n * @param {string[]} [resourceTypes] - \u8981\u5C4F\u853D\u7684\u8D44\u6E90\u7C7B\u578B\uFF0C\u9ED8\u8BA4\u4E3A ['font', 'image', 'media']\n */\n async setupBlockingResources(page, resourceTypes = ['font', 'image', 'media']) {\n await page.route('**/*', (route) => {\n const request = route.request();\n const type = request.resourceType();\n if (resourceTypes.includes(type)) {\n return route.abort();\n }\n return route.continue();\n });\n },\n\n /**\n * \u83B7\u53D6\u63A8\u8350\u7684 Stealth \u542F\u52A8\u53C2\u6570\n */\n getStealthLaunchArgs() {\n return [\n '--disable-blink-features=AutomationControlled',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-infobars',\n '--window-position=0,0',\n '--ignore-certificate-errors',\n '--disable-web-security',\n // \u6CE8\u610F\uFF1A\u4E0D\u5EFA\u8BAE\u8FD9\u91CC\u5F3A\u5236\u6307\u5B9A window-size\uFF0C\u8BA9 syncViewportWithScreen \u53BB\u52A8\u6001\u8C03\u6574\n // '--window-size=1920,1080' \n ];\n },\n\n /**\n * \u83B7\u53D6\u589E\u5F3A\u7248 Stealth \u542F\u52A8\u53C2\u6570 (\u63A8\u8350\u7528\u4E8E\u9AD8\u98CE\u9669\u53CD\u722C\u573A\u666F)\n * \u5305\u542B\u66F4\u591A\u9488\u5BF9\u81EA\u52A8\u5316\u68C0\u6D4B\u7684\u9632\u62A4\n */\n getAdvancedStealthArgs() {\n return [\n ...this.getStealthLaunchArgs(),\n // \u7981\u7528\u5404\u79CD\u53EF\u80FD\u66B4\u9732\u81EA\u52A8\u5316\u7684\u7279\u5F81\n '--disable-dev-shm-usage',\n '--disable-accelerated-2d-canvas',\n '--disable-gpu-sandbox',\n '--disable-background-networking',\n '--disable-default-apps',\n '--disable-extensions',\n '--disable-sync',\n '--disable-translate',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-first-run',\n // \u6A21\u62DF\u771F\u5B9E\u7528\u6237\u914D\u7F6E\n '--lang=zh-CN,zh',\n ];\n }\n}\n", "import delay, { rangeDelay } from 'delay';\nimport { log } from 'crawlee';\n\nexport const Humanize = {\n /**\n * \u968F\u673A\u5EF6\u8FDF\u4E00\u6BB5\u6BEB\u79D2\u6570 (API Wrapper for 'delay' package)\n * @param {number} min - \u6700\u5C0F\u6BEB\u79D2\n * @param {number} max - \u6700\u5927\u6BEB\u79D2\n */\n async randomSleep(min, max) {\n const ms = typeof max === 'number'\n ? rangeDelay(min, max)\n : delay(min); // \u5982\u679C\u53EA\u4F20\u4E00\u4E2A\u53C2\u6570\uFF0C\u89C6\u4E3A\u56FA\u5B9A\u5EF6\u8FDF\u6216\u6700\u5C0F\u5EF6\u8FDF\n\n // log.debug(`[Humanize] Sleeping for ${await ms} ms...`); // delay return promise acts like number somewhat but best await it\n // The delay package returns a promise that resolves after the delay.\n // delay.range() returns a promise too.\n\n await ms;\n },\n\n /**\n * \u6A21\u62DF\u4EBA\u7C7B\u201C\u6CE8\u89C6\u201D\u6216\u201C\u9605\u8BFB\u201D\u884C\u4E3A\uFF1A\u9F20\u6807\u5728\u9875\u9762\u4E0A\u968F\u673A\u5FAE\u52A8\u3002\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor \n * @param {number} durationMs - \u6301\u7EED\u65F6\u95F4\n */\n async simulateGaze(cursor, durationMs = 2000) {\n const startTime = Date.now();\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u5C0F\u5E45\u5EA6\u79FB\u52A8\n const x = Math.random() * 800;\n const y = Math.random() * 600;\n await cursor.actions.move({ x, y });\n await rangeDelay(200, 800);\n }\n },\n\n /**\n * \u4EBA\u7C7B\u5316\u8F93\u5165 - \u5E26\u8282\u594F\u53D8\u5316\uFF08\u5FEB-\u6162-\u505C\u987F-\u5076\u5C14\u52A0\u901F\uFF09\n * @param {import('playwright').Page} page\n * @param {string} selector - \u8F93\u5165\u6846\u9009\u62E9\u5668\n * @param {string} text - \u8981\u8F93\u5165\u7684\u6587\u672C\n * @param {Object} [options]\n * @param {number} [options.minDelay=50] - \u6700\u5C0F\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.maxDelay=200] - \u6700\u5927\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.pauseProbability=0.1] - \u505C\u987F\u6982\u7387 (0-1)\n * @param {number} [options.pauseMin=300] - \u505C\u987F\u6700\u5C0F\u65F6\u957F (ms)\n * @param {number} [options.pauseMax=800] - \u505C\u987F\u6700\u5927\u65F6\u957F (ms)\n */\n async humanType(page, selector, text, options = {}) {\n const {\n minDelay = 50,\n maxDelay = 200,\n pauseProbability = 0.1,\n pauseMin = 300,\n pauseMax = 800\n } = options;\n\n const locator = page.locator(selector);\n await locator.click();\n await rangeDelay(100, 300);\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n\n // \u8BA1\u7B97\u5F53\u524D\u5B57\u7B26\u7684\u5EF6\u8FDF\uFF08\u6A21\u62DF\u6253\u5B57\u8282\u594F\u53D8\u5316\uFF09\n let charDelay;\n if (char === ' ') {\n // \u7A7A\u683C\u901A\u5E38\u6253\u5F97\u5FEB\n charDelay = minDelay + Math.random() * 50;\n } else if (/[,.!?;:]/.test(char)) {\n // \u6807\u70B9\u540E\u901A\u5E38\u6709\u505C\u987F\n charDelay = maxDelay + Math.random() * 100;\n } else {\n // \u666E\u901A\u5B57\u7B26\u968F\u673A\u5EF6\u8FDF\n charDelay = minDelay + Math.random() * (maxDelay - minDelay);\n }\n\n await locator.press(char);\n await delay(charDelay);\n\n // \u968F\u673A\u505C\u987F\uFF08\u6A21\u62DF\u601D\u8003\u6216\u770B\u5C4F\u5E55\uFF09\n if (Math.random() < pauseProbability && i < text.length - 1) {\n const pauseTime = pauseMin + Math.random() * (pauseMax - pauseMin);\n log.debug(`[Humanize] \u505C\u987F ${Math.round(pauseTime)}ms...`);\n await delay(pauseTime);\n }\n }\n },\n\n /**\n * \u9875\u9762\u9884\u70ED\u6D4F\u89C8 - \u6A21\u62DF\u4EBA\u7C7B\u8FDB\u5165\u9875\u9762\u540E\u7684\u63A2\u7D22\u884C\u4E3A\n * @param {import('playwright').Page} page\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor\n * @param {number} [durationMs=3000] - \u9884\u70ED\u65F6\u957F (ms)\n */\n async warmUpBrowsing(page, cursor, durationMs = 3000) {\n log.info(`[Humanize] \u5F00\u59CB\u9875\u9762\u9884\u70ED\u6D4F\u89C8 (${durationMs}ms)...`);\n const startTime = Date.now();\n const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };\n\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u52A8\u4F5C\u9009\u62E9\n const action = Math.random();\n\n if (action < 0.4) {\n // 40% \u6982\u7387\uFF1A\u9F20\u6807\u968F\u673A\u79FB\u52A8\n const x = 100 + Math.random() * (viewportSize.width - 200);\n const y = 100 + Math.random() * (viewportSize.height - 200);\n await cursor.actions.move({ x, y });\n await rangeDelay(200, 500);\n } else if (action < 0.7) {\n // 30% \u6982\u7387\uFF1A\u5C0F\u5E45\u6EDA\u52A8\n const scrollY = (Math.random() - 0.5) * 200; // -100 \u5230 +100\n await page.mouse.wheel(0, scrollY);\n await rangeDelay(300, 700);\n } else {\n // 30% \u6982\u7387\uFF1A\u505C\u987F\u89C2\u770B\n await rangeDelay(500, 1000);\n }\n }\n\n log.info('[Humanize] \u9875\u9762\u9884\u70ED\u5B8C\u6210');\n },\n\n /**\n * \u81EA\u7136\u6EDA\u52A8 - \u5E26\u60EF\u6027\u548C\u51CF\u901F\u6548\u679C\n * @param {import('playwright').Page} page\n * @param {'up' | 'down'} [direction='down'] - \u6EDA\u52A8\u65B9\u5411\n * @param {number} [distance=300] - \u603B\u6EDA\u52A8\u8DDD\u79BB (px)\n * @param {number} [steps=5] - \u5206\u51E0\u6B65\u5B8C\u6210\n */\n async naturalScroll(page, direction = 'down', distance = 300, steps = 5) {\n const sign = direction === 'down' ? 1 : -1;\n const stepDistance = distance / steps;\n\n // \u6A21\u62DF\u51CF\u901F\u6548\u679C\uFF1A\u5F00\u59CB\u5FEB\uFF0C\u7ED3\u675F\u6162\n for (let i = 0; i < steps; i++) {\n // \u6BCF\u6B65\u6EDA\u52A8\u91CF\u9012\u51CF\n const factor = 1 - (i / steps) * 0.5; // 1 -> 0.5 \u9012\u51CF\n const scrollAmount = stepDistance * factor * sign;\n\n await page.mouse.wheel(0, scrollAmount);\n\n // \u5EF6\u8FDF\u4E5F\u9012\u589E\uFF08\u6A21\u62DF\u51CF\u901F\uFF09\n const delayTime = 50 + i * 30;\n await delay(delayTime);\n }\n },\n\n /**\n * \u4EBA\u7C7B\u5316\u70B9\u51FB - \u4F7F\u7528 ghost-cursor \u6A21\u62DF\u4EBA\u7C7B\u9F20\u6807\u79FB\u52A8\u8F68\u8FF9\u5E76\u70B9\u51FB\n * \n * \u5C01\u88C5\u4E86\u5E38\u89C1\u7684 ghost-cursor \u70B9\u51FB\u6A21\u5F0F\uFF1A\u5B9A\u4F4D\u5143\u7D20 -> \u79FB\u52A8\u9F20\u6807 -> \u968F\u673A\u5EF6\u8FDF -> \u70B9\u51FB\n * \n * @param {import('playwright').Page} page\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor - \u7531 createCursor(page) \u521B\u5EFA\n * @param {string} selector - CSS \u9009\u62E9\u5668\n * @param {Object} [options]\n * @param {number} [options.delayBefore=300] - \u70B9\u51FB\u524D\u6700\u5C0F\u5EF6\u8FDF (ms)\n * @param {number} [options.delayAfter=800] - \u70B9\u51FB\u524D\u6700\u5927\u5EF6\u8FDF (ms)\n * @param {boolean} [options.throwOnMissing=true] - \u5143\u7D20\u4E0D\u5B58\u5728\u65F6\u662F\u5426\u629B\u51FA\u9519\u8BEF\n */\n async humanClick(page, cursor, selector, options = {}) {\n const {\n delayBefore = 300,\n delayAfter = 800,\n throwOnMissing = true\n } = options;\n\n const element = await page.$(selector);\n if (!element) {\n if (throwOnMissing) {\n throw new Error(`[Humanize] humanClick: \u627E\u4E0D\u5230\u5143\u7D20 ${selector}`);\n }\n log.warning(`[Humanize] humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);\n return false;\n }\n\n const box = await element.boundingBox();\n if (!box) {\n if (throwOnMissing) {\n throw new Error(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u5143\u7D20\u4F4D\u7F6E ${selector}`);\n }\n log.warning(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);\n return false;\n }\n\n // \u8BA1\u7B97\u5143\u7D20\u4E2D\u5FC3\u70B9\uFF08\u5E26\u968F\u673A\u504F\u79FB\uFF09\n const offsetX = (Math.random() - 0.5) * box.width * 0.3; // \u00B115% \u504F\u79FB\n const offsetY = (Math.random() - 0.5) * box.height * 0.3;\n const x = box.x + box.width / 2 + offsetX;\n const y = box.y + box.height / 2 + offsetY;\n\n // \u79FB\u52A8\u9F20\u6807\n await cursor.actions.move({ x, y });\n\n // \u968F\u673A\u5EF6\u8FDF\u540E\u70B9\u51FB\n await rangeDelay(delayBefore, delayAfter);\n await cursor.actions.click();\n\n return true;\n }\n}\n", "// \u96C6\u4E2D\u7BA1\u7406\u542F\u52A8\u914D\u7F6E\uFF0C\u6682\u65F6\u4E3B\u8981\u7531 Stealth \u6A21\u5757\u63D0\u4F9B Args\uFF0C\u8FD9\u91CC\u4F5C\u4E3A\u6269\u5C55\u70B9\nimport { Stealth } from './stealth.js';\n\nexport const Launch = {\n getLaunchOptions(customArgs = []) {\n return {\n args: [\n ...Stealth.getStealthLaunchArgs(),\n ...customArgs\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n };\n },\n\n /**\n * \u83B7\u53D6\u589E\u5F3A\u7248\u542F\u52A8\u9009\u9879\uFF08\u7528\u4E8E\u9AD8\u98CE\u9669\u53CD\u722C\u573A\u666F\uFF09\n */\n getAdvancedLaunchOptions(customArgs = []) {\n return {\n args: [\n ...Stealth.getAdvancedStealthArgs(),\n ...customArgs\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n };\n },\n\n /**\n * \u63A8\u8350\u7684 Fingerprint Generator \u9009\u9879\n * \u786E\u4FDD\u751F\u6210\u7684\u662F\u684C\u9762\u7AEF\u3001\u8F83\u65B0\u7684 Chrome\uFF0C\u4EE5\u5339\u914D\u6211\u4EEC\u7684\u811A\u672C\u903B\u8F91\n */\n getFingerprintGeneratorOptions() {\n return {\n browsers: [{ name: 'chrome', minVersion: 110 }],\n devices: ['desktop'],\n operatingSystems: ['windows', 'linux'], // \u5305\u542B Linux \u517C\u5BB9\u5BB9\u5668\n };\n },\n\n /**\n * \u521B\u5EFA\u5DF2\u6CE8\u518C Stealth \u63D2\u4EF6\u7684 Chromium \u5B9E\u4F8B\n * \n * \u5C01\u88C5\u4E86 `chromium.use(stealthPlugin())` \u7684\u5E38\u7528\u6A21\u5F0F\n * \n * @example\n * ```javascript\n * import { chromium } from 'playwright-extra';\n * import stealthPlugin from 'puppeteer-extra-plugin-stealth';\n * \n * const stealthChromium = Launch.createStealthChromium(chromium, stealthPlugin);\n * // \u73B0\u5728 stealthChromium \u5DF2\u6CE8\u518C stealth \u63D2\u4EF6\uFF0C\u53EF\u7528\u4E8E launchContext.launcher\n * ```\n * \n * @param {import('playwright-extra').ChromiumExtra} chromium - playwright-extra \u7684 chromium\n * @param {Function} stealthPlugin - puppeteer-extra-plugin-stealth \u7684\u9ED8\u8BA4\u5BFC\u51FA\n * @returns {import('playwright-extra').ChromiumExtra} \u5DF2\u6CE8\u518C stealth \u7684 chromium\n */\n createStealthChromium(chromium, stealthPlugin) {\n chromium.use(stealthPlugin());\n return chromium;\n },\n\n /**\n * \u521B\u5EFA Ghost Cursor \u5B9E\u4F8B\n * \n * \u5BF9 ghost-cursor-playwright \u7684\u7B80\u5355\u5C01\u88C5\n * \n * @param {import('playwright').Page} page\n * @param {Function} createCursor - ghost-cursor-playwright \u7684 createCursor \u51FD\u6570\n * @returns {Promise<import('ghost-cursor-playwright').Cursor>}\n */\n async createGhostCursor(page, createCursor) {\n return await createCursor(page);\n }\n}\n\n", "import express from 'express';\nimport { log } from 'crawlee';\nimport { Actor } from 'apify';\nimport { PresetOfLiveViewKey } from './constants';\n\n/**\n * \u542F\u52A8\u4E00\u4E2A Web \u670D\u52A1\u5668\u4EE5\u5728 Live View \u9009\u9879\u5361\u4E2D\u663E\u793A\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\u3002\n */\nasync function startLiveViewServer(liveViewKey) {\n const app = express();\n\n app.get('/', async (req, res) => {\n try {\n // \u4ECE\u9ED8\u8BA4\u7684 Key-Value Store \u4E2D\u8BFB\u53D6\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\n const screenshotBuffer = await Actor.getValue(liveViewKey);\n\n if (!screenshotBuffer) {\n // \u5982\u679C\u8FD8\u6CA1\u6709\u622A\u56FE\uFF0C\u53D1\u9001\u4E00\u4E2A\u81EA\u52A8\u5237\u65B0\u7684\u5360\u4F4D\u9875\u9762\n res.send('<html><head><meta http-equiv=\"refresh\" content=\"2\"></head><body>\u7B49\u5F85\u7B2C\u4E00\u4E2A\u5C4F\u5E55\u622A\u56FE...</body></html>');\n return;\n }\n\n // \u5C06 Buffer \u8F6C\u6362\u4E3A Base64 \u5B57\u7B26\u4E32\n const screenshotBase64 = screenshotBuffer.toString('base64');\n\n // \u53D1\u9001\u4E00\u4E2A HTML \u9875\u9762\uFF0C\u8BE5\u9875\u9762\u6BCF 1 \u79D2\u81EA\u52A8\u5237\u65B0\u4E00\u6B21\uFF0C\u5E76\u663E\u793A\u622A\u56FE\n res.send(`\n <html>\n <head>\n <title>Live View (\u622A\u56FE)</title>\n <meta http-equiv=\"refresh\" content=\"1\">\n </head>\n <body style=\"margin:0; padding:0;\">\n <img src=\"data:image/png;base64,${screenshotBase64}\" \n alt=\"Live View Screenshot\" \n style=\"width: 100%; height: auto;\" />\n </body>\n </html>\n `);\n } catch (error) {\n log.error(`Live View \u670D\u52A1\u5668\u9519\u8BEF: ${error.message}`);\n res.status(500).send(`\u65E0\u6CD5\u52A0\u8F7D\u5C4F\u5E55\u622A\u56FE: ${error.message}`);\n }\n });\n\n // \u76D1\u542C Apify \u5BB9\u5668\u7AEF\u53E3 \n const port = process.env.APIFY_CONTAINER_PORT || 4321;\n app.listen(port, () => { log.info(`Live View \u670D\u52A1\u5668\u5DF2\u542F\u52A8\uFF0C\u76D1\u542C\u7AEF\u53E3 ${port}\u3002\u8BF7\u6253\u5F00 \"Live View\" \u9009\u9879\u5361\u67E5\u770B\u3002`); });\n}\n\n/**\n * \u62CD\u6444\u5F53\u524D\u9875\u9762\u7684\u5C4F\u5E55\u622A\u56FE\u5E76\u5C06\u5176\u4FDD\u5B58\u5230 Key-Value Store\u3002\n * @param {import('playwright').Page} page\n * @param {string} [logMessage] - \u53EF\u9009\u7684\u65E5\u5FD7\u6D88\u606F\u3002\n */\nasync function takeLiveScreenshot(liveViewKey, page, logMessage) {\n try {\n const buffer = await page.screenshot({ type: 'png' });\n await Actor.setValue(liveViewKey, buffer, { contentType: 'image/png' });\n if (logMessage) {\n log.info(`(\u622A\u56FE): ${logMessage}`);\n }\n } catch (e) {\n log.warning(`\u65E0\u6CD5\u6355\u83B7 Live View \u5C4F\u5E55\u622A\u56FE: ${e.message}`);\n }\n}\n\nconst useLiveView = (liveViewKey = PresetOfLiveViewKey) => {\n return {\n takeLiveScreenshot: async (page, logMessage) => {\n return await takeLiveScreenshot(liveViewKey, page, logMessage)\n },\n startLiveViewServer: async () => {\n return await startLiveViewServer(liveViewKey);\n }\n }\n}\n\nexport const LiveView = {\n useLiveView,\n};\n", "import { log } from 'crawlee';\n\n/**\n * \u521B\u5EFA\u9A8C\u8BC1\u7801\u76D1\u63A7\u5668 - \u652F\u6301 DOM \u9009\u62E9\u5668 \u548C URL \u6A21\u5F0F \u4E24\u79CD\u68C0\u6D4B\u65B9\u5F0F\n * \n * \u6CE8\u610F\uFF1A\u76D1\u63A7\u5668\u968F\u9875\u9762\u751F\u547D\u5468\u671F\u81EA\u52A8\u6E05\u7406\uFF0C\u65E0\u9700\u624B\u52A8 cleanup\n * \n * @param {import('playwright').Page} page\n * @param {Object} options\n * @param {string} [options.domSelector] - DOM \u5143\u7D20\u9009\u62E9\u5668 (\u5982 '#captcha_container')\n * @param {string} [options.urlPattern] - URL \u5339\u914D\u6A21\u5F0F (\u5982 '/captcha')\n * @param {Function} options.onDetected - \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\u65F6\u7684\u56DE\u8C03 (async function)\n */\nexport function useCaptchaMonitor(page, options) {\n const { domSelector, urlPattern, onDetected } = options;\n\n if (!domSelector && !urlPattern) {\n throw new Error('[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector \u6216 urlPattern \u81F3\u5C11\u4E00\u4E2A');\n }\n\n if (!onDetected || typeof onDetected !== 'function') {\n throw new Error('[CaptchaMonitor] onDetected \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570');\n }\n\n let isHandled = false;\n let frameHandler = null;\n let exposedFunctionName = null;\n\n const triggerDetected = async () => {\n if (isHandled) return;\n isHandled = true;\n log.error('[CaptchaMonitor] \uD83D\uDED1 \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\uFF01');\n await onDetected();\n };\n\n // ============================================================\n // \u6A21\u5F0F1: DOM \u76D1\u63A7 (\u4F7F\u7528 MutationObserver)\n // ============================================================\n if (domSelector) {\n // \u751F\u6210\u552F\u4E00\u7684\u51FD\u6570\u540D\u907F\u514D\u51B2\u7A81\n exposedFunctionName = `__c_d_${Date.now()}`;\n\n // \u66B4\u9732\u56DE\u8C03\u51FD\u6570\u7ED9\u9875\u9762\n page.exposeFunction(exposedFunctionName, triggerDetected).catch(() => {\n // \u5FFD\u7565\u91CD\u590D\u66B4\u9732\u9519\u8BEF\n });\n\n // \u6CE8\u5165 MutationObserver \u76D1\u542C\u811A\u672C\n page.addInitScript(({ selector, callbackName }) => {\n (() => {\n let observer = null;\n\n const checkAndReport = () => {\n const element = document.querySelector(selector);\n if (element) {\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n if (window[callbackName]) {\n window[callbackName]();\n }\n return true;\n }\n return false;\n };\n\n // 1. \u7ACB\u5373\u68C0\u67E5\u4E00\u6B21\n if (checkAndReport()) return;\n\n // 2. \u542F\u52A8 MutationObserver\n observer = new MutationObserver((mutations) => {\n let shouldCheck = false;\n for (const mutation of mutations) {\n if (mutation.addedNodes.length > 0) {\n shouldCheck = true;\n break;\n }\n }\n if (shouldCheck && observer) {\n checkAndReport();\n }\n });\n\n // 3. \u6302\u8F7D\u76D1\u542C\uFF08\u786E\u4FDD DOM \u51C6\u5907\u5C31\u7EEA\uFF09\n const mountObserver = () => {\n const target = document.documentElement;\n if (target && observer) {\n observer.observe(target, { childList: true, subtree: true });\n }\n };\n\n if (document.readyState === 'loading') {\n window.addEventListener('DOMContentLoaded', mountObserver);\n } else {\n mountObserver();\n }\n })();\n }, { selector: domSelector, callbackName: exposedFunctionName });\n\n log.info(`[CaptchaMonitor] DOM \u76D1\u63A7\u5DF2\u542F\u7528: ${domSelector}`);\n }\n\n // ============================================================\n // \u6A21\u5F0F2: URL \u76D1\u63A7 (\u76D1\u542C framenavigated)\n // ============================================================\n if (urlPattern) {\n frameHandler = async (frame) => {\n if (frame === page.mainFrame()) {\n const currentUrl = page.url();\n if (currentUrl.includes(urlPattern)) {\n await triggerDetected();\n }\n }\n };\n\n page.on('framenavigated', frameHandler);\n log.info(`[CaptchaMonitor] URL \u76D1\u63A7\u5DF2\u542F\u7528: ${urlPattern}`);\n }\n\n // \u6CE8\u610F\uFF1A\u4E0D\u63D0\u4F9B cleanup \u51FD\u6570\n // - DOM \u6A21\u5F0F\uFF1AaddInitScript \u6CE8\u5165\u7684\u4EE3\u7801\u65E0\u6CD5\u4ECE Node \u7AEF\u6E05\u7406\n // - URL \u6A21\u5F0F\uFF1Aframenavigated \u76D1\u542C\u901A\u5E38\u8DDF\u968F\u9875\u9762\u751F\u547D\u5468\u671F\uFF0C\u65E0\u9700\u624B\u52A8\u6E05\u7406\n // \u5982\u679C\u9700\u8981\u63D0\u524D\u7EC8\u6B62\u76D1\u63A7\uFF0C\u8BBE\u8BA1\u4E0A\u5E94\u8BE5\u8BA9 onDetected \u5904\u7406\u540E\u7EED\u903B\u8F91\uFF08\u5982 Actor.fail\uFF09\n}\n\n// \u6309\u7167 toolkit \u7EDF\u4E00\u7684\u5BFC\u51FA\u6A21\u5F0F\nexport const Captcha = {\n useCaptchaMonitor\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Actor", "import_crawlee", "import_crawlee", "delay", "import_crawlee", "express", "import_crawlee"]
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -280,7 +280,7 @@ var Humanize = {
|
|
|
280
280
|
while (Date.now() - startTime < durationMs) {
|
|
281
281
|
const x = Math.random() * 800;
|
|
282
282
|
const y = Math.random() * 600;
|
|
283
|
-
await cursor.
|
|
283
|
+
await cursor.actions.move({ x, y });
|
|
284
284
|
await rangeDelay(200, 800);
|
|
285
285
|
}
|
|
286
286
|
},
|
|
@@ -341,7 +341,7 @@ var Humanize = {
|
|
|
341
341
|
if (action < 0.4) {
|
|
342
342
|
const x = 100 + Math.random() * (viewportSize.width - 200);
|
|
343
343
|
const y = 100 + Math.random() * (viewportSize.height - 200);
|
|
344
|
-
await cursor.
|
|
344
|
+
await cursor.actions.move({ x, y });
|
|
345
345
|
await rangeDelay(200, 500);
|
|
346
346
|
} else if (action < 0.7) {
|
|
347
347
|
const scrollY = (Math.random() - 0.5) * 200;
|
|
@@ -370,6 +370,50 @@ var Humanize = {
|
|
|
370
370
|
const delayTime = 50 + i * 30;
|
|
371
371
|
await delay(delayTime);
|
|
372
372
|
}
|
|
373
|
+
},
|
|
374
|
+
/**
|
|
375
|
+
* 人类化点击 - 使用 ghost-cursor 模拟人类鼠标移动轨迹并点击
|
|
376
|
+
*
|
|
377
|
+
* 封装了常见的 ghost-cursor 点击模式:定位元素 -> 移动鼠标 -> 随机延迟 -> 点击
|
|
378
|
+
*
|
|
379
|
+
* @param {import('playwright').Page} page
|
|
380
|
+
* @param {import('ghost-cursor-playwright').GhostCursor} cursor - 由 createCursor(page) 创建
|
|
381
|
+
* @param {string} selector - CSS 选择器
|
|
382
|
+
* @param {Object} [options]
|
|
383
|
+
* @param {number} [options.delayBefore=300] - 点击前最小延迟 (ms)
|
|
384
|
+
* @param {number} [options.delayAfter=800] - 点击前最大延迟 (ms)
|
|
385
|
+
* @param {boolean} [options.throwOnMissing=true] - 元素不存在时是否抛出错误
|
|
386
|
+
*/
|
|
387
|
+
async humanClick(page, cursor, selector, options = {}) {
|
|
388
|
+
const {
|
|
389
|
+
delayBefore = 300,
|
|
390
|
+
delayAfter = 800,
|
|
391
|
+
throwOnMissing = true
|
|
392
|
+
} = options;
|
|
393
|
+
const element = await page.$(selector);
|
|
394
|
+
if (!element) {
|
|
395
|
+
if (throwOnMissing) {
|
|
396
|
+
throw new Error(`[Humanize] humanClick: \u627E\u4E0D\u5230\u5143\u7D20 ${selector}`);
|
|
397
|
+
}
|
|
398
|
+
log3.warning(`[Humanize] humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
const box = await element.boundingBox();
|
|
402
|
+
if (!box) {
|
|
403
|
+
if (throwOnMissing) {
|
|
404
|
+
throw new Error(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u5143\u7D20\u4F4D\u7F6E ${selector}`);
|
|
405
|
+
}
|
|
406
|
+
log3.warning(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
const offsetX = (Math.random() - 0.5) * box.width * 0.3;
|
|
410
|
+
const offsetY = (Math.random() - 0.5) * box.height * 0.3;
|
|
411
|
+
const x = box.x + box.width / 2 + offsetX;
|
|
412
|
+
const y = box.y + box.height / 2 + offsetY;
|
|
413
|
+
await cursor.actions.move({ x, y });
|
|
414
|
+
await rangeDelay(delayBefore, delayAfter);
|
|
415
|
+
await cursor.actions.click();
|
|
416
|
+
return true;
|
|
373
417
|
}
|
|
374
418
|
};
|
|
375
419
|
|
|
@@ -384,6 +428,18 @@ var Launch = {
|
|
|
384
428
|
ignoreDefaultArgs: ["--enable-automation"]
|
|
385
429
|
};
|
|
386
430
|
},
|
|
431
|
+
/**
|
|
432
|
+
* 获取增强版启动选项(用于高风险反爬场景)
|
|
433
|
+
*/
|
|
434
|
+
getAdvancedLaunchOptions(customArgs = []) {
|
|
435
|
+
return {
|
|
436
|
+
args: [
|
|
437
|
+
...Stealth.getAdvancedStealthArgs(),
|
|
438
|
+
...customArgs
|
|
439
|
+
],
|
|
440
|
+
ignoreDefaultArgs: ["--enable-automation"]
|
|
441
|
+
};
|
|
442
|
+
},
|
|
387
443
|
/**
|
|
388
444
|
* 推荐的 Fingerprint Generator 选项
|
|
389
445
|
* 确保生成的是桌面端、较新的 Chrome,以匹配我们的脚本逻辑
|
|
@@ -395,6 +451,40 @@ var Launch = {
|
|
|
395
451
|
operatingSystems: ["windows", "linux"]
|
|
396
452
|
// 包含 Linux 兼容容器
|
|
397
453
|
};
|
|
454
|
+
},
|
|
455
|
+
/**
|
|
456
|
+
* 创建已注册 Stealth 插件的 Chromium 实例
|
|
457
|
+
*
|
|
458
|
+
* 封装了 `chromium.use(stealthPlugin())` 的常用模式
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* ```javascript
|
|
462
|
+
* import { chromium } from 'playwright-extra';
|
|
463
|
+
* import stealthPlugin from 'puppeteer-extra-plugin-stealth';
|
|
464
|
+
*
|
|
465
|
+
* const stealthChromium = Launch.createStealthChromium(chromium, stealthPlugin);
|
|
466
|
+
* // 现在 stealthChromium 已注册 stealth 插件,可用于 launchContext.launcher
|
|
467
|
+
* ```
|
|
468
|
+
*
|
|
469
|
+
* @param {import('playwright-extra').ChromiumExtra} chromium - playwright-extra 的 chromium
|
|
470
|
+
* @param {Function} stealthPlugin - puppeteer-extra-plugin-stealth 的默认导出
|
|
471
|
+
* @returns {import('playwright-extra').ChromiumExtra} 已注册 stealth 的 chromium
|
|
472
|
+
*/
|
|
473
|
+
createStealthChromium(chromium, stealthPlugin) {
|
|
474
|
+
chromium.use(stealthPlugin());
|
|
475
|
+
return chromium;
|
|
476
|
+
},
|
|
477
|
+
/**
|
|
478
|
+
* 创建 Ghost Cursor 实例
|
|
479
|
+
*
|
|
480
|
+
* 对 ghost-cursor-playwright 的简单封装
|
|
481
|
+
*
|
|
482
|
+
* @param {import('playwright').Page} page
|
|
483
|
+
* @param {Function} createCursor - ghost-cursor-playwright 的 createCursor 函数
|
|
484
|
+
* @returns {Promise<import('ghost-cursor-playwright').Cursor>}
|
|
485
|
+
*/
|
|
486
|
+
async createGhostCursor(page, createCursor) {
|
|
487
|
+
return await createCursor(page);
|
|
398
488
|
}
|
|
399
489
|
};
|
|
400
490
|
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/apify-kit.js", "../src/constants.js", "../src/utils.js", "../src/stealth.js", "../src/humanize.js", "../src/launch.js", "../src/live-view.js", "../src/captcha-monitor.js", "../index.js"],
|
|
4
|
-
"sourcesContent": ["import { log } from 'crawlee';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants';\n\n/**\n * \u521B\u5EFA ApifyKit \u5B9E\u4F8B\n * \u5982\u679C apify \u53EF\u7528\uFF0C\u8FD4\u56DE\u5B8C\u6574\u529F\u80FD\u7684 ApifyKit\n * \u5982\u679C apify \u4E0D\u53EF\u7528\uFF0C\u8FD4\u56DE\u964D\u7EA7\u7248\u672C\uFF08\u975E apify \u76F8\u5173\u529F\u80FD\u4ECD\u53EF\u7528\uFF09\n */\nasync function createApifyKit() {\n let apify = null;\n\n // \u5C1D\u8BD5\u52A0\u8F7D apify\n try {\n apify = await import('apify');\n } catch (error) {\n // apify \u4E0D\u53EF\u7528\uFF0C\u5C06\u4F7F\u7528\u964D\u7EA7\u7248\u672C\n throw new Error('\u26A0\uFE0F apify \u5E93\u672A\u5B89\u88C5\uFF0CApifyKit \u7684 Actor \u76F8\u5173\u529F\u80FD\u4E0D\u53EF\u7528')\n }\n\n const { Actor } = apify;\n\n return {\n /**\n * \u5305\u88C5 Step Name\n */\n wrapStepNameWithFailedKey(key, stepName) {\n return `${key}${FAILED_KEY_SEPARATOR}${stepName}`;\n },\n\n /**\n * \u89E3\u5305 Step Name\n */\n unwrapStepName(stepName) {\n const splitIndex = stepName.indexOf(FAILED_KEY_SEPARATOR);\n if (splitIndex === -1) {\n return ['-', stepName];\n }\n const key = stepName.substring(0, splitIndex);\n const value = stepName.substring(splitIndex + FAILED_KEY_SEPARATOR.length);\n return [key, value];\n },\n\n /**\n * \u6838\u5FC3\u5C01\u88C5\uFF1A\u6267\u884C\u6B65\u9AA4\uFF0C\u5E26\u81EA\u52A8\u65E5\u5FD7\u786E\u8BA4\u548C\u5931\u8D25\u622A\u56FE\u5904\u7406\n */\n async runStep(pendingStepName, page, actionFn, options = {}) {\n const { failActor = true } = options; // \u9ED8\u8BA4\u8C03\u7528 Actor.fail\n const [failedKey, stepName] = this.unwrapStepName(pendingStepName);\n\n log.info(`\uD83D\uDD04 [\u6B63\u5728\u6267\u884C] ${stepName}...`);\n\n try {\n const result = await actionFn();\n log.info(`\u2705 [\u6267\u884C\u6210\u529F] ${stepName}`);\n return result;\n } catch (error) {\n log.error(`\u274C [\u6267\u884C\u5931\u8D25] ${stepName}: ${error.message}`);\n\n let screenshotBase64 = '\u622A\u56FE\u5931\u8D25';\n try {\n if (page) {\n const buffer = await page.screenshot({ fullPage: true, type: 'jpeg', quality: 60 });\n screenshotBase64 = `data:image/jpeg;base64,${buffer.toString('base64')}`;\n }\n } catch (snapErr) {\n log.warning(`\u622A\u56FE\u751F\u6210\u5931\u8D25: ${snapErr.message}`);\n }\n\n // \u4F7F\u7528 pushFailed \u65B9\u6CD5\u63A8\u9001\u5931\u8D25\u6570\u636E\uFF08\u79C1\u6709\u4F7F\u7528\uFF09\n await this.pushFailed(error, {\n failedStep: stepName,\n failedKey: failedKey,\n errorMessage: error.message,\n errorStack: error.stack,\n screenshotBase64: screenshotBase64\n });\n\n // \u6839\u636E failActor \u51B3\u5B9A\u662F\u5426\u8C03\u7528 Actor.fail\n if (failActor) {\n await Actor.fail(`Run Step ${stepName} \u5931\u8D25: ${error.message}`);\n } else {\n // \u4E0D\u8C03\u7528 Actor.fail\uFF0C\u76F4\u63A5\u629B\u51FA\u9519\u8BEF\n throw error;\n }\n }\n },\n\n /**\n * \u5BBD\u677E\u7248runStep\uFF1A\u5931\u8D25\u65F6\u4E0D\u8C03\u7528Actor.fail\uFF0C\u53EA\u629B\u51FA\u5F02\u5E38\n */\n async runStepLoose(stepName, page, fn) {\n return await this.runStep(stepName, page, fn, { failActor: false });\n },\n\n /**\n * \u63A8\u9001\u6210\u529F\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\n * @param {Object} data - \u8981\u63A8\u9001\u7684\u6570\u636E\u5BF9\u8C61\n */\n async pushSuccess(data) {\n await Actor.pushData({\n code: StatusCode.Success,\n status: Status.Success,\n timestamp: new Date().toISOString(),\n ...data\n });\n },\n\n /**\n * \u63A8\u9001\u5931\u8D25\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\uFF08\u79C1\u6709\u65B9\u6CD5\uFF0C\u4EC5\u4F9BrunStep\u5185\u90E8\u4F7F\u7528\uFF09\n * @param {Error|Object} error - \u9519\u8BEF\u5BF9\u8C61\uFF08\u53EF\u5305\u542B\u5176\u4ED6\u7684\u9519\u8BEF/\u6216\u90E8\u5206\u5904\u7406\u6210\u529F\u7684\u989D\u5916\u4FE1\u606F\uFF09\n * @param {Object} [meta] - \u989D\u5916\u7684\u6570\u636E\uFF08\u5982failedStep, screenshotBase64\u7B49\uFF0C\u4EC5runStep\u4F7F\u7528\uFF09\n * @private\n */\n async pushFailed(error, meta = {}) {\n await Actor.pushData({\n code: StatusCode.Failed,\n status: Status.Failed,\n // \u8FD9\u91CC\u53EF\u80FD\u5E26\u5176\u4ED6\u9519\u8BEF\u4FE1\u606F\n error,\n timestamp: new Date().toISOString(),\n ...meta\n });\n }\n };\n}\n\n// \u61D2\u52A0\u8F7D\u5355\u4F8B\nlet instance = null;\n\n/**\n * \u83B7\u53D6 ApifyKit \u5B9E\u4F8B\uFF08\u61D2\u52A0\u8F7D\uFF09\n * @returns {Promise<Object>} ApifyKit \u5B9E\u4F8B\n */\nasync function useApifyKit() {\n if (!instance) {\n instance = await createApifyKit();\n }\n return instance;\n}\n\n// \u4E5F\u5BFC\u51FA\u521D\u59CB\u5316\u51FD\u6570\uFF0C\u4F9B\u9700\u8981\u7684\u7528\u6237\u4F7F\u7528\nexport const ApifyKit = {\n useApifyKit\n};\n", "export const ErrorKeygen = {\n NotLogin: 30000001,\n Chaptcha: 30000002,\n}\n\nexport const Status = {\n Success: 'SUCCESS',\n Failed: 'FAILED'\n}\n\nexport const StatusCode = {\n Success: 0,\n Failed: -1\n}\n\nexport const FAILED_KEY_SEPARATOR = '::<@>::';\n\nexport const PresetOfLiveViewKey = 'LIVE_VIEW_SCREENSHOT';\n", "export const Utils = {\n /**\n * \u89E3\u6790 SSE \u6D41\u6587\u672C\n */\n parseSseStream(sseStreamText) {\n const events = [];\n const lines = sseStreamText.split('\\n');\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const jsonContent = line.substring(6).trim();\n if (jsonContent && jsonContent !== '[DONE]') {\n events.push(JSON.parse(jsonContent));\n }\n } catch (e) {\n // Ignore lines that are not valid JSON\n }\n }\n }\n return events;\n }\n}\n", "import { log } from 'crawlee';\n\nexport const Stealth = {\n /**\n * \u5173\u952E\u4FEE\u590D\uFF1A\u5C06 Page \u89C6\u53E3\u8C03\u6574\u4E3A\u4E0E\u6D4F\u89C8\u5668\u6307\u7EB9 (window.screen) \u4E00\u81F4\u3002\n * \u9632\u6B62 \"Viewport Mismatch\" \u7C7B\u578B\u7684\u53CD\u722C\u68C0\u6D4B\u3002\n * @param {import('playwright').Page} page \n */\n async syncViewportWithScreen(page) {\n try {\n // \u83B7\u53D6\u6307\u7EB9\u4E2D\u7684\u5C4F\u5E55\u5C3A\u5BF8\n const screen = await page.evaluate(() => ({\n width: window.screen.width,\n height: window.screen.height,\n availWidth: window.screen.availWidth,\n availHeight: window.screen.availHeight,\n }));\n\n // \u8C03\u6574\u89C6\u53E3\n await page.setViewportSize({\n width: screen.width,\n height: screen.height\n });\n\n log.info(`[Stealth] Viewport synced to fingerprint: ${screen.width}x${screen.height}`);\n } catch (e) {\n log.warning(`[Stealth] Failed to sync viewport: ${e.message}. Fallback to 1920x1080.`);\n await page.setViewportSize({ width: 1920, height: 1080 });\n }\n },\n\n /**\n * \u786E\u4FDD navigator.webdriver \u9690\u85CF (\u901A\u5E38 Playwright Stealth \u63D2\u4EF6\u5DF2\u5904\u7406\uFF0C\u4F46\u53CC\u91CD\u4FDD\u9669)\n */\n async hideWebdriver(page) {\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', {\n get: () => false,\n });\n });\n },\n\n /**\n * \u901A\u7528\u7684 Playwright \u8D44\u6E90\u62E6\u622A\u5668\uFF0C\u7528\u4E8E\u5C4F\u853D\u4E0D\u5FC5\u8981\u7684\u8D44\u6E90\u4EE5\u52A0\u901F\u52A0\u8F7D\n * @param {import('playwright').Page} page\n * @param {string[]} [resourceTypes] - \u8981\u5C4F\u853D\u7684\u8D44\u6E90\u7C7B\u578B\uFF0C\u9ED8\u8BA4\u4E3A ['font', 'image', 'media']\n */\n async setupBlockingResources(page, resourceTypes = ['font', 'image', 'media']) {\n await page.route('**/*', (route) => {\n const request = route.request();\n const type = request.resourceType();\n if (resourceTypes.includes(type)) {\n return route.abort();\n }\n return route.continue();\n });\n },\n\n /**\n * \u83B7\u53D6\u63A8\u8350\u7684 Stealth \u542F\u52A8\u53C2\u6570\n */\n getStealthLaunchArgs() {\n return [\n '--disable-blink-features=AutomationControlled',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-infobars',\n '--window-position=0,0',\n '--ignore-certificate-errors',\n '--disable-web-security',\n // \u6CE8\u610F\uFF1A\u4E0D\u5EFA\u8BAE\u8FD9\u91CC\u5F3A\u5236\u6307\u5B9A window-size\uFF0C\u8BA9 syncViewportWithScreen \u53BB\u52A8\u6001\u8C03\u6574\n // '--window-size=1920,1080' \n ];\n },\n\n /**\n * \u83B7\u53D6\u589E\u5F3A\u7248 Stealth \u542F\u52A8\u53C2\u6570 (\u63A8\u8350\u7528\u4E8E\u9AD8\u98CE\u9669\u53CD\u722C\u573A\u666F)\n * \u5305\u542B\u66F4\u591A\u9488\u5BF9\u81EA\u52A8\u5316\u68C0\u6D4B\u7684\u9632\u62A4\n */\n getAdvancedStealthArgs() {\n return [\n ...this.getStealthLaunchArgs(),\n // \u7981\u7528\u5404\u79CD\u53EF\u80FD\u66B4\u9732\u81EA\u52A8\u5316\u7684\u7279\u5F81\n '--disable-dev-shm-usage',\n '--disable-accelerated-2d-canvas',\n '--disable-gpu-sandbox',\n '--disable-background-networking',\n '--disable-default-apps',\n '--disable-extensions',\n '--disable-sync',\n '--disable-translate',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-first-run',\n // \u6A21\u62DF\u771F\u5B9E\u7528\u6237\u914D\u7F6E\n '--lang=zh-CN,zh',\n ];\n }\n}\n", "import delay, { rangeDelay } from 'delay';\nimport { log } from 'crawlee';\n\nexport const Humanize = {\n /**\n * \u968F\u673A\u5EF6\u8FDF\u4E00\u6BB5\u6BEB\u79D2\u6570 (API Wrapper for 'delay' package)\n * @param {number} min - \u6700\u5C0F\u6BEB\u79D2\n * @param {number} max - \u6700\u5927\u6BEB\u79D2\n */\n async randomSleep(min, max) {\n const ms = typeof max === 'number'\n ? rangeDelay(min, max)\n : delay(min); // \u5982\u679C\u53EA\u4F20\u4E00\u4E2A\u53C2\u6570\uFF0C\u89C6\u4E3A\u56FA\u5B9A\u5EF6\u8FDF\u6216\u6700\u5C0F\u5EF6\u8FDF\n\n // log.debug(`[Humanize] Sleeping for ${await ms} ms...`); // delay return promise acts like number somewhat but best await it\n // The delay package returns a promise that resolves after the delay.\n // delay.range() returns a promise too.\n\n await ms;\n },\n\n /**\n * \u6A21\u62DF\u4EBA\u7C7B\u201C\u6CE8\u89C6\u201D\u6216\u201C\u9605\u8BFB\u201D\u884C\u4E3A\uFF1A\u9F20\u6807\u5728\u9875\u9762\u4E0A\u968F\u673A\u5FAE\u52A8\u3002\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor \n * @param {number} durationMs - \u6301\u7EED\u65F6\u95F4\n */\n async simulateGaze(cursor, durationMs = 2000) {\n const startTime = Date.now();\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u5C0F\u5E45\u5EA6\u79FB\u52A8\n const x = Math.random() * 800;\n const y = Math.random() * 600;\n await cursor.moveTo({ x, y });\n await rangeDelay(200, 800);\n }\n },\n\n /**\n * \u4EBA\u7C7B\u5316\u8F93\u5165 - \u5E26\u8282\u594F\u53D8\u5316\uFF08\u5FEB-\u6162-\u505C\u987F-\u5076\u5C14\u52A0\u901F\uFF09\n * @param {import('playwright').Page} page\n * @param {string} selector - \u8F93\u5165\u6846\u9009\u62E9\u5668\n * @param {string} text - \u8981\u8F93\u5165\u7684\u6587\u672C\n * @param {Object} [options]\n * @param {number} [options.minDelay=50] - \u6700\u5C0F\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.maxDelay=200] - \u6700\u5927\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.pauseProbability=0.1] - \u505C\u987F\u6982\u7387 (0-1)\n * @param {number} [options.pauseMin=300] - \u505C\u987F\u6700\u5C0F\u65F6\u957F (ms)\n * @param {number} [options.pauseMax=800] - \u505C\u987F\u6700\u5927\u65F6\u957F (ms)\n */\n async humanType(page, selector, text, options = {}) {\n const {\n minDelay = 50,\n maxDelay = 200,\n pauseProbability = 0.1,\n pauseMin = 300,\n pauseMax = 800\n } = options;\n\n const locator = page.locator(selector);\n await locator.click();\n await rangeDelay(100, 300);\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n\n // \u8BA1\u7B97\u5F53\u524D\u5B57\u7B26\u7684\u5EF6\u8FDF\uFF08\u6A21\u62DF\u6253\u5B57\u8282\u594F\u53D8\u5316\uFF09\n let charDelay;\n if (char === ' ') {\n // \u7A7A\u683C\u901A\u5E38\u6253\u5F97\u5FEB\n charDelay = minDelay + Math.random() * 50;\n } else if (/[,.!?;:]/.test(char)) {\n // \u6807\u70B9\u540E\u901A\u5E38\u6709\u505C\u987F\n charDelay = maxDelay + Math.random() * 100;\n } else {\n // \u666E\u901A\u5B57\u7B26\u968F\u673A\u5EF6\u8FDF\n charDelay = minDelay + Math.random() * (maxDelay - minDelay);\n }\n\n await locator.press(char);\n await delay(charDelay);\n\n // \u968F\u673A\u505C\u987F\uFF08\u6A21\u62DF\u601D\u8003\u6216\u770B\u5C4F\u5E55\uFF09\n if (Math.random() < pauseProbability && i < text.length - 1) {\n const pauseTime = pauseMin + Math.random() * (pauseMax - pauseMin);\n log.debug(`[Humanize] \u505C\u987F ${Math.round(pauseTime)}ms...`);\n await delay(pauseTime);\n }\n }\n },\n\n /**\n * \u9875\u9762\u9884\u70ED\u6D4F\u89C8 - \u6A21\u62DF\u4EBA\u7C7B\u8FDB\u5165\u9875\u9762\u540E\u7684\u63A2\u7D22\u884C\u4E3A\n * @param {import('playwright').Page} page\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor\n * @param {number} [durationMs=3000] - \u9884\u70ED\u65F6\u957F (ms)\n */\n async warmUpBrowsing(page, cursor, durationMs = 3000) {\n log.info(`[Humanize] \u5F00\u59CB\u9875\u9762\u9884\u70ED\u6D4F\u89C8 (${durationMs}ms)...`);\n const startTime = Date.now();\n const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };\n\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u52A8\u4F5C\u9009\u62E9\n const action = Math.random();\n\n if (action < 0.4) {\n // 40% \u6982\u7387\uFF1A\u9F20\u6807\u968F\u673A\u79FB\u52A8\n const x = 100 + Math.random() * (viewportSize.width - 200);\n const y = 100 + Math.random() * (viewportSize.height - 200);\n await cursor.moveTo({ x, y });\n await rangeDelay(200, 500);\n } else if (action < 0.7) {\n // 30% \u6982\u7387\uFF1A\u5C0F\u5E45\u6EDA\u52A8\n const scrollY = (Math.random() - 0.5) * 200; // -100 \u5230 +100\n await page.mouse.wheel(0, scrollY);\n await rangeDelay(300, 700);\n } else {\n // 30% \u6982\u7387\uFF1A\u505C\u987F\u89C2\u770B\n await rangeDelay(500, 1000);\n }\n }\n\n log.info('[Humanize] \u9875\u9762\u9884\u70ED\u5B8C\u6210');\n },\n\n /**\n * \u81EA\u7136\u6EDA\u52A8 - \u5E26\u60EF\u6027\u548C\u51CF\u901F\u6548\u679C\n * @param {import('playwright').Page} page\n * @param {'up' | 'down'} [direction='down'] - \u6EDA\u52A8\u65B9\u5411\n * @param {number} [distance=300] - \u603B\u6EDA\u52A8\u8DDD\u79BB (px)\n * @param {number} [steps=5] - \u5206\u51E0\u6B65\u5B8C\u6210\n */\n async naturalScroll(page, direction = 'down', distance = 300, steps = 5) {\n const sign = direction === 'down' ? 1 : -1;\n const stepDistance = distance / steps;\n\n // \u6A21\u62DF\u51CF\u901F\u6548\u679C\uFF1A\u5F00\u59CB\u5FEB\uFF0C\u7ED3\u675F\u6162\n for (let i = 0; i < steps; i++) {\n // \u6BCF\u6B65\u6EDA\u52A8\u91CF\u9012\u51CF\n const factor = 1 - (i / steps) * 0.5; // 1 -> 0.5 \u9012\u51CF\n const scrollAmount = stepDistance * factor * sign;\n\n await page.mouse.wheel(0, scrollAmount);\n\n // \u5EF6\u8FDF\u4E5F\u9012\u589E\uFF08\u6A21\u62DF\u51CF\u901F\uFF09\n const delayTime = 50 + i * 30;\n await delay(delayTime);\n }\n }\n}\n", "// \u96C6\u4E2D\u7BA1\u7406\u542F\u52A8\u914D\u7F6E\uFF0C\u6682\u65F6\u4E3B\u8981\u7531 Stealth \u6A21\u5757\u63D0\u4F9B Args\uFF0C\u8FD9\u91CC\u4F5C\u4E3A\u6269\u5C55\u70B9\nimport { Stealth } from './stealth.js';\n\nexport const Launch = {\n getLaunchOptions(customArgs = []) {\n return {\n args: [\n ...Stealth.getStealthLaunchArgs(),\n ...customArgs\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n };\n },\n\n /**\n * \u63A8\u8350\u7684 Fingerprint Generator \u9009\u9879\n * \u786E\u4FDD\u751F\u6210\u7684\u662F\u684C\u9762\u7AEF\u3001\u8F83\u65B0\u7684 Chrome\uFF0C\u4EE5\u5339\u914D\u6211\u4EEC\u7684\u811A\u672C\u903B\u8F91\n */\n getFingerprintGeneratorOptions() {\n return {\n browsers: [{ name: 'chrome', minVersion: 110 }],\n devices: ['desktop'],\n operatingSystems: ['windows', 'linux'], // \u5305\u542B Linux \u517C\u5BB9\u5BB9\u5668\n };\n }\n}\n", "import express from 'express';\nimport { log } from 'crawlee';\nimport { Actor } from 'apify';\nimport { PresetOfLiveViewKey } from './constants';\n\n/**\n * \u542F\u52A8\u4E00\u4E2A Web \u670D\u52A1\u5668\u4EE5\u5728 Live View \u9009\u9879\u5361\u4E2D\u663E\u793A\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\u3002\n */\nasync function startLiveViewServer(liveViewKey) {\n const app = express();\n\n app.get('/', async (req, res) => {\n try {\n // \u4ECE\u9ED8\u8BA4\u7684 Key-Value Store \u4E2D\u8BFB\u53D6\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\n const screenshotBuffer = await Actor.getValue(liveViewKey);\n\n if (!screenshotBuffer) {\n // \u5982\u679C\u8FD8\u6CA1\u6709\u622A\u56FE\uFF0C\u53D1\u9001\u4E00\u4E2A\u81EA\u52A8\u5237\u65B0\u7684\u5360\u4F4D\u9875\u9762\n res.send('<html><head><meta http-equiv=\"refresh\" content=\"2\"></head><body>\u7B49\u5F85\u7B2C\u4E00\u4E2A\u5C4F\u5E55\u622A\u56FE...</body></html>');\n return;\n }\n\n // \u5C06 Buffer \u8F6C\u6362\u4E3A Base64 \u5B57\u7B26\u4E32\n const screenshotBase64 = screenshotBuffer.toString('base64');\n\n // \u53D1\u9001\u4E00\u4E2A HTML \u9875\u9762\uFF0C\u8BE5\u9875\u9762\u6BCF 1 \u79D2\u81EA\u52A8\u5237\u65B0\u4E00\u6B21\uFF0C\u5E76\u663E\u793A\u622A\u56FE\n res.send(`\n <html>\n <head>\n <title>Live View (\u622A\u56FE)</title>\n <meta http-equiv=\"refresh\" content=\"1\">\n </head>\n <body style=\"margin:0; padding:0;\">\n <img src=\"data:image/png;base64,${screenshotBase64}\" \n alt=\"Live View Screenshot\" \n style=\"width: 100%; height: auto;\" />\n </body>\n </html>\n `);\n } catch (error) {\n log.error(`Live View \u670D\u52A1\u5668\u9519\u8BEF: ${error.message}`);\n res.status(500).send(`\u65E0\u6CD5\u52A0\u8F7D\u5C4F\u5E55\u622A\u56FE: ${error.message}`);\n }\n });\n\n // \u76D1\u542C Apify \u5BB9\u5668\u7AEF\u53E3 \n const port = process.env.APIFY_CONTAINER_PORT || 4321;\n app.listen(port, () => { log.info(`Live View \u670D\u52A1\u5668\u5DF2\u542F\u52A8\uFF0C\u76D1\u542C\u7AEF\u53E3 ${port}\u3002\u8BF7\u6253\u5F00 \"Live View\" \u9009\u9879\u5361\u67E5\u770B\u3002`); });\n}\n\n/**\n * \u62CD\u6444\u5F53\u524D\u9875\u9762\u7684\u5C4F\u5E55\u622A\u56FE\u5E76\u5C06\u5176\u4FDD\u5B58\u5230 Key-Value Store\u3002\n * @param {import('playwright').Page} page\n * @param {string} [logMessage] - \u53EF\u9009\u7684\u65E5\u5FD7\u6D88\u606F\u3002\n */\nasync function takeLiveScreenshot(liveViewKey, page, logMessage) {\n try {\n const buffer = await page.screenshot({ type: 'png' });\n await Actor.setValue(liveViewKey, buffer, { contentType: 'image/png' });\n if (logMessage) {\n log.info(`(\u622A\u56FE): ${logMessage}`);\n }\n } catch (e) {\n log.warning(`\u65E0\u6CD5\u6355\u83B7 Live View \u5C4F\u5E55\u622A\u56FE: ${e.message}`);\n }\n}\n\nconst useLiveView = (liveViewKey = PresetOfLiveViewKey) => {\n return {\n takeLiveScreenshot: async (page, logMessage) => {\n return await takeLiveScreenshot(liveViewKey, page, logMessage)\n },\n startLiveViewServer: async () => {\n return await startLiveViewServer(liveViewKey);\n }\n }\n}\n\nexport const LiveView = {\n useLiveView,\n};\n", "import { log } from 'crawlee';\n\n/**\n * \u521B\u5EFA\u9A8C\u8BC1\u7801\u76D1\u63A7\u5668 - \u652F\u6301 DOM \u9009\u62E9\u5668 \u548C URL \u6A21\u5F0F \u4E24\u79CD\u68C0\u6D4B\u65B9\u5F0F\n * \n * \u6CE8\u610F\uFF1A\u76D1\u63A7\u5668\u968F\u9875\u9762\u751F\u547D\u5468\u671F\u81EA\u52A8\u6E05\u7406\uFF0C\u65E0\u9700\u624B\u52A8 cleanup\n * \n * @param {import('playwright').Page} page\n * @param {Object} options\n * @param {string} [options.domSelector] - DOM \u5143\u7D20\u9009\u62E9\u5668 (\u5982 '#captcha_container')\n * @param {string} [options.urlPattern] - URL \u5339\u914D\u6A21\u5F0F (\u5982 '/captcha')\n * @param {Function} options.onDetected - \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\u65F6\u7684\u56DE\u8C03 (async function)\n */\nexport function useCaptchaMonitor(page, options) {\n const { domSelector, urlPattern, onDetected } = options;\n\n if (!domSelector && !urlPattern) {\n throw new Error('[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector \u6216 urlPattern \u81F3\u5C11\u4E00\u4E2A');\n }\n\n if (!onDetected || typeof onDetected !== 'function') {\n throw new Error('[CaptchaMonitor] onDetected \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570');\n }\n\n let isHandled = false;\n let frameHandler = null;\n let exposedFunctionName = null;\n\n const triggerDetected = async () => {\n if (isHandled) return;\n isHandled = true;\n log.error('[CaptchaMonitor] \uD83D\uDED1 \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\uFF01');\n await onDetected();\n };\n\n // ============================================================\n // \u6A21\u5F0F1: DOM \u76D1\u63A7 (\u4F7F\u7528 MutationObserver)\n // ============================================================\n if (domSelector) {\n // \u751F\u6210\u552F\u4E00\u7684\u51FD\u6570\u540D\u907F\u514D\u51B2\u7A81\n exposedFunctionName = `__c_d_${Date.now()}`;\n\n // \u66B4\u9732\u56DE\u8C03\u51FD\u6570\u7ED9\u9875\u9762\n page.exposeFunction(exposedFunctionName, triggerDetected).catch(() => {\n // \u5FFD\u7565\u91CD\u590D\u66B4\u9732\u9519\u8BEF\n });\n\n // \u6CE8\u5165 MutationObserver \u76D1\u542C\u811A\u672C\n page.addInitScript(({ selector, callbackName }) => {\n (() => {\n let observer = null;\n\n const checkAndReport = () => {\n const element = document.querySelector(selector);\n if (element) {\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n if (window[callbackName]) {\n window[callbackName]();\n }\n return true;\n }\n return false;\n };\n\n // 1. \u7ACB\u5373\u68C0\u67E5\u4E00\u6B21\n if (checkAndReport()) return;\n\n // 2. \u542F\u52A8 MutationObserver\n observer = new MutationObserver((mutations) => {\n let shouldCheck = false;\n for (const mutation of mutations) {\n if (mutation.addedNodes.length > 0) {\n shouldCheck = true;\n break;\n }\n }\n if (shouldCheck && observer) {\n checkAndReport();\n }\n });\n\n // 3. \u6302\u8F7D\u76D1\u542C\uFF08\u786E\u4FDD DOM \u51C6\u5907\u5C31\u7EEA\uFF09\n const mountObserver = () => {\n const target = document.documentElement;\n if (target && observer) {\n observer.observe(target, { childList: true, subtree: true });\n }\n };\n\n if (document.readyState === 'loading') {\n window.addEventListener('DOMContentLoaded', mountObserver);\n } else {\n mountObserver();\n }\n })();\n }, { selector: domSelector, callbackName: exposedFunctionName });\n\n log.info(`[CaptchaMonitor] DOM \u76D1\u63A7\u5DF2\u542F\u7528: ${domSelector}`);\n }\n\n // ============================================================\n // \u6A21\u5F0F2: URL \u76D1\u63A7 (\u76D1\u542C framenavigated)\n // ============================================================\n if (urlPattern) {\n frameHandler = async (frame) => {\n if (frame === page.mainFrame()) {\n const currentUrl = page.url();\n if (currentUrl.includes(urlPattern)) {\n await triggerDetected();\n }\n }\n };\n\n page.on('framenavigated', frameHandler);\n log.info(`[CaptchaMonitor] URL \u76D1\u63A7\u5DF2\u542F\u7528: ${urlPattern}`);\n }\n\n // \u6CE8\u610F\uFF1A\u4E0D\u63D0\u4F9B cleanup \u51FD\u6570\n // - DOM \u6A21\u5F0F\uFF1AaddInitScript \u6CE8\u5165\u7684\u4EE3\u7801\u65E0\u6CD5\u4ECE Node \u7AEF\u6E05\u7406\n // - URL \u6A21\u5F0F\uFF1Aframenavigated \u76D1\u542C\u901A\u5E38\u8DDF\u968F\u9875\u9762\u751F\u547D\u5468\u671F\uFF0C\u65E0\u9700\u624B\u52A8\u6E05\u7406\n // \u5982\u679C\u9700\u8981\u63D0\u524D\u7EC8\u6B62\u76D1\u63A7\uFF0C\u8BBE\u8BA1\u4E0A\u5E94\u8BE5\u8BA9 onDetected \u5904\u7406\u540E\u7EED\u903B\u8F91\uFF08\u5982 Actor.fail\uFF09\n}\n\n// \u6309\u7167 toolkit \u7EDF\u4E00\u7684\u5BFC\u51FA\u6A21\u5F0F\nexport const Captcha = {\n useCaptchaMonitor\n};\n", "import { ApifyKit } from './src/apify-kit.js';\nimport { Utils } from './src/utils.js';\nimport { Stealth } from './src/stealth.js';\nimport { Humanize } from './src/humanize.js';\nimport { Launch } from './src/launch.js';\nimport { LiveView } from './src/live-view.js';\nimport { Captcha } from './src/captcha-monitor.js';\nimport * as Constants from './src/constants.js';\n\n// Unified Entry Point\nexport const usePlaywrightToolKit = () => {\n return {\n ApifyKit,\n Stealth,\n Humanize,\n Launch,\n LiveView,\n Constants,\n Utils,\n Captcha\n };\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { log } from 'crawlee';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants';\n\n/**\n * \u521B\u5EFA ApifyKit \u5B9E\u4F8B\n * \u5982\u679C apify \u53EF\u7528\uFF0C\u8FD4\u56DE\u5B8C\u6574\u529F\u80FD\u7684 ApifyKit\n * \u5982\u679C apify \u4E0D\u53EF\u7528\uFF0C\u8FD4\u56DE\u964D\u7EA7\u7248\u672C\uFF08\u975E apify \u76F8\u5173\u529F\u80FD\u4ECD\u53EF\u7528\uFF09\n */\nasync function createApifyKit() {\n let apify = null;\n\n // \u5C1D\u8BD5\u52A0\u8F7D apify\n try {\n apify = await import('apify');\n } catch (error) {\n // apify \u4E0D\u53EF\u7528\uFF0C\u5C06\u4F7F\u7528\u964D\u7EA7\u7248\u672C\n throw new Error('\u26A0\uFE0F apify \u5E93\u672A\u5B89\u88C5\uFF0CApifyKit \u7684 Actor \u76F8\u5173\u529F\u80FD\u4E0D\u53EF\u7528')\n }\n\n const { Actor } = apify;\n\n return {\n /**\n * \u5305\u88C5 Step Name\n */\n wrapStepNameWithFailedKey(key, stepName) {\n return `${key}${FAILED_KEY_SEPARATOR}${stepName}`;\n },\n\n /**\n * \u89E3\u5305 Step Name\n */\n unwrapStepName(stepName) {\n const splitIndex = stepName.indexOf(FAILED_KEY_SEPARATOR);\n if (splitIndex === -1) {\n return ['-', stepName];\n }\n const key = stepName.substring(0, splitIndex);\n const value = stepName.substring(splitIndex + FAILED_KEY_SEPARATOR.length);\n return [key, value];\n },\n\n /**\n * \u6838\u5FC3\u5C01\u88C5\uFF1A\u6267\u884C\u6B65\u9AA4\uFF0C\u5E26\u81EA\u52A8\u65E5\u5FD7\u786E\u8BA4\u548C\u5931\u8D25\u622A\u56FE\u5904\u7406\n */\n async runStep(pendingStepName, page, actionFn, options = {}) {\n const { failActor = true } = options; // \u9ED8\u8BA4\u8C03\u7528 Actor.fail\n const [failedKey, stepName] = this.unwrapStepName(pendingStepName);\n\n log.info(`\uD83D\uDD04 [\u6B63\u5728\u6267\u884C] ${stepName}...`);\n\n try {\n const result = await actionFn();\n log.info(`\u2705 [\u6267\u884C\u6210\u529F] ${stepName}`);\n return result;\n } catch (error) {\n log.error(`\u274C [\u6267\u884C\u5931\u8D25] ${stepName}: ${error.message}`);\n\n let screenshotBase64 = '\u622A\u56FE\u5931\u8D25';\n try {\n if (page) {\n const buffer = await page.screenshot({ fullPage: true, type: 'jpeg', quality: 60 });\n screenshotBase64 = `data:image/jpeg;base64,${buffer.toString('base64')}`;\n }\n } catch (snapErr) {\n log.warning(`\u622A\u56FE\u751F\u6210\u5931\u8D25: ${snapErr.message}`);\n }\n\n // \u4F7F\u7528 pushFailed \u65B9\u6CD5\u63A8\u9001\u5931\u8D25\u6570\u636E\uFF08\u79C1\u6709\u4F7F\u7528\uFF09\n await this.pushFailed(error, {\n failedStep: stepName,\n failedKey: failedKey,\n errorMessage: error.message,\n errorStack: error.stack,\n screenshotBase64: screenshotBase64\n });\n\n // \u6839\u636E failActor \u51B3\u5B9A\u662F\u5426\u8C03\u7528 Actor.fail\n if (failActor) {\n await Actor.fail(`Run Step ${stepName} \u5931\u8D25: ${error.message}`);\n } else {\n // \u4E0D\u8C03\u7528 Actor.fail\uFF0C\u76F4\u63A5\u629B\u51FA\u9519\u8BEF\n throw error;\n }\n }\n },\n\n /**\n * \u5BBD\u677E\u7248runStep\uFF1A\u5931\u8D25\u65F6\u4E0D\u8C03\u7528Actor.fail\uFF0C\u53EA\u629B\u51FA\u5F02\u5E38\n */\n async runStepLoose(stepName, page, fn) {\n return await this.runStep(stepName, page, fn, { failActor: false });\n },\n\n /**\n * \u63A8\u9001\u6210\u529F\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\n * @param {Object} data - \u8981\u63A8\u9001\u7684\u6570\u636E\u5BF9\u8C61\n */\n async pushSuccess(data) {\n await Actor.pushData({\n code: StatusCode.Success,\n status: Status.Success,\n timestamp: new Date().toISOString(),\n ...data\n });\n },\n\n /**\n * \u63A8\u9001\u5931\u8D25\u6570\u636E\u7684\u901A\u7528\u65B9\u6CD5\uFF08\u79C1\u6709\u65B9\u6CD5\uFF0C\u4EC5\u4F9BrunStep\u5185\u90E8\u4F7F\u7528\uFF09\n * @param {Error|Object} error - \u9519\u8BEF\u5BF9\u8C61\uFF08\u53EF\u5305\u542B\u5176\u4ED6\u7684\u9519\u8BEF/\u6216\u90E8\u5206\u5904\u7406\u6210\u529F\u7684\u989D\u5916\u4FE1\u606F\uFF09\n * @param {Object} [meta] - \u989D\u5916\u7684\u6570\u636E\uFF08\u5982failedStep, screenshotBase64\u7B49\uFF0C\u4EC5runStep\u4F7F\u7528\uFF09\n * @private\n */\n async pushFailed(error, meta = {}) {\n await Actor.pushData({\n code: StatusCode.Failed,\n status: Status.Failed,\n // \u8FD9\u91CC\u53EF\u80FD\u5E26\u5176\u4ED6\u9519\u8BEF\u4FE1\u606F\n error,\n timestamp: new Date().toISOString(),\n ...meta\n });\n }\n };\n}\n\n// \u61D2\u52A0\u8F7D\u5355\u4F8B\nlet instance = null;\n\n/**\n * \u83B7\u53D6 ApifyKit \u5B9E\u4F8B\uFF08\u61D2\u52A0\u8F7D\uFF09\n * @returns {Promise<Object>} ApifyKit \u5B9E\u4F8B\n */\nasync function useApifyKit() {\n if (!instance) {\n instance = await createApifyKit();\n }\n return instance;\n}\n\n// \u4E5F\u5BFC\u51FA\u521D\u59CB\u5316\u51FD\u6570\uFF0C\u4F9B\u9700\u8981\u7684\u7528\u6237\u4F7F\u7528\nexport const ApifyKit = {\n useApifyKit\n};\n", "export const ErrorKeygen = {\n NotLogin: 30000001,\n Chaptcha: 30000002,\n}\n\nexport const Status = {\n Success: 'SUCCESS',\n Failed: 'FAILED'\n}\n\nexport const StatusCode = {\n Success: 0,\n Failed: -1\n}\n\nexport const FAILED_KEY_SEPARATOR = '::<@>::';\n\nexport const PresetOfLiveViewKey = 'LIVE_VIEW_SCREENSHOT';\n", "export const Utils = {\n /**\n * \u89E3\u6790 SSE \u6D41\u6587\u672C\n */\n parseSseStream(sseStreamText) {\n const events = [];\n const lines = sseStreamText.split('\\n');\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const jsonContent = line.substring(6).trim();\n if (jsonContent && jsonContent !== '[DONE]') {\n events.push(JSON.parse(jsonContent));\n }\n } catch (e) {\n // Ignore lines that are not valid JSON\n }\n }\n }\n return events;\n }\n}\n", "import { log } from 'crawlee';\n\nexport const Stealth = {\n /**\n * \u5173\u952E\u4FEE\u590D\uFF1A\u5C06 Page \u89C6\u53E3\u8C03\u6574\u4E3A\u4E0E\u6D4F\u89C8\u5668\u6307\u7EB9 (window.screen) \u4E00\u81F4\u3002\n * \u9632\u6B62 \"Viewport Mismatch\" \u7C7B\u578B\u7684\u53CD\u722C\u68C0\u6D4B\u3002\n * @param {import('playwright').Page} page \n */\n async syncViewportWithScreen(page) {\n try {\n // \u83B7\u53D6\u6307\u7EB9\u4E2D\u7684\u5C4F\u5E55\u5C3A\u5BF8\n const screen = await page.evaluate(() => ({\n width: window.screen.width,\n height: window.screen.height,\n availWidth: window.screen.availWidth,\n availHeight: window.screen.availHeight,\n }));\n\n // \u8C03\u6574\u89C6\u53E3\n await page.setViewportSize({\n width: screen.width,\n height: screen.height\n });\n\n log.info(`[Stealth] Viewport synced to fingerprint: ${screen.width}x${screen.height}`);\n } catch (e) {\n log.warning(`[Stealth] Failed to sync viewport: ${e.message}. Fallback to 1920x1080.`);\n await page.setViewportSize({ width: 1920, height: 1080 });\n }\n },\n\n /**\n * \u786E\u4FDD navigator.webdriver \u9690\u85CF (\u901A\u5E38 Playwright Stealth \u63D2\u4EF6\u5DF2\u5904\u7406\uFF0C\u4F46\u53CC\u91CD\u4FDD\u9669)\n */\n async hideWebdriver(page) {\n await page.addInitScript(() => {\n Object.defineProperty(navigator, 'webdriver', {\n get: () => false,\n });\n });\n },\n\n /**\n * \u901A\u7528\u7684 Playwright \u8D44\u6E90\u62E6\u622A\u5668\uFF0C\u7528\u4E8E\u5C4F\u853D\u4E0D\u5FC5\u8981\u7684\u8D44\u6E90\u4EE5\u52A0\u901F\u52A0\u8F7D\n * @param {import('playwright').Page} page\n * @param {string[]} [resourceTypes] - \u8981\u5C4F\u853D\u7684\u8D44\u6E90\u7C7B\u578B\uFF0C\u9ED8\u8BA4\u4E3A ['font', 'image', 'media']\n */\n async setupBlockingResources(page, resourceTypes = ['font', 'image', 'media']) {\n await page.route('**/*', (route) => {\n const request = route.request();\n const type = request.resourceType();\n if (resourceTypes.includes(type)) {\n return route.abort();\n }\n return route.continue();\n });\n },\n\n /**\n * \u83B7\u53D6\u63A8\u8350\u7684 Stealth \u542F\u52A8\u53C2\u6570\n */\n getStealthLaunchArgs() {\n return [\n '--disable-blink-features=AutomationControlled',\n '--no-sandbox',\n '--disable-setuid-sandbox',\n '--disable-infobars',\n '--window-position=0,0',\n '--ignore-certificate-errors',\n '--disable-web-security',\n // \u6CE8\u610F\uFF1A\u4E0D\u5EFA\u8BAE\u8FD9\u91CC\u5F3A\u5236\u6307\u5B9A window-size\uFF0C\u8BA9 syncViewportWithScreen \u53BB\u52A8\u6001\u8C03\u6574\n // '--window-size=1920,1080' \n ];\n },\n\n /**\n * \u83B7\u53D6\u589E\u5F3A\u7248 Stealth \u542F\u52A8\u53C2\u6570 (\u63A8\u8350\u7528\u4E8E\u9AD8\u98CE\u9669\u53CD\u722C\u573A\u666F)\n * \u5305\u542B\u66F4\u591A\u9488\u5BF9\u81EA\u52A8\u5316\u68C0\u6D4B\u7684\u9632\u62A4\n */\n getAdvancedStealthArgs() {\n return [\n ...this.getStealthLaunchArgs(),\n // \u7981\u7528\u5404\u79CD\u53EF\u80FD\u66B4\u9732\u81EA\u52A8\u5316\u7684\u7279\u5F81\n '--disable-dev-shm-usage',\n '--disable-accelerated-2d-canvas',\n '--disable-gpu-sandbox',\n '--disable-background-networking',\n '--disable-default-apps',\n '--disable-extensions',\n '--disable-sync',\n '--disable-translate',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-first-run',\n // \u6A21\u62DF\u771F\u5B9E\u7528\u6237\u914D\u7F6E\n '--lang=zh-CN,zh',\n ];\n }\n}\n", "import delay, { rangeDelay } from 'delay';\nimport { log } from 'crawlee';\n\nexport const Humanize = {\n /**\n * \u968F\u673A\u5EF6\u8FDF\u4E00\u6BB5\u6BEB\u79D2\u6570 (API Wrapper for 'delay' package)\n * @param {number} min - \u6700\u5C0F\u6BEB\u79D2\n * @param {number} max - \u6700\u5927\u6BEB\u79D2\n */\n async randomSleep(min, max) {\n const ms = typeof max === 'number'\n ? rangeDelay(min, max)\n : delay(min); // \u5982\u679C\u53EA\u4F20\u4E00\u4E2A\u53C2\u6570\uFF0C\u89C6\u4E3A\u56FA\u5B9A\u5EF6\u8FDF\u6216\u6700\u5C0F\u5EF6\u8FDF\n\n // log.debug(`[Humanize] Sleeping for ${await ms} ms...`); // delay return promise acts like number somewhat but best await it\n // The delay package returns a promise that resolves after the delay.\n // delay.range() returns a promise too.\n\n await ms;\n },\n\n /**\n * \u6A21\u62DF\u4EBA\u7C7B\u201C\u6CE8\u89C6\u201D\u6216\u201C\u9605\u8BFB\u201D\u884C\u4E3A\uFF1A\u9F20\u6807\u5728\u9875\u9762\u4E0A\u968F\u673A\u5FAE\u52A8\u3002\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor \n * @param {number} durationMs - \u6301\u7EED\u65F6\u95F4\n */\n async simulateGaze(cursor, durationMs = 2000) {\n const startTime = Date.now();\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u5C0F\u5E45\u5EA6\u79FB\u52A8\n const x = Math.random() * 800;\n const y = Math.random() * 600;\n await cursor.actions.move({ x, y });\n await rangeDelay(200, 800);\n }\n },\n\n /**\n * \u4EBA\u7C7B\u5316\u8F93\u5165 - \u5E26\u8282\u594F\u53D8\u5316\uFF08\u5FEB-\u6162-\u505C\u987F-\u5076\u5C14\u52A0\u901F\uFF09\n * @param {import('playwright').Page} page\n * @param {string} selector - \u8F93\u5165\u6846\u9009\u62E9\u5668\n * @param {string} text - \u8981\u8F93\u5165\u7684\u6587\u672C\n * @param {Object} [options]\n * @param {number} [options.minDelay=50] - \u6700\u5C0F\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.maxDelay=200] - \u6700\u5927\u6309\u952E\u5EF6\u8FDF (ms)\n * @param {number} [options.pauseProbability=0.1] - \u505C\u987F\u6982\u7387 (0-1)\n * @param {number} [options.pauseMin=300] - \u505C\u987F\u6700\u5C0F\u65F6\u957F (ms)\n * @param {number} [options.pauseMax=800] - \u505C\u987F\u6700\u5927\u65F6\u957F (ms)\n */\n async humanType(page, selector, text, options = {}) {\n const {\n minDelay = 50,\n maxDelay = 200,\n pauseProbability = 0.1,\n pauseMin = 300,\n pauseMax = 800\n } = options;\n\n const locator = page.locator(selector);\n await locator.click();\n await rangeDelay(100, 300);\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n\n // \u8BA1\u7B97\u5F53\u524D\u5B57\u7B26\u7684\u5EF6\u8FDF\uFF08\u6A21\u62DF\u6253\u5B57\u8282\u594F\u53D8\u5316\uFF09\n let charDelay;\n if (char === ' ') {\n // \u7A7A\u683C\u901A\u5E38\u6253\u5F97\u5FEB\n charDelay = minDelay + Math.random() * 50;\n } else if (/[,.!?;:]/.test(char)) {\n // \u6807\u70B9\u540E\u901A\u5E38\u6709\u505C\u987F\n charDelay = maxDelay + Math.random() * 100;\n } else {\n // \u666E\u901A\u5B57\u7B26\u968F\u673A\u5EF6\u8FDF\n charDelay = minDelay + Math.random() * (maxDelay - minDelay);\n }\n\n await locator.press(char);\n await delay(charDelay);\n\n // \u968F\u673A\u505C\u987F\uFF08\u6A21\u62DF\u601D\u8003\u6216\u770B\u5C4F\u5E55\uFF09\n if (Math.random() < pauseProbability && i < text.length - 1) {\n const pauseTime = pauseMin + Math.random() * (pauseMax - pauseMin);\n log.debug(`[Humanize] \u505C\u987F ${Math.round(pauseTime)}ms...`);\n await delay(pauseTime);\n }\n }\n },\n\n /**\n * \u9875\u9762\u9884\u70ED\u6D4F\u89C8 - \u6A21\u62DF\u4EBA\u7C7B\u8FDB\u5165\u9875\u9762\u540E\u7684\u63A2\u7D22\u884C\u4E3A\n * @param {import('playwright').Page} page\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor\n * @param {number} [durationMs=3000] - \u9884\u70ED\u65F6\u957F (ms)\n */\n async warmUpBrowsing(page, cursor, durationMs = 3000) {\n log.info(`[Humanize] \u5F00\u59CB\u9875\u9762\u9884\u70ED\u6D4F\u89C8 (${durationMs}ms)...`);\n const startTime = Date.now();\n const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };\n\n while (Date.now() - startTime < durationMs) {\n // \u968F\u673A\u52A8\u4F5C\u9009\u62E9\n const action = Math.random();\n\n if (action < 0.4) {\n // 40% \u6982\u7387\uFF1A\u9F20\u6807\u968F\u673A\u79FB\u52A8\n const x = 100 + Math.random() * (viewportSize.width - 200);\n const y = 100 + Math.random() * (viewportSize.height - 200);\n await cursor.actions.move({ x, y });\n await rangeDelay(200, 500);\n } else if (action < 0.7) {\n // 30% \u6982\u7387\uFF1A\u5C0F\u5E45\u6EDA\u52A8\n const scrollY = (Math.random() - 0.5) * 200; // -100 \u5230 +100\n await page.mouse.wheel(0, scrollY);\n await rangeDelay(300, 700);\n } else {\n // 30% \u6982\u7387\uFF1A\u505C\u987F\u89C2\u770B\n await rangeDelay(500, 1000);\n }\n }\n\n log.info('[Humanize] \u9875\u9762\u9884\u70ED\u5B8C\u6210');\n },\n\n /**\n * \u81EA\u7136\u6EDA\u52A8 - \u5E26\u60EF\u6027\u548C\u51CF\u901F\u6548\u679C\n * @param {import('playwright').Page} page\n * @param {'up' | 'down'} [direction='down'] - \u6EDA\u52A8\u65B9\u5411\n * @param {number} [distance=300] - \u603B\u6EDA\u52A8\u8DDD\u79BB (px)\n * @param {number} [steps=5] - \u5206\u51E0\u6B65\u5B8C\u6210\n */\n async naturalScroll(page, direction = 'down', distance = 300, steps = 5) {\n const sign = direction === 'down' ? 1 : -1;\n const stepDistance = distance / steps;\n\n // \u6A21\u62DF\u51CF\u901F\u6548\u679C\uFF1A\u5F00\u59CB\u5FEB\uFF0C\u7ED3\u675F\u6162\n for (let i = 0; i < steps; i++) {\n // \u6BCF\u6B65\u6EDA\u52A8\u91CF\u9012\u51CF\n const factor = 1 - (i / steps) * 0.5; // 1 -> 0.5 \u9012\u51CF\n const scrollAmount = stepDistance * factor * sign;\n\n await page.mouse.wheel(0, scrollAmount);\n\n // \u5EF6\u8FDF\u4E5F\u9012\u589E\uFF08\u6A21\u62DF\u51CF\u901F\uFF09\n const delayTime = 50 + i * 30;\n await delay(delayTime);\n }\n },\n\n /**\n * \u4EBA\u7C7B\u5316\u70B9\u51FB - \u4F7F\u7528 ghost-cursor \u6A21\u62DF\u4EBA\u7C7B\u9F20\u6807\u79FB\u52A8\u8F68\u8FF9\u5E76\u70B9\u51FB\n * \n * \u5C01\u88C5\u4E86\u5E38\u89C1\u7684 ghost-cursor \u70B9\u51FB\u6A21\u5F0F\uFF1A\u5B9A\u4F4D\u5143\u7D20 -> \u79FB\u52A8\u9F20\u6807 -> \u968F\u673A\u5EF6\u8FDF -> \u70B9\u51FB\n * \n * @param {import('playwright').Page} page\n * @param {import('ghost-cursor-playwright').GhostCursor} cursor - \u7531 createCursor(page) \u521B\u5EFA\n * @param {string} selector - CSS \u9009\u62E9\u5668\n * @param {Object} [options]\n * @param {number} [options.delayBefore=300] - \u70B9\u51FB\u524D\u6700\u5C0F\u5EF6\u8FDF (ms)\n * @param {number} [options.delayAfter=800] - \u70B9\u51FB\u524D\u6700\u5927\u5EF6\u8FDF (ms)\n * @param {boolean} [options.throwOnMissing=true] - \u5143\u7D20\u4E0D\u5B58\u5728\u65F6\u662F\u5426\u629B\u51FA\u9519\u8BEF\n */\n async humanClick(page, cursor, selector, options = {}) {\n const {\n delayBefore = 300,\n delayAfter = 800,\n throwOnMissing = true\n } = options;\n\n const element = await page.$(selector);\n if (!element) {\n if (throwOnMissing) {\n throw new Error(`[Humanize] humanClick: \u627E\u4E0D\u5230\u5143\u7D20 ${selector}`);\n }\n log.warning(`[Humanize] humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);\n return false;\n }\n\n const box = await element.boundingBox();\n if (!box) {\n if (throwOnMissing) {\n throw new Error(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u5143\u7D20\u4F4D\u7F6E ${selector}`);\n }\n log.warning(`[Humanize] humanClick: \u65E0\u6CD5\u83B7\u53D6\u4F4D\u7F6E\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${selector}`);\n return false;\n }\n\n // \u8BA1\u7B97\u5143\u7D20\u4E2D\u5FC3\u70B9\uFF08\u5E26\u968F\u673A\u504F\u79FB\uFF09\n const offsetX = (Math.random() - 0.5) * box.width * 0.3; // \u00B115% \u504F\u79FB\n const offsetY = (Math.random() - 0.5) * box.height * 0.3;\n const x = box.x + box.width / 2 + offsetX;\n const y = box.y + box.height / 2 + offsetY;\n\n // \u79FB\u52A8\u9F20\u6807\n await cursor.actions.move({ x, y });\n\n // \u968F\u673A\u5EF6\u8FDF\u540E\u70B9\u51FB\n await rangeDelay(delayBefore, delayAfter);\n await cursor.actions.click();\n\n return true;\n }\n}\n", "// \u96C6\u4E2D\u7BA1\u7406\u542F\u52A8\u914D\u7F6E\uFF0C\u6682\u65F6\u4E3B\u8981\u7531 Stealth \u6A21\u5757\u63D0\u4F9B Args\uFF0C\u8FD9\u91CC\u4F5C\u4E3A\u6269\u5C55\u70B9\nimport { Stealth } from './stealth.js';\n\nexport const Launch = {\n getLaunchOptions(customArgs = []) {\n return {\n args: [\n ...Stealth.getStealthLaunchArgs(),\n ...customArgs\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n };\n },\n\n /**\n * \u83B7\u53D6\u589E\u5F3A\u7248\u542F\u52A8\u9009\u9879\uFF08\u7528\u4E8E\u9AD8\u98CE\u9669\u53CD\u722C\u573A\u666F\uFF09\n */\n getAdvancedLaunchOptions(customArgs = []) {\n return {\n args: [\n ...Stealth.getAdvancedStealthArgs(),\n ...customArgs\n ],\n ignoreDefaultArgs: ['--enable-automation'],\n };\n },\n\n /**\n * \u63A8\u8350\u7684 Fingerprint Generator \u9009\u9879\n * \u786E\u4FDD\u751F\u6210\u7684\u662F\u684C\u9762\u7AEF\u3001\u8F83\u65B0\u7684 Chrome\uFF0C\u4EE5\u5339\u914D\u6211\u4EEC\u7684\u811A\u672C\u903B\u8F91\n */\n getFingerprintGeneratorOptions() {\n return {\n browsers: [{ name: 'chrome', minVersion: 110 }],\n devices: ['desktop'],\n operatingSystems: ['windows', 'linux'], // \u5305\u542B Linux \u517C\u5BB9\u5BB9\u5668\n };\n },\n\n /**\n * \u521B\u5EFA\u5DF2\u6CE8\u518C Stealth \u63D2\u4EF6\u7684 Chromium \u5B9E\u4F8B\n * \n * \u5C01\u88C5\u4E86 `chromium.use(stealthPlugin())` \u7684\u5E38\u7528\u6A21\u5F0F\n * \n * @example\n * ```javascript\n * import { chromium } from 'playwright-extra';\n * import stealthPlugin from 'puppeteer-extra-plugin-stealth';\n * \n * const stealthChromium = Launch.createStealthChromium(chromium, stealthPlugin);\n * // \u73B0\u5728 stealthChromium \u5DF2\u6CE8\u518C stealth \u63D2\u4EF6\uFF0C\u53EF\u7528\u4E8E launchContext.launcher\n * ```\n * \n * @param {import('playwright-extra').ChromiumExtra} chromium - playwright-extra \u7684 chromium\n * @param {Function} stealthPlugin - puppeteer-extra-plugin-stealth \u7684\u9ED8\u8BA4\u5BFC\u51FA\n * @returns {import('playwright-extra').ChromiumExtra} \u5DF2\u6CE8\u518C stealth \u7684 chromium\n */\n createStealthChromium(chromium, stealthPlugin) {\n chromium.use(stealthPlugin());\n return chromium;\n },\n\n /**\n * \u521B\u5EFA Ghost Cursor \u5B9E\u4F8B\n * \n * \u5BF9 ghost-cursor-playwright \u7684\u7B80\u5355\u5C01\u88C5\n * \n * @param {import('playwright').Page} page\n * @param {Function} createCursor - ghost-cursor-playwright \u7684 createCursor \u51FD\u6570\n * @returns {Promise<import('ghost-cursor-playwright').Cursor>}\n */\n async createGhostCursor(page, createCursor) {\n return await createCursor(page);\n }\n}\n\n", "import express from 'express';\nimport { log } from 'crawlee';\nimport { Actor } from 'apify';\nimport { PresetOfLiveViewKey } from './constants';\n\n/**\n * \u542F\u52A8\u4E00\u4E2A Web \u670D\u52A1\u5668\u4EE5\u5728 Live View \u9009\u9879\u5361\u4E2D\u663E\u793A\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\u3002\n */\nasync function startLiveViewServer(liveViewKey) {\n const app = express();\n\n app.get('/', async (req, res) => {\n try {\n // \u4ECE\u9ED8\u8BA4\u7684 Key-Value Store \u4E2D\u8BFB\u53D6\u6700\u65B0\u7684\u5C4F\u5E55\u622A\u56FE\n const screenshotBuffer = await Actor.getValue(liveViewKey);\n\n if (!screenshotBuffer) {\n // \u5982\u679C\u8FD8\u6CA1\u6709\u622A\u56FE\uFF0C\u53D1\u9001\u4E00\u4E2A\u81EA\u52A8\u5237\u65B0\u7684\u5360\u4F4D\u9875\u9762\n res.send('<html><head><meta http-equiv=\"refresh\" content=\"2\"></head><body>\u7B49\u5F85\u7B2C\u4E00\u4E2A\u5C4F\u5E55\u622A\u56FE...</body></html>');\n return;\n }\n\n // \u5C06 Buffer \u8F6C\u6362\u4E3A Base64 \u5B57\u7B26\u4E32\n const screenshotBase64 = screenshotBuffer.toString('base64');\n\n // \u53D1\u9001\u4E00\u4E2A HTML \u9875\u9762\uFF0C\u8BE5\u9875\u9762\u6BCF 1 \u79D2\u81EA\u52A8\u5237\u65B0\u4E00\u6B21\uFF0C\u5E76\u663E\u793A\u622A\u56FE\n res.send(`\n <html>\n <head>\n <title>Live View (\u622A\u56FE)</title>\n <meta http-equiv=\"refresh\" content=\"1\">\n </head>\n <body style=\"margin:0; padding:0;\">\n <img src=\"data:image/png;base64,${screenshotBase64}\" \n alt=\"Live View Screenshot\" \n style=\"width: 100%; height: auto;\" />\n </body>\n </html>\n `);\n } catch (error) {\n log.error(`Live View \u670D\u52A1\u5668\u9519\u8BEF: ${error.message}`);\n res.status(500).send(`\u65E0\u6CD5\u52A0\u8F7D\u5C4F\u5E55\u622A\u56FE: ${error.message}`);\n }\n });\n\n // \u76D1\u542C Apify \u5BB9\u5668\u7AEF\u53E3 \n const port = process.env.APIFY_CONTAINER_PORT || 4321;\n app.listen(port, () => { log.info(`Live View \u670D\u52A1\u5668\u5DF2\u542F\u52A8\uFF0C\u76D1\u542C\u7AEF\u53E3 ${port}\u3002\u8BF7\u6253\u5F00 \"Live View\" \u9009\u9879\u5361\u67E5\u770B\u3002`); });\n}\n\n/**\n * \u62CD\u6444\u5F53\u524D\u9875\u9762\u7684\u5C4F\u5E55\u622A\u56FE\u5E76\u5C06\u5176\u4FDD\u5B58\u5230 Key-Value Store\u3002\n * @param {import('playwright').Page} page\n * @param {string} [logMessage] - \u53EF\u9009\u7684\u65E5\u5FD7\u6D88\u606F\u3002\n */\nasync function takeLiveScreenshot(liveViewKey, page, logMessage) {\n try {\n const buffer = await page.screenshot({ type: 'png' });\n await Actor.setValue(liveViewKey, buffer, { contentType: 'image/png' });\n if (logMessage) {\n log.info(`(\u622A\u56FE): ${logMessage}`);\n }\n } catch (e) {\n log.warning(`\u65E0\u6CD5\u6355\u83B7 Live View \u5C4F\u5E55\u622A\u56FE: ${e.message}`);\n }\n}\n\nconst useLiveView = (liveViewKey = PresetOfLiveViewKey) => {\n return {\n takeLiveScreenshot: async (page, logMessage) => {\n return await takeLiveScreenshot(liveViewKey, page, logMessage)\n },\n startLiveViewServer: async () => {\n return await startLiveViewServer(liveViewKey);\n }\n }\n}\n\nexport const LiveView = {\n useLiveView,\n};\n", "import { log } from 'crawlee';\n\n/**\n * \u521B\u5EFA\u9A8C\u8BC1\u7801\u76D1\u63A7\u5668 - \u652F\u6301 DOM \u9009\u62E9\u5668 \u548C URL \u6A21\u5F0F \u4E24\u79CD\u68C0\u6D4B\u65B9\u5F0F\n * \n * \u6CE8\u610F\uFF1A\u76D1\u63A7\u5668\u968F\u9875\u9762\u751F\u547D\u5468\u671F\u81EA\u52A8\u6E05\u7406\uFF0C\u65E0\u9700\u624B\u52A8 cleanup\n * \n * @param {import('playwright').Page} page\n * @param {Object} options\n * @param {string} [options.domSelector] - DOM \u5143\u7D20\u9009\u62E9\u5668 (\u5982 '#captcha_container')\n * @param {string} [options.urlPattern] - URL \u5339\u914D\u6A21\u5F0F (\u5982 '/captcha')\n * @param {Function} options.onDetected - \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\u65F6\u7684\u56DE\u8C03 (async function)\n */\nexport function useCaptchaMonitor(page, options) {\n const { domSelector, urlPattern, onDetected } = options;\n\n if (!domSelector && !urlPattern) {\n throw new Error('[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector \u6216 urlPattern \u81F3\u5C11\u4E00\u4E2A');\n }\n\n if (!onDetected || typeof onDetected !== 'function') {\n throw new Error('[CaptchaMonitor] onDetected \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570');\n }\n\n let isHandled = false;\n let frameHandler = null;\n let exposedFunctionName = null;\n\n const triggerDetected = async () => {\n if (isHandled) return;\n isHandled = true;\n log.error('[CaptchaMonitor] \uD83D\uDED1 \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\uFF01');\n await onDetected();\n };\n\n // ============================================================\n // \u6A21\u5F0F1: DOM \u76D1\u63A7 (\u4F7F\u7528 MutationObserver)\n // ============================================================\n if (domSelector) {\n // \u751F\u6210\u552F\u4E00\u7684\u51FD\u6570\u540D\u907F\u514D\u51B2\u7A81\n exposedFunctionName = `__c_d_${Date.now()}`;\n\n // \u66B4\u9732\u56DE\u8C03\u51FD\u6570\u7ED9\u9875\u9762\n page.exposeFunction(exposedFunctionName, triggerDetected).catch(() => {\n // \u5FFD\u7565\u91CD\u590D\u66B4\u9732\u9519\u8BEF\n });\n\n // \u6CE8\u5165 MutationObserver \u76D1\u542C\u811A\u672C\n page.addInitScript(({ selector, callbackName }) => {\n (() => {\n let observer = null;\n\n const checkAndReport = () => {\n const element = document.querySelector(selector);\n if (element) {\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n if (window[callbackName]) {\n window[callbackName]();\n }\n return true;\n }\n return false;\n };\n\n // 1. \u7ACB\u5373\u68C0\u67E5\u4E00\u6B21\n if (checkAndReport()) return;\n\n // 2. \u542F\u52A8 MutationObserver\n observer = new MutationObserver((mutations) => {\n let shouldCheck = false;\n for (const mutation of mutations) {\n if (mutation.addedNodes.length > 0) {\n shouldCheck = true;\n break;\n }\n }\n if (shouldCheck && observer) {\n checkAndReport();\n }\n });\n\n // 3. \u6302\u8F7D\u76D1\u542C\uFF08\u786E\u4FDD DOM \u51C6\u5907\u5C31\u7EEA\uFF09\n const mountObserver = () => {\n const target = document.documentElement;\n if (target && observer) {\n observer.observe(target, { childList: true, subtree: true });\n }\n };\n\n if (document.readyState === 'loading') {\n window.addEventListener('DOMContentLoaded', mountObserver);\n } else {\n mountObserver();\n }\n })();\n }, { selector: domSelector, callbackName: exposedFunctionName });\n\n log.info(`[CaptchaMonitor] DOM \u76D1\u63A7\u5DF2\u542F\u7528: ${domSelector}`);\n }\n\n // ============================================================\n // \u6A21\u5F0F2: URL \u76D1\u63A7 (\u76D1\u542C framenavigated)\n // ============================================================\n if (urlPattern) {\n frameHandler = async (frame) => {\n if (frame === page.mainFrame()) {\n const currentUrl = page.url();\n if (currentUrl.includes(urlPattern)) {\n await triggerDetected();\n }\n }\n };\n\n page.on('framenavigated', frameHandler);\n log.info(`[CaptchaMonitor] URL \u76D1\u63A7\u5DF2\u542F\u7528: ${urlPattern}`);\n }\n\n // \u6CE8\u610F\uFF1A\u4E0D\u63D0\u4F9B cleanup \u51FD\u6570\n // - DOM \u6A21\u5F0F\uFF1AaddInitScript \u6CE8\u5165\u7684\u4EE3\u7801\u65E0\u6CD5\u4ECE Node \u7AEF\u6E05\u7406\n // - URL \u6A21\u5F0F\uFF1Aframenavigated \u76D1\u542C\u901A\u5E38\u8DDF\u968F\u9875\u9762\u751F\u547D\u5468\u671F\uFF0C\u65E0\u9700\u624B\u52A8\u6E05\u7406\n // \u5982\u679C\u9700\u8981\u63D0\u524D\u7EC8\u6B62\u76D1\u63A7\uFF0C\u8BBE\u8BA1\u4E0A\u5E94\u8BE5\u8BA9 onDetected \u5904\u7406\u540E\u7EED\u903B\u8F91\uFF08\u5982 Actor.fail\uFF09\n}\n\n// \u6309\u7167 toolkit \u7EDF\u4E00\u7684\u5BFC\u51FA\u6A21\u5F0F\nexport const Captcha = {\n useCaptchaMonitor\n};\n", "import { ApifyKit } from './src/apify-kit.js';\nimport { Utils } from './src/utils.js';\nimport { Stealth } from './src/stealth.js';\nimport { Humanize } from './src/humanize.js';\nimport { Launch } from './src/launch.js';\nimport { LiveView } from './src/live-view.js';\nimport { Captcha } from './src/captcha-monitor.js';\nimport * as Constants from './src/constants.js';\n\n// Unified Entry Point\nexport const usePlaywrightToolKit = () => {\n return {\n ApifyKit,\n Stealth,\n Humanize,\n Launch,\n LiveView,\n Constants,\n Utils,\n Captcha\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Actor", "log", "log", "log", "log", "log"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skrillex1224/playwright-toolkit",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.16",
|
|
4
4
|
"description": "一个在 Apify/Crawlee Actor 中启用实时截图视图的实用工具库。",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -39,13 +39,21 @@
|
|
|
39
39
|
"apify": "*",
|
|
40
40
|
"crawlee": "*",
|
|
41
41
|
"playwright": "*",
|
|
42
|
-
"
|
|
42
|
+
"playwright-extra": "*",
|
|
43
|
+
"puppeteer-extra-plugin-stealth": "*",
|
|
44
|
+
"ghost-cursor-playwright": "*"
|
|
43
45
|
},
|
|
44
46
|
"peerDependenciesMeta": {
|
|
45
47
|
"playwright": {
|
|
46
48
|
"optional": true
|
|
47
49
|
},
|
|
48
|
-
"
|
|
50
|
+
"playwright-extra": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"puppeteer-extra-plugin-stealth": {
|
|
54
|
+
"optional": true
|
|
55
|
+
},
|
|
56
|
+
"ghost-cursor-playwright": {
|
|
49
57
|
"optional": true
|
|
50
58
|
}
|
|
51
59
|
},
|