@skrillex1224/playwright-toolkit 2.1.247 → 2.1.248
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 +451 -68
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +451 -68
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -133,10 +133,10 @@ var createActorInfo = (info) => {
|
|
|
133
133
|
xurl
|
|
134
134
|
};
|
|
135
135
|
};
|
|
136
|
-
const buildLandingUrl = ({ protocol: protocol2, domain: domain2, path:
|
|
136
|
+
const buildLandingUrl = ({ protocol: protocol2, domain: domain2, path: path4 }) => {
|
|
137
137
|
const safeProtocol = String(protocol2).trim();
|
|
138
138
|
const safeDomain = normalizeDomain(domain2);
|
|
139
|
-
const safePath = normalizePath(
|
|
139
|
+
const safePath = normalizePath(path4);
|
|
140
140
|
return `${safeProtocol}://${safeDomain}${safePath}`;
|
|
141
141
|
};
|
|
142
142
|
const buildIcon = ({ key }) => {
|
|
@@ -144,14 +144,14 @@ var createActorInfo = (info) => {
|
|
|
144
144
|
};
|
|
145
145
|
const protocol = info.protocol || "https";
|
|
146
146
|
const domain = normalizeDomain(info.domain);
|
|
147
|
-
const
|
|
147
|
+
const path3 = normalizePath(info.path);
|
|
148
148
|
const share = normalizeShare2(info.share);
|
|
149
149
|
const device = normalizeDevice(info.device);
|
|
150
150
|
return {
|
|
151
151
|
...info,
|
|
152
152
|
protocol,
|
|
153
153
|
domain,
|
|
154
|
-
path:
|
|
154
|
+
path: path3,
|
|
155
155
|
share,
|
|
156
156
|
device,
|
|
157
157
|
get icon() {
|
|
@@ -1512,7 +1512,7 @@ var normalizeCookies = (value) => {
|
|
|
1512
1512
|
if (!name || !cookieValue || cookieValue === "<nil>") return null;
|
|
1513
1513
|
const domain = String(raw.domain || "").trim();
|
|
1514
1514
|
const url = normalizeHttpUrl(raw.url);
|
|
1515
|
-
const
|
|
1515
|
+
const path3 = String(raw.path || "").trim() || "/";
|
|
1516
1516
|
const sameSite = normalizeCookieSameSite(raw.sameSite);
|
|
1517
1517
|
const expires = normalizeCookieExpires(raw);
|
|
1518
1518
|
const secure = Boolean(raw.secure);
|
|
@@ -1521,7 +1521,7 @@ var normalizeCookies = (value) => {
|
|
|
1521
1521
|
const normalized = {
|
|
1522
1522
|
name,
|
|
1523
1523
|
value: cookieValue,
|
|
1524
|
-
path:
|
|
1524
|
+
path: path3,
|
|
1525
1525
|
...domain ? { domain } : {},
|
|
1526
1526
|
...!domain && url ? { url } : {},
|
|
1527
1527
|
...sameSite ? { sameSite } : {},
|
|
@@ -2592,6 +2592,10 @@ var assertPoint = (point) => {
|
|
|
2592
2592
|
throw new Error(`Invalid input point: ${JSON.stringify(point)}`);
|
|
2593
2593
|
}
|
|
2594
2594
|
};
|
|
2595
|
+
var toFiniteNumber = (value, fallback = 0) => {
|
|
2596
|
+
const number = Number(value);
|
|
2597
|
+
return Number.isFinite(number) ? number : fallback;
|
|
2598
|
+
};
|
|
2595
2599
|
var dispatchMouseMove = (page, point, options = {}) => page.mouse.move(point.x, point.y, options);
|
|
2596
2600
|
var dispatchMouseStart = (page, options = {}) => page.mouse.down(options);
|
|
2597
2601
|
var dispatchMouseEnd = (page, options = {}) => page.mouse.up(options);
|
|
@@ -2611,6 +2615,11 @@ var dragWithMouse = async (page, points, options = {}) => {
|
|
|
2611
2615
|
}, { steps: 2 });
|
|
2612
2616
|
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2613
2617
|
}
|
|
2618
|
+
const finalMoveRepeats = Math.max(0, Math.floor(toFiniteNumber(options.finalMoveRepeats)));
|
|
2619
|
+
for (let repeat = 0; repeat < finalMoveRepeats; repeat += 1) {
|
|
2620
|
+
await dispatchMouseMove(page, points.end, { steps: 1 });
|
|
2621
|
+
await waitFor(page, options.finalMoveDelayMs ?? 35);
|
|
2622
|
+
}
|
|
2614
2623
|
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2615
2624
|
await dispatchMouseEnd(page);
|
|
2616
2625
|
await waitFor(page, options.afterReleaseDelayMs ?? 100);
|
|
@@ -2620,6 +2629,7 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2620
2629
|
let client = null;
|
|
2621
2630
|
try {
|
|
2622
2631
|
client = await page.context().newCDPSession(page);
|
|
2632
|
+
await waitFor(page, options.initialDelayMs ?? 250);
|
|
2623
2633
|
await client.send("Input.dispatchTouchEvent", {
|
|
2624
2634
|
type: "touchStart",
|
|
2625
2635
|
touchPoints: [{ x: points.start.x, y: points.start.y, id: 1 }]
|
|
@@ -2641,6 +2651,14 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2641
2651
|
});
|
|
2642
2652
|
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2643
2653
|
}
|
|
2654
|
+
const finalMoveRepeats = Math.max(0, Math.floor(toFiniteNumber(options.finalMoveRepeats)));
|
|
2655
|
+
for (let repeat = 0; repeat < finalMoveRepeats; repeat += 1) {
|
|
2656
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
2657
|
+
type: "touchMove",
|
|
2658
|
+
touchPoints: [{ x: points.end.x, y: points.end.y, id: 1 }]
|
|
2659
|
+
});
|
|
2660
|
+
await waitFor(page, options.finalMoveDelayMs ?? 35);
|
|
2661
|
+
}
|
|
2644
2662
|
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2645
2663
|
await client.send("Input.dispatchTouchEvent", {
|
|
2646
2664
|
type: "touchEnd",
|
|
@@ -2658,7 +2676,7 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2658
2676
|
var clickTargetWithDevice = async (page, target, options = {}) => {
|
|
2659
2677
|
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2660
2678
|
const resolvedDevice = resolveDeviceFromPage(page);
|
|
2661
|
-
if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick) {
|
|
2679
|
+
if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick && !normalizedOptions.forceMouse) {
|
|
2662
2680
|
if (typeof target.tap === "function") {
|
|
2663
2681
|
await target.tap(normalizedOptions.tapOptions);
|
|
2664
2682
|
return true;
|
|
@@ -2858,20 +2876,26 @@ var DeviceInput = {
|
|
|
2858
2876
|
throw new Error("Unable to resolve drag coordinates.");
|
|
2859
2877
|
}
|
|
2860
2878
|
const steps = options.steps || 10;
|
|
2879
|
+
const sourceOffsetX = toFiniteNumber(options.sourceOffsetX);
|
|
2880
|
+
const sourceOffsetY = toFiniteNumber(options.sourceOffsetY);
|
|
2881
|
+
const targetOffsetX = toFiniteNumber(options.targetOffsetX);
|
|
2882
|
+
const targetOffsetY = toFiniteNumber(options.targetOffsetY);
|
|
2883
|
+
const sourceCenterX = sourceBox.x + sourceBox.width / 2 + sourceOffsetX;
|
|
2884
|
+
const sourceCenterY = sourceBox.y + sourceBox.height / 2 + sourceOffsetY;
|
|
2861
2885
|
const liftOffsetX = Math.min(18, Math.max(8, sourceBox.width * 0.12));
|
|
2862
2886
|
const liftOffsetY = Math.min(12, Math.max(4, sourceBox.height * 0.08));
|
|
2863
2887
|
const points = {
|
|
2864
2888
|
start: {
|
|
2865
|
-
x:
|
|
2866
|
-
y:
|
|
2889
|
+
x: sourceCenterX,
|
|
2890
|
+
y: sourceCenterY
|
|
2867
2891
|
},
|
|
2868
2892
|
lift: {
|
|
2869
|
-
x:
|
|
2870
|
-
y:
|
|
2893
|
+
x: sourceCenterX + liftOffsetX,
|
|
2894
|
+
y: sourceCenterY + liftOffsetY
|
|
2871
2895
|
},
|
|
2872
2896
|
end: {
|
|
2873
|
-
x: targetBox.x + targetBox.width / 2,
|
|
2874
|
-
y: targetBox.y + targetBox.height / 2
|
|
2897
|
+
x: targetBox.x + targetBox.width / 2 + targetOffsetX,
|
|
2898
|
+
y: targetBox.y + targetBox.height / 2 + targetOffsetY
|
|
2875
2899
|
},
|
|
2876
2900
|
steps
|
|
2877
2901
|
};
|
|
@@ -4988,6 +5012,10 @@ var LiveView = {
|
|
|
4988
5012
|
// src/chaptcha.js
|
|
4989
5013
|
var import_uuid = require("uuid");
|
|
4990
5014
|
|
|
5015
|
+
// src/internals/captcha/bytedance.js
|
|
5016
|
+
var import_promises = require("fs/promises");
|
|
5017
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
5018
|
+
|
|
4991
5019
|
// src/internals/captcha/shared.js
|
|
4992
5020
|
var waitForVisible = async (locator, timeout) => {
|
|
4993
5021
|
try {
|
|
@@ -5005,38 +5033,71 @@ var isAnyCaptchaTextVisible = async (frame, texts, timeout) => {
|
|
|
5005
5033
|
if (!text) {
|
|
5006
5034
|
continue;
|
|
5007
5035
|
}
|
|
5008
|
-
const
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5036
|
+
const textLocator = frame.getByText(text, { exact: false });
|
|
5037
|
+
const locatorText = frame.locator(`text=${text}`);
|
|
5038
|
+
const candidateGroups = [textLocator, locatorText];
|
|
5039
|
+
for (const candidateGroup of candidateGroups) {
|
|
5040
|
+
const candidateCount = await candidateGroup.count().catch(() => 0);
|
|
5041
|
+
for (let index = 0; index < candidateCount; index += 1) {
|
|
5042
|
+
const candidate = candidateGroup.nth(index);
|
|
5043
|
+
const isVisible = await candidate.isVisible({ timeout }).catch(() => false);
|
|
5044
|
+
if (isVisible) {
|
|
5045
|
+
return true;
|
|
5046
|
+
}
|
|
5016
5047
|
}
|
|
5017
5048
|
}
|
|
5018
5049
|
}
|
|
5019
5050
|
return false;
|
|
5020
5051
|
};
|
|
5052
|
+
var collectVisibleCandidateIndexes = async (candidateGroup, count, timeout) => {
|
|
5053
|
+
const visibleIndexes = [];
|
|
5054
|
+
for (let index = 0; index < count; index += 1) {
|
|
5055
|
+
const candidate = candidateGroup.nth(index);
|
|
5056
|
+
const isVisible = await candidate.isVisible({ timeout }).catch(() => false);
|
|
5057
|
+
if (isVisible) {
|
|
5058
|
+
visibleIndexes.push(index);
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
return visibleIndexes;
|
|
5062
|
+
};
|
|
5021
5063
|
var clickCaptchaAction = async (frame, texts, options) => {
|
|
5022
5064
|
for (const text of texts || []) {
|
|
5023
|
-
const
|
|
5024
|
-
|
|
5025
|
-
|
|
5065
|
+
const textLocator = frame.getByText(text, { exact: false });
|
|
5066
|
+
const locatorText = frame.locator(`text=${text}`);
|
|
5067
|
+
const [getByTextCount, locatorTextCount] = await Promise.all([
|
|
5068
|
+
textLocator.count().catch(() => 0),
|
|
5069
|
+
locatorText.count().catch(() => 0)
|
|
5070
|
+
]);
|
|
5071
|
+
const [getByTextVisibleIndexes, locatorTextVisibleIndexes] = await Promise.all([
|
|
5072
|
+
collectVisibleCandidateIndexes(textLocator, getByTextCount, options.actionVisibleTimeoutMs),
|
|
5073
|
+
collectVisibleCandidateIndexes(locatorText, locatorTextCount, options.actionVisibleTimeoutMs)
|
|
5074
|
+
]);
|
|
5075
|
+
options.logger?.info(
|
|
5076
|
+
`[CaptchaAction] \u6587\u672C "${text}" \u547D\u4E2D\u6570\u91CF\uFF1AgetByText=${getByTextCount} (visible=${getByTextVisibleIndexes.length}), locator=${locatorTextCount} (visible=${locatorTextVisibleIndexes.length})`
|
|
5077
|
+
);
|
|
5078
|
+
const candidateGroups = [
|
|
5079
|
+
{ label: "getByText", locator: textLocator, count: getByTextCount },
|
|
5080
|
+
{ label: "locator", locator: locatorText, count: locatorTextCount }
|
|
5026
5081
|
];
|
|
5027
|
-
for (const
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5082
|
+
for (const candidateGroup of candidateGroups) {
|
|
5083
|
+
for (let index = 0; index < candidateGroup.count; index += 1) {
|
|
5084
|
+
const candidate = candidateGroup.locator.nth(index);
|
|
5085
|
+
const isVisible = await waitForVisible(candidate, options.actionVisibleTimeoutMs);
|
|
5086
|
+
if (!isVisible) {
|
|
5087
|
+
continue;
|
|
5088
|
+
}
|
|
5089
|
+
options.logger?.info(
|
|
5090
|
+
`[CaptchaAction] \u6587\u672C "${text}" \u9009\u62E9 ${candidateGroup.label}[${index}] \u4F5C\u4E3A\u7B2C\u4E00\u4E2A\u53EF\u89C1\u8282\u70B9\u6267\u884C\u70B9\u51FB\u3002`
|
|
5091
|
+
);
|
|
5092
|
+
await DeviceInput.click(options.page, candidate, options);
|
|
5093
|
+
return true;
|
|
5031
5094
|
}
|
|
5032
|
-
await DeviceInput.click(options.page, candidate);
|
|
5033
|
-
return true;
|
|
5034
5095
|
}
|
|
5035
5096
|
}
|
|
5036
5097
|
return false;
|
|
5037
5098
|
};
|
|
5038
|
-
var dragCaptchaAction = async (page, sourceLocator, targetLocator) => {
|
|
5039
|
-
await DeviceInput.drag(page, sourceLocator, targetLocator);
|
|
5099
|
+
var dragCaptchaAction = async (page, sourceLocator, targetLocator, options = {}) => {
|
|
5100
|
+
await DeviceInput.drag(page, sourceLocator, targetLocator, options);
|
|
5040
5101
|
};
|
|
5041
5102
|
|
|
5042
5103
|
// src/internals/captcha/bytedance.js
|
|
@@ -5047,11 +5108,12 @@ var DEFAULT_BYTEDANCE_CAPTCHA_OPTIONS = Object.freeze({
|
|
|
5047
5108
|
containerSelector: "#captcha_container",
|
|
5048
5109
|
iframeSelector: 'iframe[src*="verifycenter"]',
|
|
5049
5110
|
iframeFallbackSelector: "iframe",
|
|
5050
|
-
sourceImageSelector: "
|
|
5051
|
-
dropTargetContainerSelector: "
|
|
5111
|
+
sourceImageSelector: ".img-container .canvas-container",
|
|
5112
|
+
dropTargetContainerSelector: ".drag-area",
|
|
5052
5113
|
dropTargetTexts: ["\u62D6\u62FD\u5230\u8FD9\u91CC"],
|
|
5053
5114
|
refreshTexts: ["\u5237\u65B0"],
|
|
5054
5115
|
submitTexts: ["\u63D0\u4EA4"],
|
|
5116
|
+
guideMaskSelector: ".play-guide-mask",
|
|
5055
5117
|
recognitionSuccessCode: 1e4,
|
|
5056
5118
|
containerVisibleTimeoutMs: 2e3,
|
|
5057
5119
|
iframeVisibleTimeoutMs: 12e3,
|
|
@@ -5074,10 +5136,111 @@ var DEFAULT_BYTEDANCE_CAPTCHA_OPTIONS = Object.freeze({
|
|
|
5074
5136
|
],
|
|
5075
5137
|
recognitionDelayMs: 2e3,
|
|
5076
5138
|
refreshWaitMs: 3e3,
|
|
5077
|
-
submitWaitMs:
|
|
5139
|
+
submitWaitMs: 5e3,
|
|
5140
|
+
submitReadyTimeoutMs: 2500,
|
|
5078
5141
|
retryDelayBaseMs: 2e3,
|
|
5079
|
-
retryDelayStepMs: 1e3
|
|
5142
|
+
retryDelayStepMs: 1e3,
|
|
5143
|
+
sourceImageRowTolerancePx: 24,
|
|
5144
|
+
dragBetweenWaitMs: 250,
|
|
5145
|
+
promptBadgeCountSelector: ".drag-area .photo-badge .badge span",
|
|
5146
|
+
promptSubmitButtonSelector: ".vc-captcha-verify-mobile-button",
|
|
5147
|
+
promptSelectedSourceSelector: ".img-container .canvas-container.selected",
|
|
5148
|
+
promptActiveSourceSelector: ".img-container .canvas-container.active",
|
|
5149
|
+
promptDragMoveSteps: 16,
|
|
5150
|
+
promptDragStepDelayMs: 55,
|
|
5151
|
+
promptDragHoldDelayMs: 240,
|
|
5152
|
+
promptDragBeforeReleaseDelayMs: 180,
|
|
5153
|
+
promptDragAfterReleaseDelayMs: 240,
|
|
5154
|
+
promptDragFinalMoveRepeats: 3,
|
|
5155
|
+
promptDragRetryDelayMs: 250,
|
|
5156
|
+
debugArtifacts: false
|
|
5080
5157
|
});
|
|
5158
|
+
var PROMPT_CAPTCHA_DRAG_PLANS = Object.freeze([
|
|
5159
|
+
{ name: "lower-middle", endXRatio: 0.5, endYRatio: 0.72 },
|
|
5160
|
+
{ name: "center-middle", endXRatio: 0.5, endYRatio: 0.56 },
|
|
5161
|
+
{ name: "upper-middle", endXRatio: 0.5, endYRatio: 0.4 }
|
|
5162
|
+
]);
|
|
5163
|
+
var resolveCaptchaDebugDir = () => import_path2.default.resolve(process.cwd(), "storage", "captcha-debug");
|
|
5164
|
+
var rectOf = (rect) => {
|
|
5165
|
+
if (!rect) {
|
|
5166
|
+
return null;
|
|
5167
|
+
}
|
|
5168
|
+
return {
|
|
5169
|
+
x: Number(rect.x.toFixed(2)),
|
|
5170
|
+
y: Number(rect.y.toFixed(2)),
|
|
5171
|
+
width: Number(rect.width.toFixed(2)),
|
|
5172
|
+
height: Number(rect.height.toFixed(2))
|
|
5173
|
+
};
|
|
5174
|
+
};
|
|
5175
|
+
var collectCaptchaDebugInfo = async (page, frame, iframeLocator, attempt, phase, extra = null) => {
|
|
5176
|
+
const timestamp = Date.now();
|
|
5177
|
+
const debugDir = resolveCaptchaDebugDir();
|
|
5178
|
+
await (0, import_promises.mkdir)(debugDir, { recursive: true });
|
|
5179
|
+
const baseName = `bytedance-${timestamp}-attempt${attempt}-${phase}`;
|
|
5180
|
+
const iframeScreenshotPath = import_path2.default.join(debugDir, `${baseName}-iframe.png`);
|
|
5181
|
+
const pageScreenshotPath = import_path2.default.join(debugDir, `${baseName}-page.png`);
|
|
5182
|
+
const htmlPath = import_path2.default.join(debugDir, `${baseName}-iframe.html`);
|
|
5183
|
+
const infoPath = import_path2.default.join(debugDir, `${baseName}-info.json`);
|
|
5184
|
+
await iframeLocator.screenshot({ path: iframeScreenshotPath }).catch(() => {
|
|
5185
|
+
});
|
|
5186
|
+
await page.screenshot({ path: pageScreenshotPath, fullPage: true }).catch(() => {
|
|
5187
|
+
});
|
|
5188
|
+
const html = await frame.evaluate(() => document.documentElement.outerHTML).catch(() => "");
|
|
5189
|
+
if (html) {
|
|
5190
|
+
await (0, import_promises.writeFile)(htmlPath, html, "utf8");
|
|
5191
|
+
}
|
|
5192
|
+
const info = await frame.evaluate(() => {
|
|
5193
|
+
const toRect = (element) => {
|
|
5194
|
+
const rect = element.getBoundingClientRect();
|
|
5195
|
+
return {
|
|
5196
|
+
x: Number(rect.x.toFixed(2)),
|
|
5197
|
+
y: Number(rect.y.toFixed(2)),
|
|
5198
|
+
width: Number(rect.width.toFixed(2)),
|
|
5199
|
+
height: Number(rect.height.toFixed(2))
|
|
5200
|
+
};
|
|
5201
|
+
};
|
|
5202
|
+
const toItem = (element, index) => ({
|
|
5203
|
+
index,
|
|
5204
|
+
tag: element.tagName,
|
|
5205
|
+
id: element.id || "",
|
|
5206
|
+
className: typeof element.className === "string" ? element.className : "",
|
|
5207
|
+
text: String(element.textContent || "").trim(),
|
|
5208
|
+
rect: toRect(element)
|
|
5209
|
+
});
|
|
5210
|
+
const visibleNodes = Array.from(document.querySelectorAll("body *")).map(toItem).filter((item) => item.rect.width > 0 && item.rect.height > 0);
|
|
5211
|
+
return {
|
|
5212
|
+
title: document.title,
|
|
5213
|
+
bodyText: String(document.body?.innerText || "").trim(),
|
|
5214
|
+
canvasContainers: visibleNodes.filter((item) => item.className.includes("canvas-container")),
|
|
5215
|
+
canvasNodes: visibleNodes.filter((item) => item.tag === "CANVAS"),
|
|
5216
|
+
captchaNodes: visibleNodes.filter((item) => item.id.startsWith("captcha_") || item.className.includes("captcha") || item.className.includes("verify") || /拖拽到这里|刷新|提交/.test(item.text)),
|
|
5217
|
+
visibleTextNodes: visibleNodes.filter((item) => item.text).slice(0, 300)
|
|
5218
|
+
};
|
|
5219
|
+
}).catch(() => null);
|
|
5220
|
+
if (info) {
|
|
5221
|
+
const payload = {
|
|
5222
|
+
capturedAt: new Date(timestamp).toISOString(),
|
|
5223
|
+
pageUrl: page.url(),
|
|
5224
|
+
attempt,
|
|
5225
|
+
phase,
|
|
5226
|
+
iframeScreenshotPath,
|
|
5227
|
+
pageScreenshotPath,
|
|
5228
|
+
htmlPath,
|
|
5229
|
+
info
|
|
5230
|
+
};
|
|
5231
|
+
if (extra != null) {
|
|
5232
|
+
payload.extra = extra;
|
|
5233
|
+
}
|
|
5234
|
+
await (0, import_promises.writeFile)(infoPath, JSON.stringify(payload, null, 2), "utf8");
|
|
5235
|
+
}
|
|
5236
|
+
logger10.info(`\u5DF2\u5199\u51FA\u9A8C\u8BC1\u7801\u8C03\u8BD5\u4EA7\u7269\uFF1A${debugDir}`);
|
|
5237
|
+
};
|
|
5238
|
+
var maybeCollectCaptchaDebugInfo = async (page, frame, iframeLocator, attempt, phase, options, extra = null) => {
|
|
5239
|
+
if (!options.debugArtifacts) {
|
|
5240
|
+
return;
|
|
5241
|
+
}
|
|
5242
|
+
await collectCaptchaDebugInfo(page, frame, iframeLocator, attempt, phase, extra);
|
|
5243
|
+
};
|
|
5081
5244
|
var extractCaptchaSerialNumbers = (apiResponse) => {
|
|
5082
5245
|
const serialNumbers = apiResponse?.data?.data?.serial_number;
|
|
5083
5246
|
if (!Array.isArray(serialNumbers)) {
|
|
@@ -5086,7 +5249,7 @@ var extractCaptchaSerialNumbers = (apiResponse) => {
|
|
|
5086
5249
|
return serialNumbers.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value >= 0);
|
|
5087
5250
|
};
|
|
5088
5251
|
var resolveContentFrame = async (page, iframeLocator, options) => {
|
|
5089
|
-
for (let attempt = 1; attempt <= options.contentFrameResolveRetries; attempt
|
|
5252
|
+
for (let attempt = 1; attempt <= options.contentFrameResolveRetries; attempt += 1) {
|
|
5090
5253
|
const iframeHandle = await iframeLocator.elementHandle();
|
|
5091
5254
|
const frame = await iframeHandle?.contentFrame();
|
|
5092
5255
|
if (frame) {
|
|
@@ -5131,20 +5294,15 @@ var getVerifycenterCaptchaContext = async (page, options) => {
|
|
|
5131
5294
|
}
|
|
5132
5295
|
return { iframeLocator, frame };
|
|
5133
5296
|
};
|
|
5134
|
-
var refreshCaptcha = async (page, frame, options) => {
|
|
5135
|
-
const clicked = await clickCaptchaAction(frame, options.refreshTexts, { ...options, page }).catch(() => false);
|
|
5136
|
-
if (!clicked) {
|
|
5137
|
-
logger10.warn("Refresh button not found.");
|
|
5138
|
-
return false;
|
|
5139
|
-
}
|
|
5140
|
-
await page.waitForTimeout(options.refreshWaitMs);
|
|
5141
|
-
return true;
|
|
5142
|
-
};
|
|
5143
5297
|
var findCaptchaDropTarget = async (frame, options) => {
|
|
5298
|
+
const directTarget = frame.locator(options.dropTargetContainerSelector).first();
|
|
5299
|
+
if (await waitForVisible(directTarget, options.actionVisibleTimeoutMs)) {
|
|
5300
|
+
return directTarget;
|
|
5301
|
+
}
|
|
5144
5302
|
for (const text of options.dropTargetTexts) {
|
|
5145
5303
|
const candidates = [
|
|
5146
|
-
frame.
|
|
5147
|
-
frame.
|
|
5304
|
+
frame.getByText(text, { exact: false }).first(),
|
|
5305
|
+
frame.locator(`text=${text}`).first()
|
|
5148
5306
|
];
|
|
5149
5307
|
for (const candidate of candidates) {
|
|
5150
5308
|
const isVisible = await waitForVisible(candidate, options.actionVisibleTimeoutMs);
|
|
@@ -5155,10 +5313,112 @@ var findCaptchaDropTarget = async (frame, options) => {
|
|
|
5155
5313
|
}
|
|
5156
5314
|
return null;
|
|
5157
5315
|
};
|
|
5316
|
+
var readPromptCaptchaState = async (frame, options) => frame.evaluate((selectors) => {
|
|
5317
|
+
const toRect = (element) => {
|
|
5318
|
+
if (!element) {
|
|
5319
|
+
return null;
|
|
5320
|
+
}
|
|
5321
|
+
const rect = element.getBoundingClientRect();
|
|
5322
|
+
return {
|
|
5323
|
+
x: Number(rect.x.toFixed(2)),
|
|
5324
|
+
y: Number(rect.y.toFixed(2)),
|
|
5325
|
+
width: Number(rect.width.toFixed(2)),
|
|
5326
|
+
height: Number(rect.height.toFixed(2))
|
|
5327
|
+
};
|
|
5328
|
+
};
|
|
5329
|
+
const badgeNode = document.querySelector(selectors.badgeCountSelector);
|
|
5330
|
+
const submitButton = document.querySelector(selectors.submitButtonSelector);
|
|
5331
|
+
const dragArea = document.querySelector(selectors.dragAreaSelector);
|
|
5332
|
+
const badgeCount = badgeNode ? Number.parseInt(String(badgeNode.textContent || "").trim(), 10) : 0;
|
|
5333
|
+
return {
|
|
5334
|
+
badgeCount: Number.isFinite(badgeCount) ? badgeCount : 0,
|
|
5335
|
+
selectedCount: document.querySelectorAll(selectors.selectedSourceSelector).length,
|
|
5336
|
+
activeCount: document.querySelectorAll(selectors.activeSourceSelector).length,
|
|
5337
|
+
submitDisabled: submitButton ? submitButton.classList.contains("disable") : null,
|
|
5338
|
+
dragAreaActive: dragArea ? dragArea.classList.contains("active") : false,
|
|
5339
|
+
dragAreaRect: toRect(dragArea)
|
|
5340
|
+
};
|
|
5341
|
+
}, {
|
|
5342
|
+
badgeCountSelector: options.promptBadgeCountSelector,
|
|
5343
|
+
submitButtonSelector: options.promptSubmitButtonSelector,
|
|
5344
|
+
selectedSourceSelector: options.promptSelectedSourceSelector,
|
|
5345
|
+
activeSourceSelector: options.promptActiveSourceSelector,
|
|
5346
|
+
dragAreaSelector: options.dropTargetContainerSelector
|
|
5347
|
+
}).catch(() => ({
|
|
5348
|
+
badgeCount: 0,
|
|
5349
|
+
selectedCount: 0,
|
|
5350
|
+
activeCount: 0,
|
|
5351
|
+
submitDisabled: null,
|
|
5352
|
+
dragAreaActive: false,
|
|
5353
|
+
dragAreaRect: null
|
|
5354
|
+
}));
|
|
5355
|
+
var normalizeCaptchaImageIndexes = (serialNumbers, imageCount) => {
|
|
5356
|
+
if (!Array.isArray(serialNumbers) || imageCount <= 0) {
|
|
5357
|
+
return [];
|
|
5358
|
+
}
|
|
5359
|
+
const areAllOneBased = serialNumbers.every((value) => value >= 1 && value <= imageCount);
|
|
5360
|
+
if (areAllOneBased) {
|
|
5361
|
+
return serialNumbers.map((value) => value - 1);
|
|
5362
|
+
}
|
|
5363
|
+
const areAllZeroBased = serialNumbers.every((value) => value >= 0 && value < imageCount);
|
|
5364
|
+
if (areAllZeroBased) {
|
|
5365
|
+
return [...serialNumbers];
|
|
5366
|
+
}
|
|
5367
|
+
return serialNumbers.map((value) => {
|
|
5368
|
+
if (value >= 1 && value <= imageCount) {
|
|
5369
|
+
return value - 1;
|
|
5370
|
+
}
|
|
5371
|
+
if (value >= 0 && value < imageCount) {
|
|
5372
|
+
return value;
|
|
5373
|
+
}
|
|
5374
|
+
return null;
|
|
5375
|
+
}).filter((value) => Number.isInteger(value));
|
|
5376
|
+
};
|
|
5377
|
+
var resolveCaptchaSourceImagesInVisualOrder = async (frame, options) => {
|
|
5378
|
+
const sourceImages = frame.locator(options.sourceImageSelector);
|
|
5379
|
+
const imageCount = await sourceImages.count().catch(() => 0);
|
|
5380
|
+
const sources = [];
|
|
5381
|
+
for (let domIndex = 0; domIndex < imageCount; domIndex += 1) {
|
|
5382
|
+
const locator = sourceImages.nth(domIndex);
|
|
5383
|
+
const box = await locator.boundingBox().catch(() => null);
|
|
5384
|
+
if (!box || box.width <= 0 || box.height <= 0) {
|
|
5385
|
+
continue;
|
|
5386
|
+
}
|
|
5387
|
+
sources.push({
|
|
5388
|
+
domIndex,
|
|
5389
|
+
locator,
|
|
5390
|
+
box
|
|
5391
|
+
});
|
|
5392
|
+
}
|
|
5393
|
+
sources.sort((left, right) => {
|
|
5394
|
+
const deltaY = left.box.y - right.box.y;
|
|
5395
|
+
if (Math.abs(deltaY) > options.sourceImageRowTolerancePx) {
|
|
5396
|
+
return deltaY;
|
|
5397
|
+
}
|
|
5398
|
+
return left.box.x - right.box.x;
|
|
5399
|
+
});
|
|
5400
|
+
return sources;
|
|
5401
|
+
};
|
|
5402
|
+
var refreshCaptcha = async (page, frame, options) => {
|
|
5403
|
+
const clicked = await clickCaptchaAction(frame, options.refreshTexts, {
|
|
5404
|
+
...options,
|
|
5405
|
+
page,
|
|
5406
|
+
logger: logger10,
|
|
5407
|
+
forceMouse: true
|
|
5408
|
+
}).catch(() => false);
|
|
5409
|
+
if (!clicked) {
|
|
5410
|
+
logger10.warn("Refresh button not found.");
|
|
5411
|
+
return false;
|
|
5412
|
+
}
|
|
5413
|
+
await page.waitForTimeout(options.refreshWaitMs);
|
|
5414
|
+
return true;
|
|
5415
|
+
};
|
|
5158
5416
|
var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
5159
5417
|
const deadline = Date.now() + options.challengeReadyTimeoutMs;
|
|
5160
5418
|
let refreshDeadline = Date.now() + options.challengeReadyRefreshTimeoutMs;
|
|
5161
5419
|
let hasSeenLoading = false;
|
|
5420
|
+
let hasSeenGuideMask = false;
|
|
5421
|
+
let hasLoggedGuideMask = false;
|
|
5162
5422
|
while (Date.now() < deadline) {
|
|
5163
5423
|
const isLoadingVisible = await isAnyCaptchaTextVisible(
|
|
5164
5424
|
frame,
|
|
@@ -5174,8 +5434,17 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5174
5434
|
const sourceImages = frame.locator(options.sourceImageSelector);
|
|
5175
5435
|
const imageCount = await sourceImages.count().catch(() => 0);
|
|
5176
5436
|
const hasVisibleSourceImage = imageCount > 0 ? await sourceImages.first().isVisible({ timeout: options.loadingIndicatorVisibleTimeoutMs }).catch(() => false) : false;
|
|
5177
|
-
|
|
5178
|
-
|
|
5437
|
+
const hasVisibleDropTarget = await frame.locator(options.dropTargetContainerSelector).first().isVisible({ timeout: options.loadingIndicatorVisibleTimeoutMs }).catch(() => false);
|
|
5438
|
+
const hasGuideMaskVisible = options.guideMaskSelector ? await frame.locator(options.guideMaskSelector).first().isVisible({ timeout: options.loadingIndicatorVisibleTimeoutMs }).catch(() => false) : false;
|
|
5439
|
+
hasSeenGuideMask = hasSeenGuideMask || hasGuideMaskVisible;
|
|
5440
|
+
if (hasGuideMaskVisible && !hasLoggedGuideMask) {
|
|
5441
|
+
logger10.info("\u68C0\u6D4B\u5230\u9A8C\u8BC1\u7801\u64CD\u4F5C\u5F15\u5BFC\u5C42\uFF0C\u7B49\u5F85\u5176\u6D88\u5931\u540E\u518D\u5F00\u59CB\u8BC6\u522B\u3002");
|
|
5442
|
+
hasLoggedGuideMask = true;
|
|
5443
|
+
}
|
|
5444
|
+
if (!isLoadingVisible && hasVisibleSourceImage && hasVisibleDropTarget && !hasGuideMaskVisible) {
|
|
5445
|
+
logger10.info(
|
|
5446
|
+
hasSeenGuideMask ? "\u9A8C\u8BC1\u7801\u56FE\u7247\u548C\u62D6\u62FD\u533A\u57DF\u5DF2\u5C31\u7EEA\uFF0C\u5F15\u5BFC\u5C42\u5DF2\u6D88\u5931\u3002" : hasSeenLoading ? "\u9A8C\u8BC1\u7801\u56FE\u7247\u5DF2\u52A0\u8F7D\u5B8C\u6210\u3002" : "\u9A8C\u8BC1\u7801\u56FE\u7247\u5DF2\u5C31\u7EEA\u3002"
|
|
5447
|
+
);
|
|
5179
5448
|
return;
|
|
5180
5449
|
}
|
|
5181
5450
|
if (hasErrorTextVisible) {
|
|
@@ -5185,8 +5454,8 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5185
5454
|
hasSeenLoading = false;
|
|
5186
5455
|
continue;
|
|
5187
5456
|
}
|
|
5188
|
-
if (!hasVisibleSourceImage && Date.now() >= refreshDeadline) {
|
|
5189
|
-
logger10.warn(`\u9A8C\u8BC1\u7801\
|
|
5457
|
+
if ((!hasVisibleSourceImage || !hasVisibleDropTarget) && Date.now() >= refreshDeadline) {
|
|
5458
|
+
logger10.warn(`\u9A8C\u8BC1\u7801\u9898\u76EE\u8D85\u8FC7 ${options.challengeReadyRefreshTimeoutMs}ms \u4ECD\u672A\u51C6\u5907\u597D\uFF0C\u5C1D\u8BD5\u5237\u65B0\u9898\u76EE\u3002`);
|
|
5190
5459
|
await refreshCaptcha(page, frame, options);
|
|
5191
5460
|
refreshDeadline = Date.now() + options.challengeReadyRefreshTimeoutMs;
|
|
5192
5461
|
hasSeenLoading = false;
|
|
@@ -5196,6 +5465,69 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5196
5465
|
}
|
|
5197
5466
|
throw new Error("Captcha challenge is still loading and did not become ready in time.");
|
|
5198
5467
|
};
|
|
5468
|
+
var dragPromptCaptchaImage = async (page, frame, iframeLocator, sourceLocator, dropTarget, options, {
|
|
5469
|
+
attempt,
|
|
5470
|
+
visualIndex
|
|
5471
|
+
}) => {
|
|
5472
|
+
const baselineState = await readPromptCaptchaState(frame, options);
|
|
5473
|
+
const dragAttempts = [];
|
|
5474
|
+
for (const plan of PROMPT_CAPTCHA_DRAG_PLANS) {
|
|
5475
|
+
const sourceBox = await sourceLocator.boundingBox().catch(() => null);
|
|
5476
|
+
const targetBox = await dropTarget.boundingBox().catch(() => null);
|
|
5477
|
+
if (!sourceBox || !targetBox) {
|
|
5478
|
+
throw new Error("Unable to resolve prompt captcha drag coordinates.");
|
|
5479
|
+
}
|
|
5480
|
+
const targetOffsetX = (plan.endXRatio - 0.5) * targetBox.width;
|
|
5481
|
+
const targetOffsetY = (plan.endYRatio - 0.5) * targetBox.height;
|
|
5482
|
+
await dragCaptchaAction(page, sourceLocator, dropTarget, {
|
|
5483
|
+
forceMouse: true,
|
|
5484
|
+
targetOffsetX,
|
|
5485
|
+
targetOffsetY,
|
|
5486
|
+
steps: options.promptDragMoveSteps,
|
|
5487
|
+
holdDelayMs: options.promptDragHoldDelayMs,
|
|
5488
|
+
stepDelayMs: options.promptDragStepDelayMs,
|
|
5489
|
+
beforeReleaseDelayMs: options.promptDragBeforeReleaseDelayMs,
|
|
5490
|
+
afterReleaseDelayMs: options.promptDragAfterReleaseDelayMs,
|
|
5491
|
+
finalMoveRepeats: options.promptDragFinalMoveRepeats
|
|
5492
|
+
});
|
|
5493
|
+
const afterState = await readPromptCaptchaState(frame, options);
|
|
5494
|
+
const accepted = afterState.badgeCount > baselineState.badgeCount || afterState.selectedCount > baselineState.selectedCount;
|
|
5495
|
+
const attemptInfo = {
|
|
5496
|
+
planName: plan.name,
|
|
5497
|
+
sourceRect: rectOf(sourceBox),
|
|
5498
|
+
targetRect: rectOf(targetBox),
|
|
5499
|
+
targetOffsetX: Number(targetOffsetX.toFixed(2)),
|
|
5500
|
+
targetOffsetY: Number(targetOffsetY.toFixed(2)),
|
|
5501
|
+
beforeState: baselineState,
|
|
5502
|
+
afterState,
|
|
5503
|
+
accepted
|
|
5504
|
+
};
|
|
5505
|
+
dragAttempts.push(attemptInfo);
|
|
5506
|
+
logger10.info(
|
|
5507
|
+
`\u9A8C\u8BC1\u7801\u62D6\u62FD\u7B2C ${visualIndex + 1} \u5F20\uFF0C\u65B9\u6848 ${plan.name}\uFF0Cbadge ${baselineState.badgeCount} -> ${afterState.badgeCount}\uFF0Cselected ${baselineState.selectedCount} -> ${afterState.selectedCount}`
|
|
5508
|
+
);
|
|
5509
|
+
if (accepted) {
|
|
5510
|
+
return {
|
|
5511
|
+
accepted: true,
|
|
5512
|
+
dragAttempts
|
|
5513
|
+
};
|
|
5514
|
+
}
|
|
5515
|
+
if (options.promptDragRetryDelayMs > 0) {
|
|
5516
|
+
await page.waitForTimeout(options.promptDragRetryDelayMs);
|
|
5517
|
+
}
|
|
5518
|
+
}
|
|
5519
|
+
await maybeCollectCaptchaDebugInfo(page, frame, iframeLocator, attempt, `drag-${visualIndex + 1}-failed`, options, {
|
|
5520
|
+
visualIndex,
|
|
5521
|
+
dragAttempts,
|
|
5522
|
+
finalState: await readPromptCaptchaState(frame, options)
|
|
5523
|
+
}).catch((error) => {
|
|
5524
|
+
logger10.warn(`\u9A8C\u8BC1\u7801\u62D6\u62FD\u5931\u8D25\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5525
|
+
});
|
|
5526
|
+
return {
|
|
5527
|
+
accepted: false,
|
|
5528
|
+
dragAttempts
|
|
5529
|
+
};
|
|
5530
|
+
};
|
|
5199
5531
|
async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
5200
5532
|
const { callCaptchaRecognitionApi: callCaptchaRecognitionApi2 } = dependencies;
|
|
5201
5533
|
if (typeof callCaptchaRecognitionApi2 !== "function") {
|
|
@@ -5210,7 +5542,7 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5210
5542
|
return false;
|
|
5211
5543
|
}
|
|
5212
5544
|
logger10.info("\u5F53\u524D\u4F7F\u7528\u672Ctool\u2014\u2014\u6D4B\u8BD5\u7248\u672C");
|
|
5213
|
-
for (let attempt = 1; attempt <= config.maxRetries; attempt
|
|
5545
|
+
for (let attempt = 1; attempt <= config.maxRetries; attempt += 1) {
|
|
5214
5546
|
logger10.info(`\u5F00\u59CB\u7B2C ${attempt}/${config.maxRetries} \u6B21 verifycenter \u9A8C\u8BC1\u7801\u8BC6\u522B\u3002`);
|
|
5215
5547
|
try {
|
|
5216
5548
|
const captchaContext = await getVerifycenterCaptchaContext(page, config);
|
|
@@ -5220,6 +5552,16 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5220
5552
|
}
|
|
5221
5553
|
const { iframeLocator, frame } = captchaContext;
|
|
5222
5554
|
await waitForCaptchaChallengeReady(page, frame, config);
|
|
5555
|
+
await maybeCollectCaptchaDebugInfo(
|
|
5556
|
+
page,
|
|
5557
|
+
frame,
|
|
5558
|
+
iframeLocator,
|
|
5559
|
+
attempt,
|
|
5560
|
+
"ready",
|
|
5561
|
+
config
|
|
5562
|
+
).catch((error) => {
|
|
5563
|
+
logger10.warn(`\u9A8C\u8BC1\u7801\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5564
|
+
});
|
|
5223
5565
|
await page.waitForTimeout(config.recognitionDelayMs);
|
|
5224
5566
|
const screenshotBuffer = await iframeLocator.screenshot();
|
|
5225
5567
|
const apiResponse = await callCaptchaRecognitionApi2({
|
|
@@ -5243,33 +5585,74 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5243
5585
|
await refreshCaptcha(page, frame, config);
|
|
5244
5586
|
continue;
|
|
5245
5587
|
}
|
|
5246
|
-
const
|
|
5247
|
-
const
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5588
|
+
const orderedSourceImages = await resolveCaptchaSourceImagesInVisualOrder(frame, config);
|
|
5589
|
+
const normalizedIndexes = normalizeCaptchaImageIndexes(serialNumbers, orderedSourceImages.length);
|
|
5590
|
+
if (normalizedIndexes.length !== serialNumbers.length) {
|
|
5591
|
+
throw new Error(
|
|
5592
|
+
`Captcha image indexes could not be normalized. raw=${serialNumbers.join(", ")}, count=${orderedSourceImages.length}`
|
|
5593
|
+
);
|
|
5594
|
+
}
|
|
5595
|
+
logger10.info(`\u9A8C\u8BC1\u7801\u89C6\u89C9\u4F4D\u5E8F\u6620\u5C04\uFF1A${normalizedIndexes.map((index) => index + 1).join(", ")}`);
|
|
5596
|
+
for (const imageIndex of normalizedIndexes) {
|
|
5597
|
+
if (imageIndex < 0 || imageIndex >= orderedSourceImages.length) {
|
|
5598
|
+
throw new Error(
|
|
5599
|
+
`Captcha image index ${imageIndex} is out of range. count=${orderedSourceImages.length}`
|
|
5600
|
+
);
|
|
5255
5601
|
}
|
|
5256
|
-
const sourceImage =
|
|
5602
|
+
const sourceImage = orderedSourceImages[imageIndex].locator;
|
|
5257
5603
|
await sourceImage.waitFor({
|
|
5258
5604
|
state: "visible",
|
|
5259
5605
|
timeout: config.sourceImageVisibleTimeoutMs
|
|
5260
5606
|
});
|
|
5261
|
-
await
|
|
5607
|
+
const dragResult = await dragPromptCaptchaImage(
|
|
5608
|
+
page,
|
|
5609
|
+
frame,
|
|
5610
|
+
iframeLocator,
|
|
5611
|
+
sourceImage,
|
|
5612
|
+
dropTarget,
|
|
5613
|
+
config,
|
|
5614
|
+
{
|
|
5615
|
+
attempt,
|
|
5616
|
+
visualIndex: imageIndex
|
|
5617
|
+
}
|
|
5618
|
+
);
|
|
5619
|
+
if (!dragResult.accepted) {
|
|
5620
|
+
throw new Error(`Captcha prompt drag was not accepted for visual index ${imageIndex + 1}.`);
|
|
5621
|
+
}
|
|
5622
|
+
if (config.dragBetweenWaitMs > 0) {
|
|
5623
|
+
await page.waitForTimeout(config.dragBetweenWaitMs);
|
|
5624
|
+
}
|
|
5262
5625
|
}
|
|
5263
|
-
const
|
|
5626
|
+
const beforeSubmitState = await readPromptCaptchaState(frame, config);
|
|
5627
|
+
logger10.info(
|
|
5628
|
+
`\u63D0\u4EA4\u524D\u9A8C\u8BC1\u7801\u72B6\u6001\uFF1Abadge=${beforeSubmitState.badgeCount}, selected=${beforeSubmitState.selectedCount}, submitDisabled=${beforeSubmitState.submitDisabled}`
|
|
5629
|
+
);
|
|
5630
|
+
const submitted = await clickCaptchaAction(frame, config.submitTexts, {
|
|
5631
|
+
...config,
|
|
5632
|
+
page,
|
|
5633
|
+
logger: logger10,
|
|
5634
|
+
forceMouse: true,
|
|
5635
|
+
actionVisibleTimeoutMs: config.submitReadyTimeoutMs
|
|
5636
|
+
}).catch(() => false);
|
|
5264
5637
|
if (!submitted) {
|
|
5265
5638
|
logger10.warn("\u672A\u627E\u5230\u63D0\u4EA4\u6309\u94AE\uFF0C\u53EF\u80FD\u4F1A\u81EA\u52A8\u63D0\u4EA4\u3002");
|
|
5266
5639
|
}
|
|
5267
5640
|
await page.waitForTimeout(config.submitWaitMs);
|
|
5641
|
+
const afterSubmitState = await readPromptCaptchaState(frame, config);
|
|
5642
|
+
logger10.info(
|
|
5643
|
+
`\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801\u72B6\u6001\uFF1Abadge=${afterSubmitState.badgeCount}, selected=${afterSubmitState.selectedCount}, submitDisabled=${afterSubmitState.submitDisabled}`
|
|
5644
|
+
);
|
|
5268
5645
|
const stillVisible = await iframeLocator.isVisible({ timeout: config.containerVisibleTimeoutMs }).catch(() => false);
|
|
5269
5646
|
if (!stillVisible) {
|
|
5270
5647
|
logger10.info("\u9A8C\u8BC1\u7801\u8BC6\u522B\u5E76\u63D0\u4EA4\u6210\u529F\u3002");
|
|
5271
5648
|
return true;
|
|
5272
5649
|
}
|
|
5650
|
+
await maybeCollectCaptchaDebugInfo(page, frame, iframeLocator, attempt, "submit-still-visible", config, {
|
|
5651
|
+
beforeSubmitState,
|
|
5652
|
+
afterSubmitState
|
|
5653
|
+
}).catch((error) => {
|
|
5654
|
+
logger10.warn(`\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5655
|
+
});
|
|
5273
5656
|
logger10.warn("\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801 iframe \u4ECD\u7136\u53EF\u89C1\uFF0C\u51C6\u5907\u5237\u65B0\u540E\u91CD\u8BD5\u3002");
|
|
5274
5657
|
await page.waitForTimeout(2e3);
|
|
5275
5658
|
await refreshCaptcha(page, frame, config);
|
|
@@ -5712,14 +6095,14 @@ var Mutation = {
|
|
|
5712
6095
|
const isFrameElement = tagName === "IFRAME" || tagName === "FRAME";
|
|
5713
6096
|
const nodeName = descriptor?.id || descriptor?.name || "no-id";
|
|
5714
6097
|
let source = "main";
|
|
5715
|
-
let
|
|
6098
|
+
let path3 = `${selector}[${index}]`;
|
|
5716
6099
|
let text = "";
|
|
5717
6100
|
let html = "";
|
|
5718
6101
|
let frameUrl = "";
|
|
5719
6102
|
let readyState = "";
|
|
5720
6103
|
if (isFrameElement) {
|
|
5721
6104
|
source = "iframe";
|
|
5722
|
-
|
|
6105
|
+
path3 = `${selector}[${index}]::iframe(${nodeName})`;
|
|
5723
6106
|
const frame = await handle.contentFrame();
|
|
5724
6107
|
if (frame) {
|
|
5725
6108
|
try {
|
|
@@ -5749,7 +6132,7 @@ var Mutation = {
|
|
|
5749
6132
|
items.push({
|
|
5750
6133
|
selector,
|
|
5751
6134
|
source,
|
|
5752
|
-
path:
|
|
6135
|
+
path: path3,
|
|
5753
6136
|
text,
|
|
5754
6137
|
html,
|
|
5755
6138
|
frameUrl,
|