@skrillex1224/playwright-toolkit 2.0.3 → 2.0.4
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/dist/index.cjs +84 -22
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +77 -15
- package/dist/index.js.map +4 -4
- package/package.json +9 -3
package/dist/index.cjs
CHANGED
|
@@ -33,9 +33,75 @@ __export(index_exports, {
|
|
|
33
33
|
});
|
|
34
34
|
module.exports = __toCommonJS(index_exports);
|
|
35
35
|
|
|
36
|
-
// src/
|
|
37
|
-
var
|
|
38
|
-
|
|
36
|
+
// src/optional-deps.js
|
|
37
|
+
var crawleeLog;
|
|
38
|
+
async function loadCrawlee() {
|
|
39
|
+
if (crawleeLog) return crawleeLog;
|
|
40
|
+
try {
|
|
41
|
+
const crawlee = await import("crawlee");
|
|
42
|
+
crawleeLog = crawlee.log;
|
|
43
|
+
} catch (e) {
|
|
44
|
+
crawleeLog = {
|
|
45
|
+
info: (...args) => console.log("[INFO]", ...args),
|
|
46
|
+
warning: (...args) => console.warn("[WARNING]", ...args),
|
|
47
|
+
error: (...args) => console.error("[ERROR]", ...args),
|
|
48
|
+
debug: (...args) => console.debug("[DEBUG]", ...args)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return crawleeLog;
|
|
52
|
+
}
|
|
53
|
+
var log = new Proxy({}, {
|
|
54
|
+
get(target, prop) {
|
|
55
|
+
return (...args) => {
|
|
56
|
+
return loadCrawlee().then((logger) => {
|
|
57
|
+
if (typeof logger[prop] === "function") {
|
|
58
|
+
return logger[prop](...args);
|
|
59
|
+
}
|
|
60
|
+
return logger[prop];
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
var ApifyActor;
|
|
66
|
+
var isApifyAvailable = false;
|
|
67
|
+
async function loadApify() {
|
|
68
|
+
if (ApifyActor) return { Actor: ApifyActor, isApifyAvailable };
|
|
69
|
+
try {
|
|
70
|
+
const apify = await import("apify");
|
|
71
|
+
ApifyActor = apify.Actor;
|
|
72
|
+
isApifyAvailable = true;
|
|
73
|
+
} catch (e) {
|
|
74
|
+
ApifyActor = {
|
|
75
|
+
// 基础方法返回 null 或空操作
|
|
76
|
+
getValue: async () => null,
|
|
77
|
+
setValue: async () => {
|
|
78
|
+
},
|
|
79
|
+
pushData: async (data) => {
|
|
80
|
+
console.log("[APIFY_STUB] pushData called:", data);
|
|
81
|
+
},
|
|
82
|
+
isAtHome: () => false,
|
|
83
|
+
fail: async (message) => {
|
|
84
|
+
throw new Error(message);
|
|
85
|
+
},
|
|
86
|
+
// 降级提示
|
|
87
|
+
_isStub: true
|
|
88
|
+
};
|
|
89
|
+
isApifyAvailable = false;
|
|
90
|
+
}
|
|
91
|
+
return { Actor: ApifyActor, isApifyAvailable };
|
|
92
|
+
}
|
|
93
|
+
var Actor = new Proxy({}, {
|
|
94
|
+
get(target, prop) {
|
|
95
|
+
return (...args) => {
|
|
96
|
+
return loadApify().then(({ Actor: Actor2 }) => {
|
|
97
|
+
if (typeof Actor2[prop] === "function") {
|
|
98
|
+
return Actor2[prop](...args);
|
|
99
|
+
}
|
|
100
|
+
return Actor2[prop];
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
39
105
|
|
|
40
106
|
// src/constants.js
|
|
41
107
|
var constants_exports = {};
|
|
@@ -87,13 +153,13 @@ var ApifyKit = {
|
|
|
87
153
|
async runStep(pendingStepName, page, actionFn, options = {}) {
|
|
88
154
|
const { failActor = true } = options;
|
|
89
155
|
const [failedKey, stepName] = this.unwrapStepName(pendingStepName);
|
|
90
|
-
|
|
156
|
+
log.info(`\u{1F504} [\u6B63\u5728\u6267\u884C] ${stepName}...`);
|
|
91
157
|
try {
|
|
92
158
|
const result = await actionFn();
|
|
93
|
-
|
|
159
|
+
log.info(`\u2705 [\u6267\u884C\u6210\u529F] ${stepName}`);
|
|
94
160
|
return result;
|
|
95
161
|
} catch (error) {
|
|
96
|
-
|
|
162
|
+
log.error(`\u274C [\u6267\u884C\u5931\u8D25] ${stepName}: ${error.message}`);
|
|
97
163
|
let screenshotBase64 = "\u622A\u56FE\u5931\u8D25";
|
|
98
164
|
try {
|
|
99
165
|
if (page) {
|
|
@@ -101,7 +167,7 @@ var ApifyKit = {
|
|
|
101
167
|
screenshotBase64 = `data:image/jpeg;base64,${buffer.toString("base64")}`;
|
|
102
168
|
}
|
|
103
169
|
} catch (snapErr) {
|
|
104
|
-
|
|
170
|
+
log.warning(`\u622A\u56FE\u751F\u6210\u5931\u8D25: ${snapErr.message}`);
|
|
105
171
|
}
|
|
106
172
|
await this.pushFailed(error, {
|
|
107
173
|
failedStep: stepName,
|
|
@@ -111,7 +177,7 @@ var ApifyKit = {
|
|
|
111
177
|
screenshotBase64
|
|
112
178
|
});
|
|
113
179
|
if (failActor) {
|
|
114
|
-
await
|
|
180
|
+
await Actor.fail(`Run Step ${stepName} \u5931\u8D25: ${error.message}`);
|
|
115
181
|
} else {
|
|
116
182
|
throw error;
|
|
117
183
|
}
|
|
@@ -128,7 +194,7 @@ var ApifyKit = {
|
|
|
128
194
|
* @param {Object} data - 要推送的数据对象
|
|
129
195
|
*/
|
|
130
196
|
async pushSuccess(data) {
|
|
131
|
-
await
|
|
197
|
+
await Actor.pushData({
|
|
132
198
|
code: StatusCode.Success,
|
|
133
199
|
status: Status.Success,
|
|
134
200
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -142,7 +208,7 @@ var ApifyKit = {
|
|
|
142
208
|
* @private
|
|
143
209
|
*/
|
|
144
210
|
async pushFailed(error, meta = {}) {
|
|
145
|
-
await
|
|
211
|
+
await Actor.pushData({
|
|
146
212
|
code: StatusCode.Failed,
|
|
147
213
|
status: Status.Failed,
|
|
148
214
|
// 这里可能带其他错误信息
|
|
@@ -177,7 +243,6 @@ var Utils = {
|
|
|
177
243
|
};
|
|
178
244
|
|
|
179
245
|
// src/stealth.js
|
|
180
|
-
var import_crawlee2 = require("crawlee");
|
|
181
246
|
var Stealth = {
|
|
182
247
|
/**
|
|
183
248
|
* 关键修复:将 Page 视口调整为与浏览器指纹 (window.screen) 一致。
|
|
@@ -196,9 +261,9 @@ var Stealth = {
|
|
|
196
261
|
width: screen.width,
|
|
197
262
|
height: screen.height
|
|
198
263
|
});
|
|
199
|
-
|
|
264
|
+
log.info(`[Stealth] Viewport synced to fingerprint: ${screen.width}x${screen.height}`);
|
|
200
265
|
} catch (e) {
|
|
201
|
-
|
|
266
|
+
log.warning(`[Stealth] Failed to sync viewport: ${e.message}. Fallback to 1920x1080.`);
|
|
202
267
|
await page.setViewportSize({ width: 1920, height: 1080 });
|
|
203
268
|
}
|
|
204
269
|
},
|
|
@@ -247,7 +312,6 @@ var Stealth = {
|
|
|
247
312
|
|
|
248
313
|
// src/humanize.js
|
|
249
314
|
var import_delay = __toESM(require("delay"), 1);
|
|
250
|
-
var import_crawlee3 = require("crawlee");
|
|
251
315
|
var Humanize = {
|
|
252
316
|
/**
|
|
253
317
|
* 随机延迟一段毫秒数 (API Wrapper for 'delay' package)
|
|
@@ -301,13 +365,11 @@ var Launch = {
|
|
|
301
365
|
|
|
302
366
|
// src/live-view.js
|
|
303
367
|
var import_express = __toESM(require("express"), 1);
|
|
304
|
-
var import_crawlee4 = require("crawlee");
|
|
305
|
-
var import_apify2 = require("apify");
|
|
306
368
|
async function startLiveViewServer(liveViewKey) {
|
|
307
369
|
const app = (0, import_express.default)();
|
|
308
370
|
app.get("/", async (req, res) => {
|
|
309
371
|
try {
|
|
310
|
-
const screenshotBuffer = await
|
|
372
|
+
const screenshotBuffer = await Actor.getValue(liveViewKey);
|
|
311
373
|
if (!screenshotBuffer) {
|
|
312
374
|
res.send('<html><head><meta http-equiv="refresh" content="2"></head><body>\u7B49\u5F85\u7B2C\u4E00\u4E2A\u5C4F\u5E55\u622A\u56FE...</body></html>');
|
|
313
375
|
return;
|
|
@@ -327,24 +389,24 @@ async function startLiveViewServer(liveViewKey) {
|
|
|
327
389
|
</html>
|
|
328
390
|
`);
|
|
329
391
|
} catch (error) {
|
|
330
|
-
|
|
392
|
+
log.error(`Live View \u670D\u52A1\u5668\u9519\u8BEF: ${error.message}`);
|
|
331
393
|
res.status(500).send(`\u65E0\u6CD5\u52A0\u8F7D\u5C4F\u5E55\u622A\u56FE: ${error.message}`);
|
|
332
394
|
}
|
|
333
395
|
});
|
|
334
396
|
const port = process.env.APIFY_CONTAINER_PORT || 4321;
|
|
335
397
|
app.listen(port, () => {
|
|
336
|
-
|
|
398
|
+
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`);
|
|
337
399
|
});
|
|
338
400
|
}
|
|
339
401
|
async function takeLiveScreenshot(liveViewKey, page, logMessage) {
|
|
340
402
|
try {
|
|
341
403
|
const buffer = await page.screenshot({ type: "png" });
|
|
342
|
-
await
|
|
404
|
+
await Actor.setValue(liveViewKey, buffer, { contentType: "image/png" });
|
|
343
405
|
if (logMessage) {
|
|
344
|
-
|
|
406
|
+
log.info(`(\u622A\u56FE): ${logMessage}`);
|
|
345
407
|
}
|
|
346
408
|
} catch (e) {
|
|
347
|
-
|
|
409
|
+
log.warning(`\u65E0\u6CD5\u6355\u83B7 Live View \u5C4F\u5E55\u622A\u56FE: ${e.message}`);
|
|
348
410
|
}
|
|
349
411
|
}
|
|
350
412
|
var useLiveView = (liveViewKey = PresetOfLiveViewKey) => {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../index.js", "../src/
|
|
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 { Actor } from 'apify';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants.js';\n\nexport const ApifyKit = {\n\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", "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 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 ? delay.range(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 delay.range(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": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../index.js", "../src/optional-deps.js", "../src/constants.js", "../src/apify-kit.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", "/**\n * \u53EF\u9009\u4F9D\u8D56\u52A0\u8F7D\u6A21\u5757\n * \u7528\u4E8E\u5904\u7406 apify \u548C crawlee \u7684\u6761\u4EF6\u5BFC\u5165\uFF0C\u652F\u6301\u672C\u5730\u548C Apify \u73AF\u5883\n */\n\n// ============ Crawlee Log \u964D\u7EA7\u65B9\u6848 ============\nlet crawleeLog;\n\nasync function loadCrawlee() {\n if (crawleeLog) return crawleeLog;\n\n try {\n const crawlee = await import('crawlee');\n crawleeLog = crawlee.log;\n } catch (e) {\n // \u5982\u679C crawlee \u672A\u5B89\u88C5\uFF0C\u4F7F\u7528 console.log \u964D\u7EA7\n crawleeLog = {\n info: (...args) => console.log('[INFO]', ...args),\n warning: (...args) => console.warn('[WARNING]', ...args),\n error: (...args) => console.error('[ERROR]', ...args),\n debug: (...args) => console.debug('[DEBUG]', ...args),\n };\n }\n return crawleeLog;\n}\n\n// \u540C\u6B65\u4EE3\u7406\uFF0C\u5EF6\u8FDF\u52A0\u8F7D\nexport const log = new Proxy({}, {\n get(target, prop) {\n return (...args) => {\n return loadCrawlee().then(logger => {\n if (typeof logger[prop] === 'function') {\n return logger[prop](...args);\n }\n return logger[prop];\n });\n };\n }\n});\n\n// ============ Apify Actor \u964D\u7EA7\u65B9\u6848 ============\nlet ApifyActor;\nlet isApifyAvailable = false;\n\nasync function loadApify() {\n if (ApifyActor) return { Actor: ApifyActor, isApifyAvailable };\n\n try {\n const apify = await import('apify');\n ApifyActor = apify.Actor;\n isApifyAvailable = true;\n } catch (e) {\n // \u5982\u679C apify \u672A\u5B89\u88C5\uFF0C\u63D0\u4F9B\u964D\u7EA7\u5B9E\u73B0\n ApifyActor = {\n // \u57FA\u7840\u65B9\u6CD5\u8FD4\u56DE null \u6216\u7A7A\u64CD\u4F5C\n getValue: async () => null,\n setValue: async () => { },\n pushData: async (data) => {\n console.log('[APIFY_STUB] pushData called:', data);\n },\n isAtHome: () => false,\n fail: async (message) => {\n throw new Error(message);\n },\n\n // \u964D\u7EA7\u63D0\u793A\n _isStub: true,\n };\n isApifyAvailable = false;\n }\n\n return { Actor: ApifyActor, isApifyAvailable };\n}\n\n// \u540C\u6B65\u4EE3\u7406\uFF0C\u5EF6\u8FDF\u52A0\u8F7D\nexport const Actor = new Proxy({}, {\n get(target, prop) {\n return (...args) => {\n return loadApify().then(({ Actor }) => {\n if (typeof Actor[prop] === 'function') {\n return Actor[prop](...args);\n }\n return Actor[prop];\n });\n };\n }\n});\n\nexport { isApifyAvailable };\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", "import { log, Actor } from './optional-deps.js';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants.js';\n\nexport const ApifyKit = {\n\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", "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 './optional-deps.js';\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 from 'delay';\nimport { log } from './optional-deps.js';\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 ? delay.range(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 delay.range(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, Actor } from './optional-deps.js';\nimport { PresetOfLiveViewKey } from './constants.js';\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", "delay", "express"]
|
|
7
7
|
}
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,75 @@ var __export = (target, all) => {
|
|
|
4
4
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
-
// src/
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
// src/optional-deps.js
|
|
8
|
+
var crawleeLog;
|
|
9
|
+
async function loadCrawlee() {
|
|
10
|
+
if (crawleeLog) return crawleeLog;
|
|
11
|
+
try {
|
|
12
|
+
const crawlee = await import("crawlee");
|
|
13
|
+
crawleeLog = crawlee.log;
|
|
14
|
+
} catch (e) {
|
|
15
|
+
crawleeLog = {
|
|
16
|
+
info: (...args) => console.log("[INFO]", ...args),
|
|
17
|
+
warning: (...args) => console.warn("[WARNING]", ...args),
|
|
18
|
+
error: (...args) => console.error("[ERROR]", ...args),
|
|
19
|
+
debug: (...args) => console.debug("[DEBUG]", ...args)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return crawleeLog;
|
|
23
|
+
}
|
|
24
|
+
var log = new Proxy({}, {
|
|
25
|
+
get(target, prop) {
|
|
26
|
+
return (...args) => {
|
|
27
|
+
return loadCrawlee().then((logger) => {
|
|
28
|
+
if (typeof logger[prop] === "function") {
|
|
29
|
+
return logger[prop](...args);
|
|
30
|
+
}
|
|
31
|
+
return logger[prop];
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
var ApifyActor;
|
|
37
|
+
var isApifyAvailable = false;
|
|
38
|
+
async function loadApify() {
|
|
39
|
+
if (ApifyActor) return { Actor: ApifyActor, isApifyAvailable };
|
|
40
|
+
try {
|
|
41
|
+
const apify = await import("apify");
|
|
42
|
+
ApifyActor = apify.Actor;
|
|
43
|
+
isApifyAvailable = true;
|
|
44
|
+
} catch (e) {
|
|
45
|
+
ApifyActor = {
|
|
46
|
+
// 基础方法返回 null 或空操作
|
|
47
|
+
getValue: async () => null,
|
|
48
|
+
setValue: async () => {
|
|
49
|
+
},
|
|
50
|
+
pushData: async (data) => {
|
|
51
|
+
console.log("[APIFY_STUB] pushData called:", data);
|
|
52
|
+
},
|
|
53
|
+
isAtHome: () => false,
|
|
54
|
+
fail: async (message) => {
|
|
55
|
+
throw new Error(message);
|
|
56
|
+
},
|
|
57
|
+
// 降级提示
|
|
58
|
+
_isStub: true
|
|
59
|
+
};
|
|
60
|
+
isApifyAvailable = false;
|
|
61
|
+
}
|
|
62
|
+
return { Actor: ApifyActor, isApifyAvailable };
|
|
63
|
+
}
|
|
64
|
+
var Actor = new Proxy({}, {
|
|
65
|
+
get(target, prop) {
|
|
66
|
+
return (...args) => {
|
|
67
|
+
return loadApify().then(({ Actor: Actor2 }) => {
|
|
68
|
+
if (typeof Actor2[prop] === "function") {
|
|
69
|
+
return Actor2[prop](...args);
|
|
70
|
+
}
|
|
71
|
+
return Actor2[prop];
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
});
|
|
10
76
|
|
|
11
77
|
// src/constants.js
|
|
12
78
|
var constants_exports = {};
|
|
@@ -148,7 +214,6 @@ var Utils = {
|
|
|
148
214
|
};
|
|
149
215
|
|
|
150
216
|
// src/stealth.js
|
|
151
|
-
import { log as log2 } from "crawlee";
|
|
152
217
|
var Stealth = {
|
|
153
218
|
/**
|
|
154
219
|
* 关键修复:将 Page 视口调整为与浏览器指纹 (window.screen) 一致。
|
|
@@ -167,9 +232,9 @@ var Stealth = {
|
|
|
167
232
|
width: screen.width,
|
|
168
233
|
height: screen.height
|
|
169
234
|
});
|
|
170
|
-
|
|
235
|
+
log.info(`[Stealth] Viewport synced to fingerprint: ${screen.width}x${screen.height}`);
|
|
171
236
|
} catch (e) {
|
|
172
|
-
|
|
237
|
+
log.warning(`[Stealth] Failed to sync viewport: ${e.message}. Fallback to 1920x1080.`);
|
|
173
238
|
await page.setViewportSize({ width: 1920, height: 1080 });
|
|
174
239
|
}
|
|
175
240
|
},
|
|
@@ -218,7 +283,6 @@ var Stealth = {
|
|
|
218
283
|
|
|
219
284
|
// src/humanize.js
|
|
220
285
|
import delay from "delay";
|
|
221
|
-
import { log as log3 } from "crawlee";
|
|
222
286
|
var Humanize = {
|
|
223
287
|
/**
|
|
224
288
|
* 随机延迟一段毫秒数 (API Wrapper for 'delay' package)
|
|
@@ -272,13 +336,11 @@ var Launch = {
|
|
|
272
336
|
|
|
273
337
|
// src/live-view.js
|
|
274
338
|
import express from "express";
|
|
275
|
-
import { log as log4 } from "crawlee";
|
|
276
|
-
import { Actor as Actor2 } from "apify";
|
|
277
339
|
async function startLiveViewServer(liveViewKey) {
|
|
278
340
|
const app = express();
|
|
279
341
|
app.get("/", async (req, res) => {
|
|
280
342
|
try {
|
|
281
|
-
const screenshotBuffer = await
|
|
343
|
+
const screenshotBuffer = await Actor.getValue(liveViewKey);
|
|
282
344
|
if (!screenshotBuffer) {
|
|
283
345
|
res.send('<html><head><meta http-equiv="refresh" content="2"></head><body>\u7B49\u5F85\u7B2C\u4E00\u4E2A\u5C4F\u5E55\u622A\u56FE...</body></html>');
|
|
284
346
|
return;
|
|
@@ -298,24 +360,24 @@ async function startLiveViewServer(liveViewKey) {
|
|
|
298
360
|
</html>
|
|
299
361
|
`);
|
|
300
362
|
} catch (error) {
|
|
301
|
-
|
|
363
|
+
log.error(`Live View \u670D\u52A1\u5668\u9519\u8BEF: ${error.message}`);
|
|
302
364
|
res.status(500).send(`\u65E0\u6CD5\u52A0\u8F7D\u5C4F\u5E55\u622A\u56FE: ${error.message}`);
|
|
303
365
|
}
|
|
304
366
|
});
|
|
305
367
|
const port = process.env.APIFY_CONTAINER_PORT || 4321;
|
|
306
368
|
app.listen(port, () => {
|
|
307
|
-
|
|
369
|
+
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`);
|
|
308
370
|
});
|
|
309
371
|
}
|
|
310
372
|
async function takeLiveScreenshot(liveViewKey, page, logMessage) {
|
|
311
373
|
try {
|
|
312
374
|
const buffer = await page.screenshot({ type: "png" });
|
|
313
|
-
await
|
|
375
|
+
await Actor.setValue(liveViewKey, buffer, { contentType: "image/png" });
|
|
314
376
|
if (logMessage) {
|
|
315
|
-
|
|
377
|
+
log.info(`(\u622A\u56FE): ${logMessage}`);
|
|
316
378
|
}
|
|
317
379
|
} catch (e) {
|
|
318
|
-
|
|
380
|
+
log.warning(`\u65E0\u6CD5\u6355\u83B7 Live View \u5C4F\u5E55\u622A\u56FE: ${e.message}`);
|
|
319
381
|
}
|
|
320
382
|
}
|
|
321
383
|
var useLiveView = (liveViewKey = PresetOfLiveViewKey) => {
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/
|
|
4
|
-
"sourcesContent": ["import { log } from 'crawlee';\nimport { Actor } from 'apify';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants.js';\n\nexport const ApifyKit = {\n\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", "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 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 ? delay.range(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 delay.range(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": ";;;;;;;AAAA,SAAS,WAAW;
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../src/optional-deps.js", "../src/constants.js", "../src/apify-kit.js", "../src/utils.js", "../src/stealth.js", "../src/humanize.js", "../src/launch.js", "../src/live-view.js", "../index.js"],
|
|
4
|
+
"sourcesContent": ["/**\n * \u53EF\u9009\u4F9D\u8D56\u52A0\u8F7D\u6A21\u5757\n * \u7528\u4E8E\u5904\u7406 apify \u548C crawlee \u7684\u6761\u4EF6\u5BFC\u5165\uFF0C\u652F\u6301\u672C\u5730\u548C Apify \u73AF\u5883\n */\n\n// ============ Crawlee Log \u964D\u7EA7\u65B9\u6848 ============\nlet crawleeLog;\n\nasync function loadCrawlee() {\n if (crawleeLog) return crawleeLog;\n\n try {\n const crawlee = await import('crawlee');\n crawleeLog = crawlee.log;\n } catch (e) {\n // \u5982\u679C crawlee \u672A\u5B89\u88C5\uFF0C\u4F7F\u7528 console.log \u964D\u7EA7\n crawleeLog = {\n info: (...args) => console.log('[INFO]', ...args),\n warning: (...args) => console.warn('[WARNING]', ...args),\n error: (...args) => console.error('[ERROR]', ...args),\n debug: (...args) => console.debug('[DEBUG]', ...args),\n };\n }\n return crawleeLog;\n}\n\n// \u540C\u6B65\u4EE3\u7406\uFF0C\u5EF6\u8FDF\u52A0\u8F7D\nexport const log = new Proxy({}, {\n get(target, prop) {\n return (...args) => {\n return loadCrawlee().then(logger => {\n if (typeof logger[prop] === 'function') {\n return logger[prop](...args);\n }\n return logger[prop];\n });\n };\n }\n});\n\n// ============ Apify Actor \u964D\u7EA7\u65B9\u6848 ============\nlet ApifyActor;\nlet isApifyAvailable = false;\n\nasync function loadApify() {\n if (ApifyActor) return { Actor: ApifyActor, isApifyAvailable };\n\n try {\n const apify = await import('apify');\n ApifyActor = apify.Actor;\n isApifyAvailable = true;\n } catch (e) {\n // \u5982\u679C apify \u672A\u5B89\u88C5\uFF0C\u63D0\u4F9B\u964D\u7EA7\u5B9E\u73B0\n ApifyActor = {\n // \u57FA\u7840\u65B9\u6CD5\u8FD4\u56DE null \u6216\u7A7A\u64CD\u4F5C\n getValue: async () => null,\n setValue: async () => { },\n pushData: async (data) => {\n console.log('[APIFY_STUB] pushData called:', data);\n },\n isAtHome: () => false,\n fail: async (message) => {\n throw new Error(message);\n },\n\n // \u964D\u7EA7\u63D0\u793A\n _isStub: true,\n };\n isApifyAvailable = false;\n }\n\n return { Actor: ApifyActor, isApifyAvailable };\n}\n\n// \u540C\u6B65\u4EE3\u7406\uFF0C\u5EF6\u8FDF\u52A0\u8F7D\nexport const Actor = new Proxy({}, {\n get(target, prop) {\n return (...args) => {\n return loadApify().then(({ Actor }) => {\n if (typeof Actor[prop] === 'function') {\n return Actor[prop](...args);\n }\n return Actor[prop];\n });\n };\n }\n});\n\nexport { isApifyAvailable };\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", "import { log, Actor } from './optional-deps.js';\nimport { Status, FAILED_KEY_SEPARATOR, StatusCode } from './constants.js';\n\nexport const ApifyKit = {\n\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", "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 './optional-deps.js';\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 from 'delay';\nimport { log } from './optional-deps.js';\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 ? delay.range(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 delay.range(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, Actor } from './optional-deps.js';\nimport { PresetOfLiveViewKey } from './constants.js';\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": ";;;;;;;AAMA,IAAI;AAEJ,eAAe,cAAc;AACzB,MAAI,WAAY,QAAO;AAEvB,MAAI;AACA,UAAM,UAAU,MAAM,OAAO,SAAS;AACtC,iBAAa,QAAQ;AAAA,EACzB,SAAS,GAAG;AAER,iBAAa;AAAA,MACT,MAAM,IAAI,SAAS,QAAQ,IAAI,UAAU,GAAG,IAAI;AAAA,MAChD,SAAS,IAAI,SAAS,QAAQ,KAAK,aAAa,GAAG,IAAI;AAAA,MACvD,OAAO,IAAI,SAAS,QAAQ,MAAM,WAAW,GAAG,IAAI;AAAA,MACpD,OAAO,IAAI,SAAS,QAAQ,MAAM,WAAW,GAAG,IAAI;AAAA,IACxD;AAAA,EACJ;AACA,SAAO;AACX;AAGO,IAAM,MAAM,IAAI,MAAM,CAAC,GAAG;AAAA,EAC7B,IAAI,QAAQ,MAAM;AACd,WAAO,IAAI,SAAS;AAChB,aAAO,YAAY,EAAE,KAAK,YAAU;AAChC,YAAI,OAAO,OAAO,IAAI,MAAM,YAAY;AACpC,iBAAO,OAAO,IAAI,EAAE,GAAG,IAAI;AAAA,QAC/B;AACA,eAAO,OAAO,IAAI;AAAA,MACtB,CAAC;AAAA,IACL;AAAA,EACJ;AACJ,CAAC;AAGD,IAAI;AACJ,IAAI,mBAAmB;AAEvB,eAAe,YAAY;AACvB,MAAI,WAAY,QAAO,EAAE,OAAO,YAAY,iBAAiB;AAE7D,MAAI;AACA,UAAM,QAAQ,MAAM,OAAO,OAAO;AAClC,iBAAa,MAAM;AACnB,uBAAmB;AAAA,EACvB,SAAS,GAAG;AAER,iBAAa;AAAA;AAAA,MAET,UAAU,YAAY;AAAA,MACtB,UAAU,YAAY;AAAA,MAAE;AAAA,MACxB,UAAU,OAAO,SAAS;AACtB,gBAAQ,IAAI,iCAAiC,IAAI;AAAA,MACrD;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,MAAM,OAAO,YAAY;AACrB,cAAM,IAAI,MAAM,OAAO;AAAA,MAC3B;AAAA;AAAA,MAGA,SAAS;AAAA,IACb;AACA,uBAAmB;AAAA,EACvB;AAEA,SAAO,EAAE,OAAO,YAAY,iBAAiB;AACjD;AAGO,IAAM,QAAQ,IAAI,MAAM,CAAC,GAAG;AAAA,EAC/B,IAAI,QAAQ,MAAM;AACd,WAAO,IAAI,SAAS;AAChB,aAAO,UAAU,EAAE,KAAK,CAAC,EAAE,OAAAA,OAAM,MAAM;AACnC,YAAI,OAAOA,OAAM,IAAI,MAAM,YAAY;AACnC,iBAAOA,OAAM,IAAI,EAAE,GAAG,IAAI;AAAA,QAC9B;AACA,eAAOA,OAAM,IAAI;AAAA,MACrB,CAAC;AAAA,IACL;AAAA,EACJ;AACJ,CAAC;;;ACtFD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,IAAM,cAAc;AAAA,EACvB,UAAU;AAAA,EACV,UAAU;AACd;AAEO,IAAM,SAAS;AAAA,EAClB,SAAS;AAAA,EACT,QAAQ;AACZ;AAEO,IAAM,aAAa;AAAA,EACtB,SAAS;AAAA,EACT,QAAQ;AACZ;AAEO,IAAM,uBAAuB;AAE7B,IAAM,sBAAsB;;;ACd5B,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA,EAKpB,0BAA0B,KAAK,UAAU;AACrC,WAAO,GAAG,GAAG,GAAG,oBAAoB,GAAG,QAAQ;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,UAAU;AACrB,UAAM,aAAa,SAAS,QAAQ,oBAAoB;AACxD,QAAI,eAAe,IAAI;AACnB,aAAO,CAAC,KAAK,QAAQ;AAAA,IACzB;AACA,UAAM,MAAM,SAAS,UAAU,GAAG,UAAU;AAC5C,UAAM,QAAQ,SAAS,UAAU,aAAa,qBAAqB,MAAM;AACzE,WAAO,CAAC,KAAK,KAAK;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,iBAAiB,MAAM,UAAU,UAAU,CAAC,GAAG;AACzD,UAAM,EAAE,YAAY,KAAK,IAAI;AAC7B,UAAM,CAAC,WAAW,QAAQ,IAAI,KAAK,eAAe,eAAe;AAEjE,QAAI,KAAK,wCAAa,QAAQ,KAAK;AAEnC,QAAI;AACA,YAAM,SAAS,MAAM,SAAS;AAC9B,UAAI,KAAK,qCAAY,QAAQ,EAAE;AAC/B,aAAO;AAAA,IACX,SAAS,OAAO;AACZ,UAAI,MAAM,qCAAY,QAAQ,KAAK,MAAM,OAAO,EAAE;AAElD,UAAI,mBAAmB;AACvB,UAAI;AACA,YAAI,MAAM;AACN,gBAAM,SAAS,MAAM,KAAK,WAAW,EAAE,UAAU,MAAM,MAAM,QAAQ,SAAS,GAAG,CAAC;AAClF,6BAAmB,0BAA0B,OAAO,SAAS,QAAQ,CAAC;AAAA,QAC1E;AAAA,MACJ,SAAS,SAAS;AACd,YAAI,QAAQ,yCAAW,QAAQ,OAAO,EAAE;AAAA,MAC5C;AAGA,YAAM,KAAK,WAAW,OAAO;AAAA,QACzB,YAAY;AAAA,QACZ;AAAA,QACA,cAAc,MAAM;AAAA,QACpB,YAAY,MAAM;AAAA,QAClB;AAAA,MACJ,CAAC;AAGD,UAAI,WAAW;AACX,cAAM,MAAM,KAAK,YAAY,QAAQ,kBAAQ,MAAM,OAAO,EAAE;AAAA,MAChE,OAAO;AAEH,cAAM;AAAA,MACV;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,UAAU,MAAM,IAAI;AACnC,WAAO,MAAM,KAAK,QAAQ,UAAU,MAAM,IAAI,EAAE,WAAW,MAAM,CAAC;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,MAAM;AACpB,UAAM,MAAM,SAAS;AAAA,MACjB,MAAM,WAAW;AAAA,MACjB,QAAQ,OAAO;AAAA,MACf,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,GAAG;AAAA,IACP,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,WAAW,OAAO,OAAO,CAAC,GAAG;AAC/B,UAAM,MAAM,SAAS;AAAA,MACjB,MAAM,WAAW;AAAA,MACjB,QAAQ,OAAO;AAAA;AAAA,MAEf;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,GAAG;AAAA,IACP,CAAC;AAAA,EACL;AACJ;;;AC1GO,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIjB,eAAe,eAAe;AAC1B,UAAM,SAAS,CAAC;AAChB,UAAM,QAAQ,cAAc,MAAM,IAAI;AACtC,eAAW,QAAQ,OAAO;AACtB,UAAI,KAAK,WAAW,QAAQ,GAAG;AAC3B,YAAI;AACA,gBAAM,cAAc,KAAK,UAAU,CAAC,EAAE,KAAK;AAC3C,cAAI,eAAe,gBAAgB,UAAU;AACzC,mBAAO,KAAK,KAAK,MAAM,WAAW,CAAC;AAAA,UACvC;AAAA,QACJ,SAAS,GAAG;AAAA,QAEZ;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AACJ;;;ACnBO,IAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMnB,MAAM,uBAAuB,MAAM;AAC/B,QAAI;AAEA,YAAM,SAAS,MAAM,KAAK,SAAS,OAAO;AAAA,QACtC,OAAO,OAAO,OAAO;AAAA,QACrB,QAAQ,OAAO,OAAO;AAAA,QACtB,YAAY,OAAO,OAAO;AAAA,QAC1B,aAAa,OAAO,OAAO;AAAA,MAC/B,EAAE;AAGF,YAAM,KAAK,gBAAgB;AAAA,QACvB,OAAO,OAAO;AAAA,QACd,QAAQ,OAAO;AAAA,MACnB,CAAC;AAED,UAAI,KAAK,6CAA6C,OAAO,KAAK,IAAI,OAAO,MAAM,EAAE;AAAA,IACzF,SAAS,GAAG;AACR,UAAI,QAAQ,sCAAsC,EAAE,OAAO,0BAA0B;AACrF,YAAM,KAAK,gBAAgB,EAAE,OAAO,MAAM,QAAQ,KAAK,CAAC;AAAA,IAC5D;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,MAAM;AACtB,UAAM,KAAK,cAAc,MAAM;AAC3B,aAAO,eAAe,WAAW,aAAa;AAAA,QAC1C,KAAK,MAAM;AAAA,MACf,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,uBAAuB,MAAM,gBAAgB,CAAC,QAAQ,SAAS,OAAO,GAAG;AAC3E,UAAM,KAAK,MAAM,QAAQ,CAAC,UAAU;AAChC,YAAM,UAAU,MAAM,QAAQ;AAC9B,YAAM,OAAO,QAAQ,aAAa;AAClC,UAAI,cAAc,SAAS,IAAI,GAAG;AAC9B,eAAO,MAAM,MAAM;AAAA,MACvB;AACA,aAAO,MAAM,SAAS;AAAA,IAC1B,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAuB;AACnB,WAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA;AAAA,IAGJ;AAAA,EACJ;AACJ;;;AC1EA,OAAO,WAAW;AAGX,IAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMpB,MAAM,YAAY,KAAK,KAAK;AACxB,UAAM,KAAK,OAAO,QAAQ,WACpB,MAAM,MAAM,KAAK,GAAG,IACpB,MAAM,GAAG;AAMf,UAAM;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAAa,QAAQ,aAAa,KAAM;AAC1C,UAAM,YAAY,KAAK,IAAI;AAC3B,WAAO,KAAK,IAAI,IAAI,YAAY,YAAY;AAExC,YAAM,IAAI,KAAK,OAAO,IAAI;AAC1B,YAAM,IAAI,KAAK,OAAO,IAAI;AAC1B,YAAM,OAAO,OAAO,EAAE,GAAG,EAAE,CAAC;AAC5B,YAAM,MAAM,MAAM,KAAK,GAAG;AAAA,IAC9B;AAAA,EACJ;AACJ;;;ACjCO,IAAM,SAAS;AAAA,EAClB,iBAAiB,aAAa,CAAC,GAAG;AAC9B,WAAO;AAAA,MACH,MAAM;AAAA,QACF,GAAG,QAAQ,qBAAqB;AAAA,QAChC,GAAG;AAAA,MACP;AAAA,MACA,mBAAmB,CAAC,qBAAqB;AAAA,IAC7C;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iCAAiC;AAC7B,WAAO;AAAA,MACH,UAAU,CAAC,EAAE,MAAM,UAAU,YAAY,IAAI,CAAC;AAAA,MAC9C,SAAS,CAAC,SAAS;AAAA,MACnB,kBAAkB,CAAC,WAAW,OAAO;AAAA;AAAA,IACzC;AAAA,EACJ;AACJ;;;ACzBA,OAAO,aAAa;AAOpB,eAAe,oBAAoB,aAAa;AAC5C,QAAM,MAAM,QAAQ;AAEpB,MAAI,IAAI,KAAK,OAAO,KAAK,QAAQ;AAC7B,QAAI;AAEA,YAAM,mBAAmB,MAAM,MAAM,SAAS,WAAW;AAEzD,UAAI,CAAC,kBAAkB;AAEnB,YAAI,KAAK,yIAA4F;AACrG;AAAA,MACJ;AAGA,YAAM,mBAAmB,iBAAiB,SAAS,QAAQ;AAG3D,UAAI,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0DAOqC,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA,aAK7D;AAAA,IACL,SAAS,OAAO;AACZ,UAAI,MAAM,6CAAoB,MAAM,OAAO,EAAE;AAC7C,UAAI,OAAO,GAAG,EAAE,KAAK,qDAAa,MAAM,OAAO,EAAE;AAAA,IACrD;AAAA,EACJ,CAAC;AAGD,QAAM,OAAO,QAAQ,IAAI,wBAAwB;AACjD,MAAI,OAAO,MAAM,MAAM;AAAE,QAAI,KAAK,gFAAyB,IAAI,2EAAyB;AAAA,EAAG,CAAC;AAChG;AAOA,eAAe,mBAAmB,aAAa,MAAM,YAAY;AAC7D,MAAI;AACA,UAAM,SAAS,MAAM,KAAK,WAAW,EAAE,MAAM,MAAM,CAAC;AACpD,UAAM,MAAM,SAAS,aAAa,QAAQ,EAAE,aAAa,YAAY,CAAC;AACtE,QAAI,YAAY;AACZ,UAAI,KAAK,mBAAS,UAAU,EAAE;AAAA,IAClC;AAAA,EACJ,SAAS,GAAG;AACR,QAAI,QAAQ,gEAAwB,EAAE,OAAO,EAAE;AAAA,EACnD;AACJ;AAEA,IAAM,cAAc,CAAC,cAAc,wBAAwB;AACvD,SAAO;AAAA,IACH,oBAAoB,OAAO,MAAM,eAAe;AAC5C,aAAO,MAAM,mBAAmB,aAAa,MAAM,UAAU;AAAA,IACjE;AAAA,IACA,qBAAqB,YAAY;AAC7B,aAAO,MAAM,oBAAoB,WAAW;AAAA,IAChD;AAAA,EACJ;AACJ;AAEO,IAAM,WAAW;AAAA,EACpB;AACJ;;;ACtEO,IAAM,uBAAuB,MAAM;AACtC,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ;AACJ;",
|
|
6
|
+
"names": ["Actor"]
|
|
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.4",
|
|
4
4
|
"description": "一个在 Apify/Crawlee Actor 中启用实时截图视图的实用工具库。",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -36,10 +36,16 @@
|
|
|
36
36
|
"express": "^4.18.2"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"apify": "*",
|
|
40
|
-
"crawlee": "*",
|
|
41
39
|
"playwright": "*"
|
|
42
40
|
},
|
|
41
|
+
"peerDependenciesMeta": {
|
|
42
|
+
"apify": {
|
|
43
|
+
"optional": true
|
|
44
|
+
},
|
|
45
|
+
"crawlee": {
|
|
46
|
+
"optional": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
43
49
|
"devDependencies": {
|
|
44
50
|
"esbuild": "^0.24.2"
|
|
45
51
|
}
|