@skrillex1224/playwright-toolkit 2.0.13 → 2.0.14
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 +1 -1
- package/dist/index.cjs +197 -1
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +197 -1
- package/dist/index.js.map +4 -4
- package/package.json +12 -3
package/README.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -260,6 +260,29 @@ var Stealth = {
|
|
|
260
260
|
// 注意:不建议这里强制指定 window-size,让 syncViewportWithScreen 去动态调整
|
|
261
261
|
// '--window-size=1920,1080'
|
|
262
262
|
];
|
|
263
|
+
},
|
|
264
|
+
/**
|
|
265
|
+
* 获取增强版 Stealth 启动参数 (推荐用于高风险反爬场景)
|
|
266
|
+
* 包含更多针对自动化检测的防护
|
|
267
|
+
*/
|
|
268
|
+
getAdvancedStealthArgs() {
|
|
269
|
+
return [
|
|
270
|
+
...this.getStealthLaunchArgs(),
|
|
271
|
+
// 禁用各种可能暴露自动化的特征
|
|
272
|
+
"--disable-dev-shm-usage",
|
|
273
|
+
"--disable-accelerated-2d-canvas",
|
|
274
|
+
"--disable-gpu-sandbox",
|
|
275
|
+
"--disable-background-networking",
|
|
276
|
+
"--disable-default-apps",
|
|
277
|
+
"--disable-extensions",
|
|
278
|
+
"--disable-sync",
|
|
279
|
+
"--disable-translate",
|
|
280
|
+
"--metrics-recording-only",
|
|
281
|
+
"--mute-audio",
|
|
282
|
+
"--no-first-run",
|
|
283
|
+
// 模拟真实用户配置
|
|
284
|
+
"--lang=zh-CN,zh"
|
|
285
|
+
];
|
|
263
286
|
}
|
|
264
287
|
};
|
|
265
288
|
|
|
@@ -289,6 +312,93 @@ var Humanize = {
|
|
|
289
312
|
await cursor.moveTo({ x, y });
|
|
290
313
|
await (0, import_delay.rangeDelay)(200, 800);
|
|
291
314
|
}
|
|
315
|
+
},
|
|
316
|
+
/**
|
|
317
|
+
* 人类化输入 - 带节奏变化(快-慢-停顿-偶尔加速)
|
|
318
|
+
* @param {import('playwright').Page} page
|
|
319
|
+
* @param {string} selector - 输入框选择器
|
|
320
|
+
* @param {string} text - 要输入的文本
|
|
321
|
+
* @param {Object} [options]
|
|
322
|
+
* @param {number} [options.minDelay=50] - 最小按键延迟 (ms)
|
|
323
|
+
* @param {number} [options.maxDelay=200] - 最大按键延迟 (ms)
|
|
324
|
+
* @param {number} [options.pauseProbability=0.1] - 停顿概率 (0-1)
|
|
325
|
+
* @param {number} [options.pauseMin=300] - 停顿最小时长 (ms)
|
|
326
|
+
* @param {number} [options.pauseMax=800] - 停顿最大时长 (ms)
|
|
327
|
+
*/
|
|
328
|
+
async humanType(page, selector, text, options = {}) {
|
|
329
|
+
const {
|
|
330
|
+
minDelay = 50,
|
|
331
|
+
maxDelay = 200,
|
|
332
|
+
pauseProbability = 0.1,
|
|
333
|
+
pauseMin = 300,
|
|
334
|
+
pauseMax = 800
|
|
335
|
+
} = options;
|
|
336
|
+
const locator = page.locator(selector);
|
|
337
|
+
await locator.click();
|
|
338
|
+
await (0, import_delay.rangeDelay)(100, 300);
|
|
339
|
+
for (let i = 0; i < text.length; i++) {
|
|
340
|
+
const char = text[i];
|
|
341
|
+
let charDelay;
|
|
342
|
+
if (char === " ") {
|
|
343
|
+
charDelay = minDelay + Math.random() * 50;
|
|
344
|
+
} else if (/[,.!?;:]/.test(char)) {
|
|
345
|
+
charDelay = maxDelay + Math.random() * 100;
|
|
346
|
+
} else {
|
|
347
|
+
charDelay = minDelay + Math.random() * (maxDelay - minDelay);
|
|
348
|
+
}
|
|
349
|
+
await locator.press(char);
|
|
350
|
+
await (0, import_delay.default)(charDelay);
|
|
351
|
+
if (Math.random() < pauseProbability && i < text.length - 1) {
|
|
352
|
+
const pauseTime = pauseMin + Math.random() * (pauseMax - pauseMin);
|
|
353
|
+
import_crawlee3.log.debug(`[Humanize] \u505C\u987F ${Math.round(pauseTime)}ms...`);
|
|
354
|
+
await (0, import_delay.default)(pauseTime);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
/**
|
|
359
|
+
* 页面预热浏览 - 模拟人类进入页面后的探索行为
|
|
360
|
+
* @param {import('playwright').Page} page
|
|
361
|
+
* @param {import('ghost-cursor-playwright').GhostCursor} cursor
|
|
362
|
+
* @param {number} [durationMs=3000] - 预热时长 (ms)
|
|
363
|
+
*/
|
|
364
|
+
async warmUpBrowsing(page, cursor, durationMs = 3e3) {
|
|
365
|
+
import_crawlee3.log.info(`[Humanize] \u5F00\u59CB\u9875\u9762\u9884\u70ED\u6D4F\u89C8 (${durationMs}ms)...`);
|
|
366
|
+
const startTime = Date.now();
|
|
367
|
+
const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };
|
|
368
|
+
while (Date.now() - startTime < durationMs) {
|
|
369
|
+
const action = Math.random();
|
|
370
|
+
if (action < 0.4) {
|
|
371
|
+
const x = 100 + Math.random() * (viewportSize.width - 200);
|
|
372
|
+
const y = 100 + Math.random() * (viewportSize.height - 200);
|
|
373
|
+
await cursor.moveTo({ x, y });
|
|
374
|
+
await (0, import_delay.rangeDelay)(200, 500);
|
|
375
|
+
} else if (action < 0.7) {
|
|
376
|
+
const scrollY = (Math.random() - 0.5) * 200;
|
|
377
|
+
await page.mouse.wheel(0, scrollY);
|
|
378
|
+
await (0, import_delay.rangeDelay)(300, 700);
|
|
379
|
+
} else {
|
|
380
|
+
await (0, import_delay.rangeDelay)(500, 1e3);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
import_crawlee3.log.info("[Humanize] \u9875\u9762\u9884\u70ED\u5B8C\u6210");
|
|
384
|
+
},
|
|
385
|
+
/**
|
|
386
|
+
* 自然滚动 - 带惯性和减速效果
|
|
387
|
+
* @param {import('playwright').Page} page
|
|
388
|
+
* @param {'up' | 'down'} [direction='down'] - 滚动方向
|
|
389
|
+
* @param {number} [distance=300] - 总滚动距离 (px)
|
|
390
|
+
* @param {number} [steps=5] - 分几步完成
|
|
391
|
+
*/
|
|
392
|
+
async naturalScroll(page, direction = "down", distance = 300, steps = 5) {
|
|
393
|
+
const sign = direction === "down" ? 1 : -1;
|
|
394
|
+
const stepDistance = distance / steps;
|
|
395
|
+
for (let i = 0; i < steps; i++) {
|
|
396
|
+
const factor = 1 - i / steps * 0.5;
|
|
397
|
+
const scrollAmount = stepDistance * factor * sign;
|
|
398
|
+
await page.mouse.wheel(0, scrollAmount);
|
|
399
|
+
const delayTime = 50 + i * 30;
|
|
400
|
+
await (0, import_delay.default)(delayTime);
|
|
401
|
+
}
|
|
292
402
|
}
|
|
293
403
|
};
|
|
294
404
|
|
|
@@ -379,6 +489,91 @@ var LiveView = {
|
|
|
379
489
|
useLiveView
|
|
380
490
|
};
|
|
381
491
|
|
|
492
|
+
// src/captcha-monitor.js
|
|
493
|
+
var import_crawlee5 = require("crawlee");
|
|
494
|
+
function useCaptchaMonitor(page, options) {
|
|
495
|
+
const { domSelector, urlPattern, onDetected } = options;
|
|
496
|
+
if (!domSelector && !urlPattern) {
|
|
497
|
+
throw new Error("[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector \u6216 urlPattern \u81F3\u5C11\u4E00\u4E2A");
|
|
498
|
+
}
|
|
499
|
+
if (!onDetected || typeof onDetected !== "function") {
|
|
500
|
+
throw new Error("[CaptchaMonitor] onDetected \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570");
|
|
501
|
+
}
|
|
502
|
+
let isHandled = false;
|
|
503
|
+
let frameHandler = null;
|
|
504
|
+
let exposedFunctionName = null;
|
|
505
|
+
const triggerDetected = async () => {
|
|
506
|
+
if (isHandled) return;
|
|
507
|
+
isHandled = true;
|
|
508
|
+
import_crawlee5.log.error("[CaptchaMonitor] \u{1F6D1} \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\uFF01");
|
|
509
|
+
await onDetected();
|
|
510
|
+
};
|
|
511
|
+
if (domSelector) {
|
|
512
|
+
exposedFunctionName = `__c_d_${Date.now()}`;
|
|
513
|
+
page.exposeFunction(exposedFunctionName, triggerDetected).catch(() => {
|
|
514
|
+
});
|
|
515
|
+
page.addInitScript(({ selector, callbackName }) => {
|
|
516
|
+
(() => {
|
|
517
|
+
let observer = null;
|
|
518
|
+
const checkAndReport = () => {
|
|
519
|
+
const element = document.querySelector(selector);
|
|
520
|
+
if (element) {
|
|
521
|
+
if (observer) {
|
|
522
|
+
observer.disconnect();
|
|
523
|
+
observer = null;
|
|
524
|
+
}
|
|
525
|
+
if (window[callbackName]) {
|
|
526
|
+
window[callbackName]();
|
|
527
|
+
}
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
return false;
|
|
531
|
+
};
|
|
532
|
+
if (checkAndReport()) return;
|
|
533
|
+
observer = new MutationObserver((mutations) => {
|
|
534
|
+
let shouldCheck = false;
|
|
535
|
+
for (const mutation of mutations) {
|
|
536
|
+
if (mutation.addedNodes.length > 0) {
|
|
537
|
+
shouldCheck = true;
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
if (shouldCheck && observer) {
|
|
542
|
+
checkAndReport();
|
|
543
|
+
}
|
|
544
|
+
});
|
|
545
|
+
const mountObserver = () => {
|
|
546
|
+
const target = document.documentElement;
|
|
547
|
+
if (target && observer) {
|
|
548
|
+
observer.observe(target, { childList: true, subtree: true });
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
if (document.readyState === "loading") {
|
|
552
|
+
window.addEventListener("DOMContentLoaded", mountObserver);
|
|
553
|
+
} else {
|
|
554
|
+
mountObserver();
|
|
555
|
+
}
|
|
556
|
+
})();
|
|
557
|
+
}, { selector: domSelector, callbackName: exposedFunctionName });
|
|
558
|
+
import_crawlee5.log.info(`[CaptchaMonitor] DOM \u76D1\u63A7\u5DF2\u542F\u7528: ${domSelector}`);
|
|
559
|
+
}
|
|
560
|
+
if (urlPattern) {
|
|
561
|
+
frameHandler = async (frame) => {
|
|
562
|
+
if (frame === page.mainFrame()) {
|
|
563
|
+
const currentUrl = page.url();
|
|
564
|
+
if (currentUrl.includes(urlPattern)) {
|
|
565
|
+
await triggerDetected();
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
page.on("framenavigated", frameHandler);
|
|
570
|
+
import_crawlee5.log.info(`[CaptchaMonitor] URL \u76D1\u63A7\u5DF2\u542F\u7528: ${urlPattern}`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
var Captcha = {
|
|
574
|
+
useCaptchaMonitor
|
|
575
|
+
};
|
|
576
|
+
|
|
382
577
|
// index.js
|
|
383
578
|
var usePlaywrightToolKit = () => {
|
|
384
579
|
return {
|
|
@@ -388,7 +583,8 @@ var usePlaywrightToolKit = () => {
|
|
|
388
583
|
Launch,
|
|
389
584
|
LiveView,
|
|
390
585
|
Constants: constants_exports,
|
|
391
|
-
Utils
|
|
586
|
+
Utils,
|
|
587
|
+
Captcha
|
|
392
588
|
};
|
|
393
589
|
};
|
|
394
590
|
// Annotate the CommonJS export names for ESM import in node:
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 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"],
|
|
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 * 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 };\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", "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", "// \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"],
|
|
5
|
-
"mappings": "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
|
|
6
|
-
"names": ["Actor", "import_crawlee", "import_crawlee", "delay", "import_crawlee", "express"]
|
|
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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",
|
|
6
|
+
"names": ["Actor", "import_crawlee", "import_crawlee", "delay", "import_crawlee", "express", "import_crawlee"]
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -231,6 +231,29 @@ var Stealth = {
|
|
|
231
231
|
// 注意:不建议这里强制指定 window-size,让 syncViewportWithScreen 去动态调整
|
|
232
232
|
// '--window-size=1920,1080'
|
|
233
233
|
];
|
|
234
|
+
},
|
|
235
|
+
/**
|
|
236
|
+
* 获取增强版 Stealth 启动参数 (推荐用于高风险反爬场景)
|
|
237
|
+
* 包含更多针对自动化检测的防护
|
|
238
|
+
*/
|
|
239
|
+
getAdvancedStealthArgs() {
|
|
240
|
+
return [
|
|
241
|
+
...this.getStealthLaunchArgs(),
|
|
242
|
+
// 禁用各种可能暴露自动化的特征
|
|
243
|
+
"--disable-dev-shm-usage",
|
|
244
|
+
"--disable-accelerated-2d-canvas",
|
|
245
|
+
"--disable-gpu-sandbox",
|
|
246
|
+
"--disable-background-networking",
|
|
247
|
+
"--disable-default-apps",
|
|
248
|
+
"--disable-extensions",
|
|
249
|
+
"--disable-sync",
|
|
250
|
+
"--disable-translate",
|
|
251
|
+
"--metrics-recording-only",
|
|
252
|
+
"--mute-audio",
|
|
253
|
+
"--no-first-run",
|
|
254
|
+
// 模拟真实用户配置
|
|
255
|
+
"--lang=zh-CN,zh"
|
|
256
|
+
];
|
|
234
257
|
}
|
|
235
258
|
};
|
|
236
259
|
|
|
@@ -260,6 +283,93 @@ var Humanize = {
|
|
|
260
283
|
await cursor.moveTo({ x, y });
|
|
261
284
|
await rangeDelay(200, 800);
|
|
262
285
|
}
|
|
286
|
+
},
|
|
287
|
+
/**
|
|
288
|
+
* 人类化输入 - 带节奏变化(快-慢-停顿-偶尔加速)
|
|
289
|
+
* @param {import('playwright').Page} page
|
|
290
|
+
* @param {string} selector - 输入框选择器
|
|
291
|
+
* @param {string} text - 要输入的文本
|
|
292
|
+
* @param {Object} [options]
|
|
293
|
+
* @param {number} [options.minDelay=50] - 最小按键延迟 (ms)
|
|
294
|
+
* @param {number} [options.maxDelay=200] - 最大按键延迟 (ms)
|
|
295
|
+
* @param {number} [options.pauseProbability=0.1] - 停顿概率 (0-1)
|
|
296
|
+
* @param {number} [options.pauseMin=300] - 停顿最小时长 (ms)
|
|
297
|
+
* @param {number} [options.pauseMax=800] - 停顿最大时长 (ms)
|
|
298
|
+
*/
|
|
299
|
+
async humanType(page, selector, text, options = {}) {
|
|
300
|
+
const {
|
|
301
|
+
minDelay = 50,
|
|
302
|
+
maxDelay = 200,
|
|
303
|
+
pauseProbability = 0.1,
|
|
304
|
+
pauseMin = 300,
|
|
305
|
+
pauseMax = 800
|
|
306
|
+
} = options;
|
|
307
|
+
const locator = page.locator(selector);
|
|
308
|
+
await locator.click();
|
|
309
|
+
await rangeDelay(100, 300);
|
|
310
|
+
for (let i = 0; i < text.length; i++) {
|
|
311
|
+
const char = text[i];
|
|
312
|
+
let charDelay;
|
|
313
|
+
if (char === " ") {
|
|
314
|
+
charDelay = minDelay + Math.random() * 50;
|
|
315
|
+
} else if (/[,.!?;:]/.test(char)) {
|
|
316
|
+
charDelay = maxDelay + Math.random() * 100;
|
|
317
|
+
} else {
|
|
318
|
+
charDelay = minDelay + Math.random() * (maxDelay - minDelay);
|
|
319
|
+
}
|
|
320
|
+
await locator.press(char);
|
|
321
|
+
await delay(charDelay);
|
|
322
|
+
if (Math.random() < pauseProbability && i < text.length - 1) {
|
|
323
|
+
const pauseTime = pauseMin + Math.random() * (pauseMax - pauseMin);
|
|
324
|
+
log3.debug(`[Humanize] \u505C\u987F ${Math.round(pauseTime)}ms...`);
|
|
325
|
+
await delay(pauseTime);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
/**
|
|
330
|
+
* 页面预热浏览 - 模拟人类进入页面后的探索行为
|
|
331
|
+
* @param {import('playwright').Page} page
|
|
332
|
+
* @param {import('ghost-cursor-playwright').GhostCursor} cursor
|
|
333
|
+
* @param {number} [durationMs=3000] - 预热时长 (ms)
|
|
334
|
+
*/
|
|
335
|
+
async warmUpBrowsing(page, cursor, durationMs = 3e3) {
|
|
336
|
+
log3.info(`[Humanize] \u5F00\u59CB\u9875\u9762\u9884\u70ED\u6D4F\u89C8 (${durationMs}ms)...`);
|
|
337
|
+
const startTime = Date.now();
|
|
338
|
+
const viewportSize = page.viewportSize() || { width: 1920, height: 1080 };
|
|
339
|
+
while (Date.now() - startTime < durationMs) {
|
|
340
|
+
const action = Math.random();
|
|
341
|
+
if (action < 0.4) {
|
|
342
|
+
const x = 100 + Math.random() * (viewportSize.width - 200);
|
|
343
|
+
const y = 100 + Math.random() * (viewportSize.height - 200);
|
|
344
|
+
await cursor.moveTo({ x, y });
|
|
345
|
+
await rangeDelay(200, 500);
|
|
346
|
+
} else if (action < 0.7) {
|
|
347
|
+
const scrollY = (Math.random() - 0.5) * 200;
|
|
348
|
+
await page.mouse.wheel(0, scrollY);
|
|
349
|
+
await rangeDelay(300, 700);
|
|
350
|
+
} else {
|
|
351
|
+
await rangeDelay(500, 1e3);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
log3.info("[Humanize] \u9875\u9762\u9884\u70ED\u5B8C\u6210");
|
|
355
|
+
},
|
|
356
|
+
/**
|
|
357
|
+
* 自然滚动 - 带惯性和减速效果
|
|
358
|
+
* @param {import('playwright').Page} page
|
|
359
|
+
* @param {'up' | 'down'} [direction='down'] - 滚动方向
|
|
360
|
+
* @param {number} [distance=300] - 总滚动距离 (px)
|
|
361
|
+
* @param {number} [steps=5] - 分几步完成
|
|
362
|
+
*/
|
|
363
|
+
async naturalScroll(page, direction = "down", distance = 300, steps = 5) {
|
|
364
|
+
const sign = direction === "down" ? 1 : -1;
|
|
365
|
+
const stepDistance = distance / steps;
|
|
366
|
+
for (let i = 0; i < steps; i++) {
|
|
367
|
+
const factor = 1 - i / steps * 0.5;
|
|
368
|
+
const scrollAmount = stepDistance * factor * sign;
|
|
369
|
+
await page.mouse.wheel(0, scrollAmount);
|
|
370
|
+
const delayTime = 50 + i * 30;
|
|
371
|
+
await delay(delayTime);
|
|
372
|
+
}
|
|
263
373
|
}
|
|
264
374
|
};
|
|
265
375
|
|
|
@@ -350,6 +460,91 @@ var LiveView = {
|
|
|
350
460
|
useLiveView
|
|
351
461
|
};
|
|
352
462
|
|
|
463
|
+
// src/captcha-monitor.js
|
|
464
|
+
import { log as log5 } from "crawlee";
|
|
465
|
+
function useCaptchaMonitor(page, options) {
|
|
466
|
+
const { domSelector, urlPattern, onDetected } = options;
|
|
467
|
+
if (!domSelector && !urlPattern) {
|
|
468
|
+
throw new Error("[CaptchaMonitor] \u5FC5\u987B\u63D0\u4F9B domSelector \u6216 urlPattern \u81F3\u5C11\u4E00\u4E2A");
|
|
469
|
+
}
|
|
470
|
+
if (!onDetected || typeof onDetected !== "function") {
|
|
471
|
+
throw new Error("[CaptchaMonitor] onDetected \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570");
|
|
472
|
+
}
|
|
473
|
+
let isHandled = false;
|
|
474
|
+
let frameHandler = null;
|
|
475
|
+
let exposedFunctionName = null;
|
|
476
|
+
const triggerDetected = async () => {
|
|
477
|
+
if (isHandled) return;
|
|
478
|
+
isHandled = true;
|
|
479
|
+
log5.error("[CaptchaMonitor] \u{1F6D1} \u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\uFF01");
|
|
480
|
+
await onDetected();
|
|
481
|
+
};
|
|
482
|
+
if (domSelector) {
|
|
483
|
+
exposedFunctionName = `__c_d_${Date.now()}`;
|
|
484
|
+
page.exposeFunction(exposedFunctionName, triggerDetected).catch(() => {
|
|
485
|
+
});
|
|
486
|
+
page.addInitScript(({ selector, callbackName }) => {
|
|
487
|
+
(() => {
|
|
488
|
+
let observer = null;
|
|
489
|
+
const checkAndReport = () => {
|
|
490
|
+
const element = document.querySelector(selector);
|
|
491
|
+
if (element) {
|
|
492
|
+
if (observer) {
|
|
493
|
+
observer.disconnect();
|
|
494
|
+
observer = null;
|
|
495
|
+
}
|
|
496
|
+
if (window[callbackName]) {
|
|
497
|
+
window[callbackName]();
|
|
498
|
+
}
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
return false;
|
|
502
|
+
};
|
|
503
|
+
if (checkAndReport()) return;
|
|
504
|
+
observer = new MutationObserver((mutations) => {
|
|
505
|
+
let shouldCheck = false;
|
|
506
|
+
for (const mutation of mutations) {
|
|
507
|
+
if (mutation.addedNodes.length > 0) {
|
|
508
|
+
shouldCheck = true;
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if (shouldCheck && observer) {
|
|
513
|
+
checkAndReport();
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
const mountObserver = () => {
|
|
517
|
+
const target = document.documentElement;
|
|
518
|
+
if (target && observer) {
|
|
519
|
+
observer.observe(target, { childList: true, subtree: true });
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
if (document.readyState === "loading") {
|
|
523
|
+
window.addEventListener("DOMContentLoaded", mountObserver);
|
|
524
|
+
} else {
|
|
525
|
+
mountObserver();
|
|
526
|
+
}
|
|
527
|
+
})();
|
|
528
|
+
}, { selector: domSelector, callbackName: exposedFunctionName });
|
|
529
|
+
log5.info(`[CaptchaMonitor] DOM \u76D1\u63A7\u5DF2\u542F\u7528: ${domSelector}`);
|
|
530
|
+
}
|
|
531
|
+
if (urlPattern) {
|
|
532
|
+
frameHandler = async (frame) => {
|
|
533
|
+
if (frame === page.mainFrame()) {
|
|
534
|
+
const currentUrl = page.url();
|
|
535
|
+
if (currentUrl.includes(urlPattern)) {
|
|
536
|
+
await triggerDetected();
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
page.on("framenavigated", frameHandler);
|
|
541
|
+
log5.info(`[CaptchaMonitor] URL \u76D1\u63A7\u5DF2\u542F\u7528: ${urlPattern}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
var Captcha = {
|
|
545
|
+
useCaptchaMonitor
|
|
546
|
+
};
|
|
547
|
+
|
|
353
548
|
// index.js
|
|
354
549
|
var usePlaywrightToolKit = () => {
|
|
355
550
|
return {
|
|
@@ -359,7 +554,8 @@ var usePlaywrightToolKit = () => {
|
|
|
359
554
|
Launch,
|
|
360
555
|
LiveView,
|
|
361
556
|
Constants: constants_exports,
|
|
362
|
-
Utils
|
|
557
|
+
Utils,
|
|
558
|
+
Captcha
|
|
363
559
|
};
|
|
364
560
|
};
|
|
365
561
|
export {
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 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", "../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", "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", "// \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 { 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 * 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 };\n};\n"],
|
|
5
|
-
"mappings": "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
|
|
6
|
-
"names": ["Actor", "log", "log", "log", "log"]
|
|
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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",
|
|
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.14",
|
|
4
4
|
"description": "一个在 Apify/Crawlee Actor 中启用实时截图视图的实用工具库。",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -35,10 +35,19 @@
|
|
|
35
35
|
"delay": "^7.0.0",
|
|
36
36
|
"express": "^4.18.2"
|
|
37
37
|
},
|
|
38
|
-
"
|
|
38
|
+
"peerDependencies": {
|
|
39
39
|
"apify": "*",
|
|
40
40
|
"crawlee": "*",
|
|
41
|
-
"playwright": "*"
|
|
41
|
+
"playwright": "*",
|
|
42
|
+
"rebrowser-playwright": "*"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"playwright": {
|
|
46
|
+
"optional": true
|
|
47
|
+
},
|
|
48
|
+
"rebrowser-playwright": {
|
|
49
|
+
"optional": true
|
|
50
|
+
}
|
|
42
51
|
},
|
|
43
52
|
"devDependencies": {
|
|
44
53
|
"esbuild": "^0.24.2"
|