@skrillex1224/playwright-toolkit 2.1.37 → 2.1.39
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 +420 -26
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +420 -26
- package/dist/index.js.map +4 -4
- package/index.d.ts +121 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -57,10 +57,220 @@ var Status = {
|
|
|
57
57
|
var FAILED_KEY_SEPARATOR = "::<@>::";
|
|
58
58
|
var PresetOfLiveViewKey = "LIVE_VIEW_SCREENSHOT";
|
|
59
59
|
|
|
60
|
-
// src/
|
|
60
|
+
// src/logger.js
|
|
61
61
|
var import_crawlee = require("crawlee");
|
|
62
|
+
var formatLine = (prefix, icon, message) => {
|
|
63
|
+
const parts = [];
|
|
64
|
+
if (prefix) parts.push(`[${prefix}]`);
|
|
65
|
+
if (icon) parts.push(icon);
|
|
66
|
+
if (message) parts.push(message);
|
|
67
|
+
return parts.join(" ").trim();
|
|
68
|
+
};
|
|
69
|
+
var ANSI = {
|
|
70
|
+
reset: "\x1B[0m",
|
|
71
|
+
gray: "\x1B[90m",
|
|
72
|
+
red: "\x1B[31m",
|
|
73
|
+
green: "\x1B[32m",
|
|
74
|
+
yellow: "\x1B[33m",
|
|
75
|
+
blue: "\x1B[34m",
|
|
76
|
+
cyan: "\x1B[36m"
|
|
77
|
+
};
|
|
78
|
+
var colorize = (text, color) => {
|
|
79
|
+
if (!text || !color) return text;
|
|
80
|
+
return `${color}${text}${ANSI.reset}`;
|
|
81
|
+
};
|
|
82
|
+
var createBaseLogger = (prefix = "") => {
|
|
83
|
+
const name = prefix ? String(prefix) : "";
|
|
84
|
+
return {
|
|
85
|
+
info: (message) => import_crawlee.log.info(colorize(formatLine(name, "\u{1F4D6}", message), ANSI.cyan)),
|
|
86
|
+
success: (message) => import_crawlee.log.info(colorize(formatLine(name, "\u2705", message), ANSI.green)),
|
|
87
|
+
warning: (message) => import_crawlee.log.warning(colorize(formatLine(name, "\u26A0\uFE0F", message), ANSI.yellow)),
|
|
88
|
+
error: (message) => import_crawlee.log.error(colorize(formatLine(name, "\u274C", message), ANSI.red)),
|
|
89
|
+
debug: (message) => import_crawlee.log.debug(colorize(formatLine(name, "\u{1F539}", message), ANSI.gray)),
|
|
90
|
+
start: (message) => import_crawlee.log.info(colorize(formatLine(name, "\u{1F537}", message), ANSI.blue))
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
var STEP_PREFIX = "\u6B65\u9AA4:";
|
|
94
|
+
var STEP_SEPARATOR = " | ";
|
|
95
|
+
var STEP_EMOJIS = [
|
|
96
|
+
{ match: "\u4EFB\u52A1", emoji: "\u{1F9ED}" },
|
|
97
|
+
{ match: "\u8FD0\u884C\u6A21\u5F0F", emoji: "\u{1F9E9}" },
|
|
98
|
+
{ match: "\u767B\u5F55", emoji: "\u{1F510}" },
|
|
99
|
+
{ match: "\u73AF\u5883", emoji: "\u{1F9EA}" },
|
|
100
|
+
{ match: "\u8F93\u5165", emoji: "\u2328\uFE0F" },
|
|
101
|
+
{ match: "\u53D1\u9001", emoji: "\u{1F4E4}" },
|
|
102
|
+
{ match: "\u54CD\u5E94\u76D1\u542C", emoji: "\u{1F4E1}" },
|
|
103
|
+
{ match: "\u7B49\u5F85\u54CD\u5E94", emoji: "\u23F3" },
|
|
104
|
+
{ match: "\u6D41\u5F0F", emoji: "\u{1F9F5}" },
|
|
105
|
+
{ match: "\u5F15\u7528", emoji: "\u{1F4CE}" },
|
|
106
|
+
{ match: "\u622A\u56FE", emoji: "\u{1F5BC}\uFE0F" },
|
|
107
|
+
{ match: "\u5206\u4EAB\u94FE\u63A5", emoji: "\u{1F517}" },
|
|
108
|
+
{ match: "\u6570\u636E\u63A8\u9001", emoji: "\u{1F4E6}" },
|
|
109
|
+
{ match: "\u5F39\u7A97", emoji: "\u{1FA9F}" }
|
|
110
|
+
];
|
|
111
|
+
var STATUS_EMOJIS = [
|
|
112
|
+
{ match: "\u5F00\u59CB", emoji: "\u{1F680}" },
|
|
113
|
+
{ match: "\u5B8C\u6210", emoji: "\u2705" },
|
|
114
|
+
{ match: "\u6210\u529F", emoji: "\u2705" },
|
|
115
|
+
{ match: "\u5931\u8D25", emoji: "\u274C" },
|
|
116
|
+
{ match: "\u8DF3\u8FC7", emoji: "\u23ED\uFE0F" },
|
|
117
|
+
{ match: "\u8D85\u65F6", emoji: "\u23F1\uFE0F" },
|
|
118
|
+
{ match: "\u91CD\u8BD5", emoji: "\u{1F501}" },
|
|
119
|
+
{ match: "\u7ED3\u675F", emoji: "\u{1F3C1}" },
|
|
120
|
+
{ match: "\u5DF2\u914D\u7F6E", emoji: "\u{1F9F7}" },
|
|
121
|
+
{ match: "\u5DF2\u68C0\u6D4B", emoji: "\u{1F50E}" }
|
|
122
|
+
];
|
|
123
|
+
var toErrorMessage = (error) => {
|
|
124
|
+
if (!error) return "";
|
|
125
|
+
if (error instanceof Error) return error.message;
|
|
126
|
+
if (typeof error === "string") return error;
|
|
127
|
+
try {
|
|
128
|
+
return JSON.stringify(error);
|
|
129
|
+
} catch {
|
|
130
|
+
return String(error);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
var decorateLabel = (label, mappings) => {
|
|
134
|
+
if (!label) return "";
|
|
135
|
+
const mapping = mappings.find((item) => label.includes(item.match));
|
|
136
|
+
if (!mapping) return label;
|
|
137
|
+
return `${mapping.emoji} ${label}`;
|
|
138
|
+
};
|
|
139
|
+
var normalizeSnippet = (snippet, maxLen = 120) => {
|
|
140
|
+
if (!snippet) return "";
|
|
141
|
+
const text = String(snippet).replace(/\s+/g, " ").trim();
|
|
142
|
+
if (!text) return "";
|
|
143
|
+
const cleaned = text.replace(/"/g, "'");
|
|
144
|
+
if (cleaned.length <= maxLen) return cleaned;
|
|
145
|
+
return `${cleaned.slice(0, maxLen)}...`;
|
|
146
|
+
};
|
|
147
|
+
var buildStepLine = (step, status, details = []) => {
|
|
148
|
+
const parts = [];
|
|
149
|
+
const decoratedStep = step ? decorateLabel(step, STEP_EMOJIS) : "";
|
|
150
|
+
const base = decoratedStep ? `${STEP_PREFIX} ${decoratedStep}` : STEP_PREFIX;
|
|
151
|
+
parts.push(base.trim());
|
|
152
|
+
if (status) parts.push(decorateLabel(status, STATUS_EMOJIS));
|
|
153
|
+
const detailParts = details.filter(Boolean);
|
|
154
|
+
if (detailParts.length > 0) {
|
|
155
|
+
parts.push(...detailParts);
|
|
156
|
+
}
|
|
157
|
+
return parts.join(STEP_SEPARATOR);
|
|
158
|
+
};
|
|
159
|
+
var createThrottle = () => {
|
|
160
|
+
const lastMap = /* @__PURE__ */ new Map();
|
|
161
|
+
return (key, intervalMs, fn) => {
|
|
162
|
+
const now = Date.now();
|
|
163
|
+
const last = lastMap.get(key) || 0;
|
|
164
|
+
if (now - last >= intervalMs) {
|
|
165
|
+
lastMap.set(key, now);
|
|
166
|
+
fn();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
};
|
|
170
|
+
var createTemplateLogger = (baseLogger = createBaseLogger()) => {
|
|
171
|
+
const throttle = createThrottle();
|
|
172
|
+
const info = (line) => baseLogger.info(line);
|
|
173
|
+
const success = (line) => baseLogger.success(line);
|
|
174
|
+
const warning = (line) => baseLogger.warning(line);
|
|
175
|
+
const error = (line) => baseLogger.error(line);
|
|
176
|
+
const debug = (line) => baseLogger.debug(line);
|
|
177
|
+
const start = (line) => baseLogger.start(line);
|
|
178
|
+
const stepInfo = (step, status, details = []) => info(buildStepLine(step, status, details));
|
|
179
|
+
const stepSuccess = (step, status, details = []) => success(buildStepLine(step, status, details));
|
|
180
|
+
const stepWarn = (step, status, details = []) => warning(buildStepLine(step, status, details));
|
|
181
|
+
const stepError = (step, status, details = []) => error(buildStepLine(step, status, details));
|
|
182
|
+
const stepStart = (step, status, details = []) => start(buildStepLine(step, status, details));
|
|
183
|
+
return {
|
|
184
|
+
step: (step, status, details, level = "info") => {
|
|
185
|
+
if (level === "error") return stepError(step, status, details);
|
|
186
|
+
if (level === "warn" || level === "warning") return stepWarn(step, status, details);
|
|
187
|
+
return stepInfo(step, status, details);
|
|
188
|
+
},
|
|
189
|
+
taskStart: (url) => stepStart("\u4EFB\u52A1", "\u5F00\u59CB", [url ? `url=${url}` : ""]),
|
|
190
|
+
taskSuccess: () => stepSuccess("\u4EFB\u52A1", "\u5B8C\u6210"),
|
|
191
|
+
taskFail: (url, err) => stepError("\u4EFB\u52A1", "\u5931\u8D25", [
|
|
192
|
+
url ? `url=${url}` : "",
|
|
193
|
+
err ? `err=${toErrorMessage(err)}` : ""
|
|
194
|
+
]),
|
|
195
|
+
runtimeHeadless: () => stepWarn("\u8FD0\u884C\u6A21\u5F0F", "Apify \u73AF\u5883\u5F3A\u5236\u65E0\u5934"),
|
|
196
|
+
loginInjectSuccess: (detail) => stepSuccess("\u767B\u5F55\u6001\u6CE8\u5165", "\u6210\u529F", [detail ? `detail=${detail}` : ""]),
|
|
197
|
+
loginInjectSkip: (reason) => stepWarn("\u767B\u5F55\u6001\u6CE8\u5165", "\u8DF3\u8FC7", [reason ? `\u539F\u56E0=${reason}` : ""]),
|
|
198
|
+
loginInjectFail: (err) => stepError("\u767B\u5F55\u6001\u6CE8\u5165", "\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
199
|
+
loginVerifySuccess: (detail) => stepSuccess("\u767B\u5F55\u9A8C\u8BC1", "\u6210\u529F", [detail ? `detail=${detail}` : ""]),
|
|
200
|
+
loginVerifySkip: (reason) => stepWarn("\u767B\u5F55\u9A8C\u8BC1", "\u8DF3\u8FC7", [reason ? `\u539F\u56E0=${reason}` : ""]),
|
|
201
|
+
loginVerifyFail: (err) => stepError("\u767B\u5F55\u9A8C\u8BC1", "\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
202
|
+
envCheckSuccess: (detail) => stepSuccess("\u73AF\u5883\u68C0\u67E5", "\u6210\u529F", [detail ? `detail=${detail}` : ""]),
|
|
203
|
+
envCheckFail: (err) => stepError("\u73AF\u5883\u68C0\u67E5", "\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
204
|
+
inputQuery: (query) => stepStart("\u8F93\u5165\u67E5\u8BE2", "\u5F00\u59CB", [query ? `query=${query}` : ""]),
|
|
205
|
+
sendAction: () => stepInfo("\u53D1\u9001\u8BF7\u6C42", "\u70B9\u51FB\u53D1\u9001"),
|
|
206
|
+
responseListenStart: (label, timeoutSec) => stepStart("\u54CD\u5E94\u76D1\u542C", "\u5F00\u59CB", [
|
|
207
|
+
label ? `\u76EE\u6807=${label}` : "",
|
|
208
|
+
timeoutSec ? `timeout=${timeoutSec}s` : ""
|
|
209
|
+
]),
|
|
210
|
+
responseListenReady: (label) => stepInfo("\u54CD\u5E94\u76D1\u542C", "\u5DF2\u914D\u7F6E", [label ? `\u76EE\u6807=${label}` : ""]),
|
|
211
|
+
responseListenDetected: (label) => stepSuccess("\u54CD\u5E94\u76D1\u542C", "\u5DF2\u68C0\u6D4B", [label ? `\u76EE\u6807=${label}` : ""]),
|
|
212
|
+
responseListenTimeout: (label, err) => stepError("\u54CD\u5E94\u76D1\u542C", "\u8D85\u65F6", [
|
|
213
|
+
label ? `\u76EE\u6807=${label}` : "",
|
|
214
|
+
err ? `err=${toErrorMessage(err)}` : ""
|
|
215
|
+
]),
|
|
216
|
+
responseListenEnd: (label) => stepInfo("\u54CD\u5E94\u76D1\u542C", "\u7ED3\u675F", [label ? `\u76EE\u6807=${label}` : ""]),
|
|
217
|
+
streamChunk: (length, snippet) => throttle(
|
|
218
|
+
"stream-chunk",
|
|
219
|
+
2e3,
|
|
220
|
+
() => stepInfo("\u6D41\u5F0F\u7247\u6BB5", "", [
|
|
221
|
+
length !== void 0 ? `len=${length}` : "",
|
|
222
|
+
snippet ? `preview="${normalizeSnippet(snippet)}"` : ""
|
|
223
|
+
])
|
|
224
|
+
),
|
|
225
|
+
streamEventsParsed: (count) => throttle(
|
|
226
|
+
"stream-events",
|
|
227
|
+
4e3,
|
|
228
|
+
() => stepInfo("\u6D41\u5F0F\u4E8B\u4EF6\u89E3\u6790", "\u5B8C\u6210", [count !== void 0 ? `count=${count}` : ""])
|
|
229
|
+
),
|
|
230
|
+
streamCompleteEvent: () => stepSuccess("\u6D41\u5F0F\u4E8B\u4EF6", "\u5B8C\u6210\u4E8B\u4EF6\u5DF2\u6355\u83B7"),
|
|
231
|
+
streamEnd: () => stepInfo("\u6D41\u5F0F\u54CD\u5E94", "\u7ED3\u675F"),
|
|
232
|
+
responseWaitStart: (label) => stepStart("\u7B49\u5F85\u54CD\u5E94", "\u5F00\u59CB", [label ? `\u76EE\u6807=${label}` : ""]),
|
|
233
|
+
responseWaitSuccess: (label) => stepSuccess("\u7B49\u5F85\u54CD\u5E94", "\u5B8C\u6210", [label ? `\u76EE\u6807=${label}` : ""]),
|
|
234
|
+
responseWaitFail: (label, err) => stepWarn("\u7B49\u5F85\u54CD\u5E94", "\u5931\u8D25", [
|
|
235
|
+
label ? `\u76EE\u6807=${label}` : "",
|
|
236
|
+
err ? `err=${toErrorMessage(err)}` : ""
|
|
237
|
+
]),
|
|
238
|
+
responseWaitRetry: (label, attempt) => stepWarn("\u7B49\u5F85\u54CD\u5E94", "\u91CD\u8BD5", [
|
|
239
|
+
label ? `\u76EE\u6807=${label}` : "",
|
|
240
|
+
attempt !== void 0 ? `\u5C1D\u8BD5=${attempt}` : ""
|
|
241
|
+
]),
|
|
242
|
+
referenceExpandStart: (label) => stepStart("\u5F15\u7528\u5C55\u5F00", "\u5F00\u59CB", [label ? `\u76EE\u6807=${label}` : ""]),
|
|
243
|
+
referenceExpandFail: (err) => stepWarn("\u5F15\u7528\u5C55\u5F00", "\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
244
|
+
screenshotStart: () => stepStart("\u622A\u56FE", "\u5F00\u59CB"),
|
|
245
|
+
screenshotSuccess: () => stepSuccess("\u622A\u56FE", "\u6210\u529F"),
|
|
246
|
+
screenshotFail: (err) => stepWarn("\u622A\u56FE", "\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
247
|
+
shareStart: () => stepStart("\u5206\u4EAB\u94FE\u63A5", "\u5F00\u59CB"),
|
|
248
|
+
shareProgress: (label) => stepInfo("\u5206\u4EAB\u94FE\u63A5", "\u6B65\u9AA4", [label ? `\u6B65\u9AA4=${label}` : ""]),
|
|
249
|
+
shareSuccess: (link) => stepSuccess("\u5206\u4EAB\u94FE\u63A5", "\u6210\u529F", [link ? `\u94FE\u63A5=${link}` : ""]),
|
|
250
|
+
shareFail: (err) => stepWarn("\u5206\u4EAB\u94FE\u63A5", "\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
251
|
+
shareSkip: (reason) => stepWarn("\u5206\u4EAB\u94FE\u63A5", "\u8DF3\u8FC7", [reason ? `\u539F\u56E0=${reason}` : ""]),
|
|
252
|
+
dataPushSuccess: (label) => stepSuccess("\u6570\u636E\u63A8\u9001", "\u6210\u529F", [label ? `\u8BF4\u660E=${label}` : ""]),
|
|
253
|
+
dataPushFail: (err) => stepError("\u6570\u636E\u63A8\u9001", "\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
254
|
+
popupDetected: (detail) => stepWarn("\u5F39\u7A97\u5904\u7406", "\u68C0\u6D4B\u5230\u906E\u7F69", [detail ? `detail=${detail}` : ""]),
|
|
255
|
+
popupCloseAttempt: (detail) => stepInfo("\u5F39\u7A97\u5904\u7406", "\u5C1D\u8BD5\u5173\u95ED", [detail ? `detail=${detail}` : ""]),
|
|
256
|
+
popupCloseSuccess: () => stepSuccess("\u5F39\u7A97\u5904\u7406", "\u5173\u95ED\u5B8C\u6210"),
|
|
257
|
+
popupCloseFail: (err) => stepWarn("\u5F39\u7A97\u5904\u7406", "\u5173\u95ED\u5931\u8D25", [err ? `err=${toErrorMessage(err)}` : ""]),
|
|
258
|
+
info: (message) => info(message),
|
|
259
|
+
success: (message) => success(message),
|
|
260
|
+
warning: (message) => warning(message),
|
|
261
|
+
error: (message) => error(message),
|
|
262
|
+
debug: (message) => debug(message),
|
|
263
|
+
start: (message) => start(message)
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
var Logger = {
|
|
267
|
+
...createBaseLogger(),
|
|
268
|
+
useTemplate: () => createTemplateLogger()
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
// src/internal/logger.js
|
|
62
272
|
function createLogger(moduleName) {
|
|
63
|
-
const
|
|
273
|
+
const baseLogger = createBaseLogger(moduleName);
|
|
64
274
|
return {
|
|
65
275
|
/**
|
|
66
276
|
* 方法开始日志
|
|
@@ -69,7 +279,7 @@ function createLogger(moduleName) {
|
|
|
69
279
|
*/
|
|
70
280
|
start(methodName, params = "") {
|
|
71
281
|
const paramStr = params ? ` (${params})` : "";
|
|
72
|
-
|
|
282
|
+
baseLogger.start(`${methodName} \u5F00\u59CB${paramStr}`);
|
|
73
283
|
},
|
|
74
284
|
/**
|
|
75
285
|
* 方法成功日志
|
|
@@ -78,7 +288,7 @@ function createLogger(moduleName) {
|
|
|
78
288
|
*/
|
|
79
289
|
success(methodName, result = "") {
|
|
80
290
|
const resultStr = result ? ` (${result})` : "";
|
|
81
|
-
|
|
291
|
+
baseLogger.success(`${methodName} \u5B8C\u6210${resultStr}`);
|
|
82
292
|
},
|
|
83
293
|
/**
|
|
84
294
|
* 方法失败日志
|
|
@@ -87,28 +297,28 @@ function createLogger(moduleName) {
|
|
|
87
297
|
*/
|
|
88
298
|
fail(methodName, error) {
|
|
89
299
|
const message = error instanceof Error ? error.message : error;
|
|
90
|
-
|
|
300
|
+
baseLogger.error(`${methodName} \u5931\u8D25: ${message}`);
|
|
91
301
|
},
|
|
92
302
|
/**
|
|
93
303
|
* 调试日志
|
|
94
304
|
* @param {string} message - 详情
|
|
95
305
|
*/
|
|
96
306
|
debug(message) {
|
|
97
|
-
|
|
307
|
+
baseLogger.debug(message);
|
|
98
308
|
},
|
|
99
309
|
/**
|
|
100
310
|
* 警告日志
|
|
101
311
|
* @param {string} message - 警告信息
|
|
102
312
|
*/
|
|
103
313
|
warn(message) {
|
|
104
|
-
|
|
314
|
+
baseLogger.warning(message);
|
|
105
315
|
},
|
|
106
316
|
/**
|
|
107
317
|
* 普通信息日志
|
|
108
318
|
* @param {string} message - 信息
|
|
109
319
|
*/
|
|
110
320
|
info(message) {
|
|
111
|
-
|
|
321
|
+
baseLogger.info(message);
|
|
112
322
|
}
|
|
113
323
|
};
|
|
114
324
|
}
|
|
@@ -357,6 +567,8 @@ var Utils = {
|
|
|
357
567
|
* @param {import('playwright').Page} page - Playwright page 对象
|
|
358
568
|
* @param {Object} [options] - 配置选项
|
|
359
569
|
* @param {number} [options.buffer] - 额外缓冲高度 (默认: 视口高度的一半)
|
|
570
|
+
* @param {boolean} [options.restore] - 截图后是否恢复页面高度和样式 (默认: false)
|
|
571
|
+
* @param {number} [options.maxHeight] - 最大截图高度 (默认: 8000px)
|
|
360
572
|
* @returns {Promise<string>} - base64 编码的 PNG 图片
|
|
361
573
|
*/
|
|
362
574
|
async fullPageScreenshot(page, options = {}) {
|
|
@@ -364,15 +576,17 @@ var Utils = {
|
|
|
364
576
|
const originalViewport = page.viewportSize();
|
|
365
577
|
const defaultBuffer = Math.round((originalViewport?.height || 1080) / 2);
|
|
366
578
|
const buffer = options.buffer ?? defaultBuffer;
|
|
579
|
+
const restore = options.restore ?? false;
|
|
580
|
+
const maxHeight = options.maxHeight ?? 8e3;
|
|
367
581
|
try {
|
|
368
582
|
const maxScrollHeight = await page.evaluate(() => {
|
|
369
|
-
let
|
|
583
|
+
let maxHeight2 = document.body.scrollHeight;
|
|
370
584
|
document.querySelectorAll("*").forEach((el) => {
|
|
371
585
|
const style = window.getComputedStyle(el);
|
|
372
586
|
const overflowY = style.overflowY;
|
|
373
587
|
if ((overflowY === "auto" || overflowY === "scroll") && el.scrollHeight > el.clientHeight) {
|
|
374
|
-
if (el.scrollHeight >
|
|
375
|
-
|
|
588
|
+
if (el.scrollHeight > maxHeight2) {
|
|
589
|
+
maxHeight2 = el.scrollHeight;
|
|
376
590
|
}
|
|
377
591
|
el.dataset.pkOrigOverflow = el.style.overflow;
|
|
378
592
|
el.dataset.pkOrigHeight = el.style.height;
|
|
@@ -383,11 +597,12 @@ var Utils = {
|
|
|
383
597
|
el.style.maxHeight = "none";
|
|
384
598
|
}
|
|
385
599
|
});
|
|
386
|
-
return
|
|
600
|
+
return maxHeight2;
|
|
387
601
|
});
|
|
602
|
+
const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
|
|
388
603
|
await page.setViewportSize({
|
|
389
604
|
width: originalViewport?.width || 1280,
|
|
390
|
-
height:
|
|
605
|
+
height: targetHeight
|
|
391
606
|
});
|
|
392
607
|
await (0, import_delay.default)(1e3);
|
|
393
608
|
const buffer_ = await page.screenshot({
|
|
@@ -397,19 +612,21 @@ var Utils = {
|
|
|
397
612
|
logger2.success("fullPageScreenshot", `captured ${Math.round(buffer_.length / 1024)} KB`);
|
|
398
613
|
return buffer_.toString("base64");
|
|
399
614
|
} finally {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
615
|
+
if (restore) {
|
|
616
|
+
await page.evaluate(() => {
|
|
617
|
+
document.querySelectorAll(".__pk_expanded__").forEach((el) => {
|
|
618
|
+
el.style.overflow = el.dataset.pkOrigOverflow || "";
|
|
619
|
+
el.style.height = el.dataset.pkOrigHeight || "";
|
|
620
|
+
el.style.maxHeight = el.dataset.pkOrigMaxHeight || "";
|
|
621
|
+
delete el.dataset.pkOrigOverflow;
|
|
622
|
+
delete el.dataset.pkOrigHeight;
|
|
623
|
+
delete el.dataset.pkOrigMaxHeight;
|
|
624
|
+
el.classList.remove("__pk_expanded__");
|
|
625
|
+
});
|
|
409
626
|
});
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
627
|
+
if (originalViewport) {
|
|
628
|
+
await page.setViewportSize(originalViewport);
|
|
629
|
+
}
|
|
413
630
|
}
|
|
414
631
|
}
|
|
415
632
|
}
|
|
@@ -1532,6 +1749,181 @@ function isIgnorableError(error) {
|
|
|
1532
1749
|
return msg.includes("already handled") || msg.includes("Target closed") || msg.includes("closed");
|
|
1533
1750
|
}
|
|
1534
1751
|
|
|
1752
|
+
// src/mutation.js
|
|
1753
|
+
var import_uuid2 = require("uuid");
|
|
1754
|
+
var logger9 = createLogger("Mutation");
|
|
1755
|
+
function generateKey(prefix) {
|
|
1756
|
+
return `__${prefix}_${(0, import_uuid2.v4)().replace(/-/g, "_")}`;
|
|
1757
|
+
}
|
|
1758
|
+
var Mutation = {
|
|
1759
|
+
/**
|
|
1760
|
+
* 等待 DOM 元素稳定(无变化)
|
|
1761
|
+
* 使用 MutationObserver 监控指定元素,当元素持续一段时间无变化时 resolve
|
|
1762
|
+
*
|
|
1763
|
+
* @param {import('playwright').Page} page - Playwright page 对象
|
|
1764
|
+
* @param {string | string[]} selectors - 要监控的 CSS 选择器,单个或多个
|
|
1765
|
+
* @param {Object} [options] - 配置选项
|
|
1766
|
+
* @param {number} [options.stableTime] - 无变化持续时间后 resolve (毫秒, 默认: 5000)
|
|
1767
|
+
* @param {number} [options.timeout] - 整体超时时间 (毫秒, 默认: 60000)
|
|
1768
|
+
* @param {Function} [options.onMutation] - 变化时的回调钩子 (mutationCount: number) => void
|
|
1769
|
+
* @returns {Promise<{ mutationCount: number, stableTime: number }>} - 返回变化次数和稳定时长
|
|
1770
|
+
*/
|
|
1771
|
+
async waitForStable(page, selectors, options = {}) {
|
|
1772
|
+
const selectorList = Array.isArray(selectors) ? selectors : [selectors];
|
|
1773
|
+
const stableTime = options.stableTime ?? 5e3;
|
|
1774
|
+
const timeout = options.timeout ?? 6e4;
|
|
1775
|
+
const onMutation = options.onMutation;
|
|
1776
|
+
logger9.start("waitForStable", `\u76D1\u63A7 ${selectorList.length} \u4E2A\u9009\u62E9\u5668, \u7A33\u5B9A\u65F6\u95F4=${stableTime}ms`);
|
|
1777
|
+
const eventName = generateKey("pk_mut_evt");
|
|
1778
|
+
const callbackName = generateKey("pk_mut_cb");
|
|
1779
|
+
if (onMutation) {
|
|
1780
|
+
try {
|
|
1781
|
+
await page.exposeFunction(callbackName, (count) => {
|
|
1782
|
+
try {
|
|
1783
|
+
onMutation(count);
|
|
1784
|
+
} catch (e) {
|
|
1785
|
+
}
|
|
1786
|
+
});
|
|
1787
|
+
} catch (e) {
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
const result = await page.evaluate(
|
|
1791
|
+
async ({ selectorList: selectorList2, stableTime: stableTime2, timeout: timeout2, eventName: eventName2, callbackName: callbackName2, hasCallback }) => {
|
|
1792
|
+
return new Promise((resolve, reject) => {
|
|
1793
|
+
let mutationCount = 0;
|
|
1794
|
+
let stableTimer = null;
|
|
1795
|
+
let timeoutTimer = null;
|
|
1796
|
+
const observers = [];
|
|
1797
|
+
const cleanup = () => {
|
|
1798
|
+
observers.forEach((obs) => obs.disconnect());
|
|
1799
|
+
if (stableTimer) clearTimeout(stableTimer);
|
|
1800
|
+
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
1801
|
+
};
|
|
1802
|
+
const resetStableTimer = () => {
|
|
1803
|
+
if (stableTimer) clearTimeout(stableTimer);
|
|
1804
|
+
stableTimer = setTimeout(() => {
|
|
1805
|
+
cleanup();
|
|
1806
|
+
resolve({ mutationCount, stableTime: stableTime2 });
|
|
1807
|
+
}, stableTime2);
|
|
1808
|
+
};
|
|
1809
|
+
timeoutTimer = setTimeout(() => {
|
|
1810
|
+
cleanup();
|
|
1811
|
+
reject(new Error(`waitForStable \u8D85\u65F6 (${timeout2}ms), \u5DF2\u68C0\u6D4B\u5230 ${mutationCount} \u6B21\u53D8\u5316`));
|
|
1812
|
+
}, timeout2);
|
|
1813
|
+
selectorList2.forEach((selector) => {
|
|
1814
|
+
const elements = document.querySelectorAll(selector);
|
|
1815
|
+
elements.forEach((element) => {
|
|
1816
|
+
const observer = new MutationObserver((mutations) => {
|
|
1817
|
+
mutationCount += mutations.length;
|
|
1818
|
+
if (hasCallback && window[callbackName2]) {
|
|
1819
|
+
window[callbackName2](mutationCount);
|
|
1820
|
+
}
|
|
1821
|
+
resetStableTimer();
|
|
1822
|
+
});
|
|
1823
|
+
observer.observe(element, {
|
|
1824
|
+
childList: true,
|
|
1825
|
+
subtree: true,
|
|
1826
|
+
characterData: true,
|
|
1827
|
+
attributes: true
|
|
1828
|
+
});
|
|
1829
|
+
observers.push(observer);
|
|
1830
|
+
});
|
|
1831
|
+
});
|
|
1832
|
+
if (observers.length === 0) {
|
|
1833
|
+
cleanup();
|
|
1834
|
+
resolve({ mutationCount: 0, stableTime: 0 });
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
resetStableTimer();
|
|
1838
|
+
});
|
|
1839
|
+
},
|
|
1840
|
+
{ selectorList, stableTime, timeout, eventName, callbackName, hasCallback: !!onMutation }
|
|
1841
|
+
);
|
|
1842
|
+
logger9.success("waitForStable", `DOM \u7A33\u5B9A, \u603B\u5171 ${result.mutationCount} \u6B21\u53D8\u5316`);
|
|
1843
|
+
return result;
|
|
1844
|
+
},
|
|
1845
|
+
/**
|
|
1846
|
+
* 创建一个持续监控 DOM 变化的监控器
|
|
1847
|
+
*
|
|
1848
|
+
* @param {import('playwright').Page} page - Playwright page 对象
|
|
1849
|
+
* @param {string | string[]} selectors - 要监控的 CSS 选择器
|
|
1850
|
+
* @param {Object} [options] - 配置选项
|
|
1851
|
+
* @param {Function} [options.onMutation] - 变化时的回调 (mutationCount: number) => void
|
|
1852
|
+
* @returns {Promise<{ stop: () => Promise<{ totalMutations: number }> }>} - 返回停止函数
|
|
1853
|
+
*/
|
|
1854
|
+
async createMonitor(page, selectors, options = {}) {
|
|
1855
|
+
const selectorList = Array.isArray(selectors) ? selectors : [selectors];
|
|
1856
|
+
const onMutation = options.onMutation;
|
|
1857
|
+
logger9.start("createMonitor", `\u76D1\u63A7 ${selectorList.length} \u4E2A\u9009\u62E9\u5668`);
|
|
1858
|
+
const monitorKey = generateKey("pk_mon");
|
|
1859
|
+
const callbackName = generateKey("pk_mon_cb");
|
|
1860
|
+
const cleanerName = generateKey("pk_mon_clean");
|
|
1861
|
+
if (onMutation) {
|
|
1862
|
+
try {
|
|
1863
|
+
await page.exposeFunction(callbackName, (count) => {
|
|
1864
|
+
try {
|
|
1865
|
+
onMutation(count);
|
|
1866
|
+
} catch (e) {
|
|
1867
|
+
}
|
|
1868
|
+
});
|
|
1869
|
+
} catch (e) {
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
await page.evaluate(({ selectorList: selectorList2, monitorKey: monitorKey2, callbackName: callbackName2, cleanerName: cleanerName2, hasCallback }) => {
|
|
1873
|
+
const monitor = {
|
|
1874
|
+
observers: [],
|
|
1875
|
+
totalMutations: 0,
|
|
1876
|
+
running: true
|
|
1877
|
+
};
|
|
1878
|
+
selectorList2.forEach((selector) => {
|
|
1879
|
+
const elements = document.querySelectorAll(selector);
|
|
1880
|
+
elements.forEach((element) => {
|
|
1881
|
+
const observer = new MutationObserver((mutations) => {
|
|
1882
|
+
if (!monitor.running) return;
|
|
1883
|
+
monitor.totalMutations += mutations.length;
|
|
1884
|
+
if (hasCallback && window[callbackName2]) {
|
|
1885
|
+
window[callbackName2](monitor.totalMutations);
|
|
1886
|
+
}
|
|
1887
|
+
});
|
|
1888
|
+
observer.observe(element, {
|
|
1889
|
+
childList: true,
|
|
1890
|
+
subtree: true,
|
|
1891
|
+
characterData: true,
|
|
1892
|
+
attributes: true
|
|
1893
|
+
});
|
|
1894
|
+
monitor.observers.push(observer);
|
|
1895
|
+
});
|
|
1896
|
+
});
|
|
1897
|
+
window[monitorKey2] = monitor;
|
|
1898
|
+
window[cleanerName2] = () => {
|
|
1899
|
+
monitor.running = false;
|
|
1900
|
+
monitor.observers.forEach((obs) => obs.disconnect());
|
|
1901
|
+
const total = monitor.totalMutations;
|
|
1902
|
+
delete window[monitorKey2];
|
|
1903
|
+
delete window[cleanerName2];
|
|
1904
|
+
return total;
|
|
1905
|
+
};
|
|
1906
|
+
}, { selectorList, monitorKey, callbackName, cleanerName, hasCallback: !!onMutation });
|
|
1907
|
+
logger9.success("createMonitor", "\u76D1\u63A7\u5668\u5DF2\u542F\u52A8");
|
|
1908
|
+
return {
|
|
1909
|
+
stop: async () => {
|
|
1910
|
+
let totalMutations = 0;
|
|
1911
|
+
try {
|
|
1912
|
+
totalMutations = await page.evaluate((cleanerName2) => {
|
|
1913
|
+
if (window[cleanerName2]) {
|
|
1914
|
+
return window[cleanerName2]();
|
|
1915
|
+
}
|
|
1916
|
+
return 0;
|
|
1917
|
+
}, cleanerName);
|
|
1918
|
+
} catch (e) {
|
|
1919
|
+
}
|
|
1920
|
+
logger9.success("createMonitor.stop", `\u76D1\u63A7\u5DF2\u505C\u6B62, \u5171 ${totalMutations} \u6B21\u53D8\u5316`);
|
|
1921
|
+
return { totalMutations };
|
|
1922
|
+
}
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
};
|
|
1926
|
+
|
|
1535
1927
|
// index.js
|
|
1536
1928
|
var usePlaywrightToolKit = () => {
|
|
1537
1929
|
return {
|
|
@@ -1545,7 +1937,9 @@ var usePlaywrightToolKit = () => {
|
|
|
1545
1937
|
Captcha,
|
|
1546
1938
|
Sse,
|
|
1547
1939
|
Errors: errors_exports,
|
|
1548
|
-
Interception
|
|
1940
|
+
Interception,
|
|
1941
|
+
Mutation,
|
|
1942
|
+
Logger
|
|
1549
1943
|
};
|
|
1550
1944
|
};
|
|
1551
1945
|
// Annotate the CommonJS export names for ESM import in node:
|