@skrillex1224/playwright-toolkit 2.1.246 → 2.1.247
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 +238 -513
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +238 -513
- package/dist/index.js.map +4 -4
- package/index.d.ts +0 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -106,10 +106,10 @@ var createActorInfo = (info) => {
|
|
|
106
106
|
xurl
|
|
107
107
|
};
|
|
108
108
|
};
|
|
109
|
-
const buildLandingUrl = ({ protocol: protocol2, domain: domain2, path:
|
|
109
|
+
const buildLandingUrl = ({ protocol: protocol2, domain: domain2, path: path3 }) => {
|
|
110
110
|
const safeProtocol = String(protocol2).trim();
|
|
111
111
|
const safeDomain = normalizeDomain(domain2);
|
|
112
|
-
const safePath = normalizePath(
|
|
112
|
+
const safePath = normalizePath(path3);
|
|
113
113
|
return `${safeProtocol}://${safeDomain}${safePath}`;
|
|
114
114
|
};
|
|
115
115
|
const buildIcon = ({ key }) => {
|
|
@@ -117,14 +117,14 @@ var createActorInfo = (info) => {
|
|
|
117
117
|
};
|
|
118
118
|
const protocol = info.protocol || "https";
|
|
119
119
|
const domain = normalizeDomain(info.domain);
|
|
120
|
-
const
|
|
120
|
+
const path2 = normalizePath(info.path);
|
|
121
121
|
const share = normalizeShare2(info.share);
|
|
122
122
|
const device = normalizeDevice(info.device);
|
|
123
123
|
return {
|
|
124
124
|
...info,
|
|
125
125
|
protocol,
|
|
126
126
|
domain,
|
|
127
|
-
path:
|
|
127
|
+
path: path2,
|
|
128
128
|
share,
|
|
129
129
|
device,
|
|
130
130
|
get icon() {
|
|
@@ -1484,7 +1484,7 @@ var normalizeCookies = (value) => {
|
|
|
1484
1484
|
if (!name || !cookieValue || cookieValue === "<nil>") return null;
|
|
1485
1485
|
const domain = String(raw.domain || "").trim();
|
|
1486
1486
|
const url = normalizeHttpUrl(raw.url);
|
|
1487
|
-
const
|
|
1487
|
+
const path2 = String(raw.path || "").trim() || "/";
|
|
1488
1488
|
const sameSite = normalizeCookieSameSite(raw.sameSite);
|
|
1489
1489
|
const expires = normalizeCookieExpires(raw);
|
|
1490
1490
|
const secure = Boolean(raw.secure);
|
|
@@ -1493,7 +1493,7 @@ var normalizeCookies = (value) => {
|
|
|
1493
1493
|
const normalized = {
|
|
1494
1494
|
name,
|
|
1495
1495
|
value: cookieValue,
|
|
1496
|
-
path:
|
|
1496
|
+
path: path2,
|
|
1497
1497
|
...domain ? { domain } : {},
|
|
1498
1498
|
...!domain && url ? { url } : {},
|
|
1499
1499
|
...sameSite ? { sameSite } : {},
|
|
@@ -2564,10 +2564,6 @@ var assertPoint = (point) => {
|
|
|
2564
2564
|
throw new Error(`Invalid input point: ${JSON.stringify(point)}`);
|
|
2565
2565
|
}
|
|
2566
2566
|
};
|
|
2567
|
-
var toFiniteNumber = (value, fallback = 0) => {
|
|
2568
|
-
const number = Number(value);
|
|
2569
|
-
return Number.isFinite(number) ? number : fallback;
|
|
2570
|
-
};
|
|
2571
2567
|
var dispatchMouseMove = (page, point, options = {}) => page.mouse.move(point.x, point.y, options);
|
|
2572
2568
|
var dispatchMouseStart = (page, options = {}) => page.mouse.down(options);
|
|
2573
2569
|
var dispatchMouseEnd = (page, options = {}) => page.mouse.up(options);
|
|
@@ -2587,11 +2583,6 @@ var dragWithMouse = async (page, points, options = {}) => {
|
|
|
2587
2583
|
}, { steps: 2 });
|
|
2588
2584
|
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2589
2585
|
}
|
|
2590
|
-
const finalMoveRepeats = Math.max(0, Math.floor(toFiniteNumber(options.finalMoveRepeats)));
|
|
2591
|
-
for (let repeat = 0; repeat < finalMoveRepeats; repeat += 1) {
|
|
2592
|
-
await dispatchMouseMove(page, points.end, { steps: 1 });
|
|
2593
|
-
await waitFor(page, options.finalMoveDelayMs ?? 35);
|
|
2594
|
-
}
|
|
2595
2586
|
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2596
2587
|
await dispatchMouseEnd(page);
|
|
2597
2588
|
await waitFor(page, options.afterReleaseDelayMs ?? 100);
|
|
@@ -2601,7 +2592,6 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2601
2592
|
let client = null;
|
|
2602
2593
|
try {
|
|
2603
2594
|
client = await page.context().newCDPSession(page);
|
|
2604
|
-
await waitFor(page, options.initialDelayMs ?? 250);
|
|
2605
2595
|
await client.send("Input.dispatchTouchEvent", {
|
|
2606
2596
|
type: "touchStart",
|
|
2607
2597
|
touchPoints: [{ x: points.start.x, y: points.start.y, id: 1 }]
|
|
@@ -2623,14 +2613,6 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2623
2613
|
});
|
|
2624
2614
|
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2625
2615
|
}
|
|
2626
|
-
const finalMoveRepeats = Math.max(0, Math.floor(toFiniteNumber(options.finalMoveRepeats)));
|
|
2627
|
-
for (let repeat = 0; repeat < finalMoveRepeats; repeat += 1) {
|
|
2628
|
-
await client.send("Input.dispatchTouchEvent", {
|
|
2629
|
-
type: "touchMove",
|
|
2630
|
-
touchPoints: [{ x: points.end.x, y: points.end.y, id: 1 }]
|
|
2631
|
-
});
|
|
2632
|
-
await waitFor(page, options.finalMoveDelayMs ?? 35);
|
|
2633
|
-
}
|
|
2634
2616
|
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2635
2617
|
await client.send("Input.dispatchTouchEvent", {
|
|
2636
2618
|
type: "touchEnd",
|
|
@@ -2648,7 +2630,7 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2648
2630
|
var clickTargetWithDevice = async (page, target, options = {}) => {
|
|
2649
2631
|
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2650
2632
|
const resolvedDevice = resolveDeviceFromPage(page);
|
|
2651
|
-
if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick
|
|
2633
|
+
if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick) {
|
|
2652
2634
|
if (typeof target.tap === "function") {
|
|
2653
2635
|
await target.tap(normalizedOptions.tapOptions);
|
|
2654
2636
|
return true;
|
|
@@ -2848,26 +2830,20 @@ var DeviceInput = {
|
|
|
2848
2830
|
throw new Error("Unable to resolve drag coordinates.");
|
|
2849
2831
|
}
|
|
2850
2832
|
const steps = options.steps || 10;
|
|
2851
|
-
const sourceOffsetX = toFiniteNumber(options.sourceOffsetX);
|
|
2852
|
-
const sourceOffsetY = toFiniteNumber(options.sourceOffsetY);
|
|
2853
|
-
const targetOffsetX = toFiniteNumber(options.targetOffsetX);
|
|
2854
|
-
const targetOffsetY = toFiniteNumber(options.targetOffsetY);
|
|
2855
|
-
const sourceCenterX = sourceBox.x + sourceBox.width / 2 + sourceOffsetX;
|
|
2856
|
-
const sourceCenterY = sourceBox.y + sourceBox.height / 2 + sourceOffsetY;
|
|
2857
2833
|
const liftOffsetX = Math.min(18, Math.max(8, sourceBox.width * 0.12));
|
|
2858
2834
|
const liftOffsetY = Math.min(12, Math.max(4, sourceBox.height * 0.08));
|
|
2859
2835
|
const points = {
|
|
2860
2836
|
start: {
|
|
2861
|
-
x:
|
|
2862
|
-
y:
|
|
2837
|
+
x: sourceBox.x + sourceBox.width / 2,
|
|
2838
|
+
y: sourceBox.y + sourceBox.height / 2
|
|
2863
2839
|
},
|
|
2864
2840
|
lift: {
|
|
2865
|
-
x:
|
|
2866
|
-
y:
|
|
2841
|
+
x: sourceBox.x + sourceBox.width / 2 + liftOffsetX,
|
|
2842
|
+
y: sourceBox.y + sourceBox.height / 2 + liftOffsetY
|
|
2867
2843
|
},
|
|
2868
2844
|
end: {
|
|
2869
|
-
x: targetBox.x + targetBox.width / 2
|
|
2870
|
-
y: targetBox.y + targetBox.height / 2
|
|
2845
|
+
x: targetBox.x + targetBox.width / 2,
|
|
2846
|
+
y: targetBox.y + targetBox.height / 2
|
|
2871
2847
|
},
|
|
2872
2848
|
steps
|
|
2873
2849
|
};
|
|
@@ -3432,23 +3408,6 @@ var initializedPages = /* @__PURE__ */ new WeakSet();
|
|
|
3432
3408
|
var DEFAULT_TAP_TIMEOUT_MS = 2500;
|
|
3433
3409
|
var DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS = 1200;
|
|
3434
3410
|
var DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS = 900;
|
|
3435
|
-
var INTERACTIVE_SELECTOR = [
|
|
3436
|
-
"button",
|
|
3437
|
-
'[role="button"]',
|
|
3438
|
-
"a[href]",
|
|
3439
|
-
"label",
|
|
3440
|
-
"input",
|
|
3441
|
-
"textarea",
|
|
3442
|
-
"select",
|
|
3443
|
-
"summary",
|
|
3444
|
-
'[contenteditable="true"]',
|
|
3445
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
3446
|
-
].join(",");
|
|
3447
|
-
var EDITABLE_SELECTOR = [
|
|
3448
|
-
"input",
|
|
3449
|
-
"textarea",
|
|
3450
|
-
'[contenteditable="true"]'
|
|
3451
|
-
].join(",");
|
|
3452
3411
|
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
3453
3412
|
var resolveViewport = (page) => page?.viewportSize?.() || { width: 390, height: 844 };
|
|
3454
3413
|
var describeTarget = (target) => {
|
|
@@ -3488,7 +3447,7 @@ var withTimeout = async (operation, timeoutMs, label) => {
|
|
|
3488
3447
|
}
|
|
3489
3448
|
};
|
|
3490
3449
|
var checkElementVisibility = async (element) => {
|
|
3491
|
-
return element.evaluate((el
|
|
3450
|
+
return element.evaluate((el) => {
|
|
3492
3451
|
const targetStyle = window.getComputedStyle(el);
|
|
3493
3452
|
if (!targetStyle || targetStyle.display === "none" || targetStyle.visibility === "hidden" || targetStyle.visibility === "collapse") {
|
|
3494
3453
|
return { code: "NOT_INTERACTABLE", reason: "\u5143\u7D20\u4E0D\u53EF\u89C1", direction: "down" };
|
|
@@ -3550,16 +3509,30 @@ var checkElementVisibility = async (element) => {
|
|
|
3550
3509
|
positioning
|
|
3551
3510
|
};
|
|
3552
3511
|
}
|
|
3553
|
-
const
|
|
3554
|
-
const
|
|
3512
|
+
const isRootNode = (node) => !node || node === document || node === document.body || node === document.documentElement;
|
|
3513
|
+
const commonAncestor = (a, b) => {
|
|
3514
|
+
for (let current = a; current && !isRootNode(current); current = current.parentElement) {
|
|
3515
|
+
if (current.contains(b)) return current;
|
|
3516
|
+
}
|
|
3517
|
+
return null;
|
|
3518
|
+
};
|
|
3519
|
+
const sameTapTarget = (pointElement) => {
|
|
3555
3520
|
if (!pointElement) return false;
|
|
3556
3521
|
if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
|
|
3557
3522
|
return true;
|
|
3558
3523
|
}
|
|
3559
|
-
|
|
3524
|
+
const common = commonAncestor(el, pointElement);
|
|
3525
|
+
if (!common) return false;
|
|
3526
|
+
const commonRect = common.getBoundingClientRect?.();
|
|
3527
|
+
if (!commonRect || commonRect.width <= 0 || commonRect.height <= 0) return false;
|
|
3528
|
+
const commonArea = commonRect.width * commonRect.height;
|
|
3529
|
+
const targetArea = Math.max(1, rect.width * rect.height);
|
|
3530
|
+
const maxSharedRegionArea = Math.max(targetArea * 12, 4096);
|
|
3531
|
+
if (commonArea > maxSharedRegionArea) return false;
|
|
3532
|
+
if (commonRect.width > Math.max(rect.width * 8, 120) || commonRect.height > Math.max(rect.height * 8, 120)) {
|
|
3560
3533
|
return false;
|
|
3561
3534
|
}
|
|
3562
|
-
return
|
|
3535
|
+
return common.contains(el) && common.contains(pointElement);
|
|
3563
3536
|
};
|
|
3564
3537
|
const describeElement = (node) => {
|
|
3565
3538
|
if (!node) return null;
|
|
@@ -3588,7 +3561,7 @@ var checkElementVisibility = async (element) => {
|
|
|
3588
3561
|
let obstruction = null;
|
|
3589
3562
|
for (const point of samplePoints) {
|
|
3590
3563
|
const pointElement = document.elementFromPoint(point.x, point.y);
|
|
3591
|
-
if (
|
|
3564
|
+
if (sameTapTarget(pointElement)) {
|
|
3592
3565
|
return { code: "VISIBLE", isFixed, positioning };
|
|
3593
3566
|
}
|
|
3594
3567
|
obstruction = obstruction || describeElement(pointElement);
|
|
@@ -3606,10 +3579,10 @@ var checkElementVisibility = async (element) => {
|
|
|
3606
3579
|
};
|
|
3607
3580
|
}
|
|
3608
3581
|
return { code: "VISIBLE", isFixed, positioning };
|
|
3609
|
-
}
|
|
3582
|
+
});
|
|
3610
3583
|
};
|
|
3611
3584
|
var resolveSafeTapPoint = async (element) => {
|
|
3612
|
-
return element.evaluate((el
|
|
3585
|
+
return element.evaluate((el) => {
|
|
3613
3586
|
const rect = el.getBoundingClientRect();
|
|
3614
3587
|
if (!rect || rect.width <= 0 || rect.height <= 0) {
|
|
3615
3588
|
return null;
|
|
@@ -3646,16 +3619,30 @@ var resolveSafeTapPoint = async (element) => {
|
|
|
3646
3619
|
if (visibleWidth <= 1 || visibleHeight <= 1) {
|
|
3647
3620
|
return null;
|
|
3648
3621
|
}
|
|
3649
|
-
const
|
|
3650
|
-
const
|
|
3622
|
+
const isRootNode = (node) => !node || node === document || node === document.body || node === document.documentElement;
|
|
3623
|
+
const commonAncestor = (a, b) => {
|
|
3624
|
+
for (let current = a; current && !isRootNode(current); current = current.parentElement) {
|
|
3625
|
+
if (current.contains(b)) return current;
|
|
3626
|
+
}
|
|
3627
|
+
return null;
|
|
3628
|
+
};
|
|
3629
|
+
const sameTapTarget = (pointElement) => {
|
|
3651
3630
|
if (!pointElement) return false;
|
|
3652
3631
|
if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
|
|
3653
3632
|
return true;
|
|
3654
3633
|
}
|
|
3655
|
-
|
|
3634
|
+
const common = commonAncestor(el, pointElement);
|
|
3635
|
+
if (!common) return false;
|
|
3636
|
+
const commonRect = common.getBoundingClientRect?.();
|
|
3637
|
+
if (!commonRect || commonRect.width <= 0 || commonRect.height <= 0) return false;
|
|
3638
|
+
const commonArea = commonRect.width * commonRect.height;
|
|
3639
|
+
const targetArea = Math.max(1, rect.width * rect.height);
|
|
3640
|
+
const maxSharedRegionArea = Math.max(targetArea * 12, 4096);
|
|
3641
|
+
if (commonArea > maxSharedRegionArea) return false;
|
|
3642
|
+
if (commonRect.width > Math.max(rect.width * 8, 120) || commonRect.height > Math.max(rect.height * 8, 120)) {
|
|
3656
3643
|
return false;
|
|
3657
3644
|
}
|
|
3658
|
-
return
|
|
3645
|
+
return common.contains(el) && common.contains(pointElement);
|
|
3659
3646
|
};
|
|
3660
3647
|
const cx = visibleLeft + visibleWidth / 2;
|
|
3661
3648
|
const cy = visibleTop + visibleHeight / 2;
|
|
@@ -3674,7 +3661,7 @@ var resolveSafeTapPoint = async (element) => {
|
|
|
3674
3661
|
];
|
|
3675
3662
|
const safePoints = points.filter((point) => {
|
|
3676
3663
|
const pointElement = document.elementFromPoint(point.x, point.y);
|
|
3677
|
-
return
|
|
3664
|
+
return sameTapTarget(pointElement);
|
|
3678
3665
|
});
|
|
3679
3666
|
const candidates = safePoints.length ? safePoints : points;
|
|
3680
3667
|
const chosen = candidates[Math.floor(Math.random() * candidates.length)];
|
|
@@ -3683,46 +3670,57 @@ var resolveSafeTapPoint = async (element) => {
|
|
|
3683
3670
|
x: chosen.x,
|
|
3684
3671
|
y: chosen.y
|
|
3685
3672
|
};
|
|
3686
|
-
}
|
|
3673
|
+
});
|
|
3687
3674
|
};
|
|
3688
3675
|
var activateElementFallback = async (element, point = null, options = {}) => {
|
|
3689
|
-
return element.evaluate((el, {
|
|
3690
|
-
const
|
|
3691
|
-
|
|
3692
|
-
if (
|
|
3693
|
-
return node.
|
|
3676
|
+
return element.evaluate((el, { innerOptions }) => {
|
|
3677
|
+
const isEditable = (node) => {
|
|
3678
|
+
if (!node || node.nodeType !== Node.ELEMENT_NODE) return false;
|
|
3679
|
+
if (node.isContentEditable) return true;
|
|
3680
|
+
if (node instanceof HTMLTextAreaElement) return !node.disabled && !node.readOnly;
|
|
3681
|
+
if (node instanceof HTMLInputElement) {
|
|
3682
|
+
return !node.disabled && !node.readOnly && typeof node.select === "function";
|
|
3683
|
+
}
|
|
3684
|
+
return false;
|
|
3694
3685
|
};
|
|
3695
|
-
const
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
}
|
|
3701
|
-
|
|
3702
|
-
const editable = typeof target.closest === "function" ? target.closest(editableSelector) : null;
|
|
3686
|
+
const findEditable = (node) => {
|
|
3687
|
+
for (let current = node; current && current !== document.body; current = current.parentElement) {
|
|
3688
|
+
if (isEditable(current)) return current;
|
|
3689
|
+
}
|
|
3690
|
+
return null;
|
|
3691
|
+
};
|
|
3692
|
+
const editable = findEditable(el);
|
|
3703
3693
|
if (editable && typeof editable.focus === "function") {
|
|
3704
3694
|
editable.focus({ preventScroll: true });
|
|
3705
3695
|
if (innerOptions.editableOnly) {
|
|
3706
3696
|
return { activated: true, method: "focus", tag: editable.tagName || "" };
|
|
3707
3697
|
}
|
|
3708
3698
|
}
|
|
3709
|
-
if (
|
|
3710
|
-
|
|
3699
|
+
if (innerOptions.editableOnly) {
|
|
3700
|
+
return { activated: false, method: "none", tag: el?.tagName || "" };
|
|
3711
3701
|
}
|
|
3712
|
-
if (
|
|
3713
|
-
|
|
3714
|
-
|
|
3702
|
+
if (typeof el.focus === "function") {
|
|
3703
|
+
el.focus({ preventScroll: true });
|
|
3704
|
+
}
|
|
3705
|
+
if (typeof el.click === "function") {
|
|
3706
|
+
el.click();
|
|
3707
|
+
return { activated: true, method: "dom-click", tag: el.tagName || "" };
|
|
3708
|
+
}
|
|
3709
|
+
if (typeof el.dispatchEvent === "function") {
|
|
3710
|
+
el.dispatchEvent(new MouseEvent("click", {
|
|
3711
|
+
bubbles: true,
|
|
3712
|
+
cancelable: true,
|
|
3713
|
+
view: window
|
|
3714
|
+
}));
|
|
3715
|
+
return { activated: true, method: "dispatch-click", tag: el.tagName || "" };
|
|
3715
3716
|
}
|
|
3716
3717
|
return {
|
|
3717
3718
|
activated: Boolean(editable),
|
|
3718
3719
|
method: editable ? "focus" : "none",
|
|
3719
|
-
tag:
|
|
3720
|
+
tag: el?.tagName || ""
|
|
3720
3721
|
};
|
|
3721
3722
|
}, {
|
|
3722
|
-
|
|
3723
|
-
innerOptions: options || {},
|
|
3724
|
-
interactiveSelector: INTERACTIVE_SELECTOR,
|
|
3725
|
-
editableSelector: EDITABLE_SELECTOR
|
|
3723
|
+
innerOptions: options || {}
|
|
3726
3724
|
});
|
|
3727
3725
|
};
|
|
3728
3726
|
var getScrollableRect = async (element) => {
|
|
@@ -3826,6 +3824,47 @@ var scrollAwayFromObstruction = async (element, status) => {
|
|
|
3826
3824
|
};
|
|
3827
3825
|
}, status);
|
|
3828
3826
|
};
|
|
3827
|
+
var getElementViewportSnapshot = async (element) => {
|
|
3828
|
+
return element.evaluate((el) => {
|
|
3829
|
+
const rect = el.getBoundingClientRect();
|
|
3830
|
+
return {
|
|
3831
|
+
top: rect.top,
|
|
3832
|
+
bottom: rect.bottom,
|
|
3833
|
+
left: rect.left,
|
|
3834
|
+
right: rect.right,
|
|
3835
|
+
width: rect.width,
|
|
3836
|
+
height: rect.height,
|
|
3837
|
+
scrollX: window.scrollX,
|
|
3838
|
+
scrollY: window.scrollY
|
|
3839
|
+
};
|
|
3840
|
+
});
|
|
3841
|
+
};
|
|
3842
|
+
var isTargetImmobileAfterScroll = (before, after) => {
|
|
3843
|
+
if (!before || !after) return false;
|
|
3844
|
+
const rectDeltaY = Number(after.top || 0) - Number(before.top || 0);
|
|
3845
|
+
const rectDeltaX = Number(after.left || 0) - Number(before.left || 0);
|
|
3846
|
+
const scrollDeltaY = Number(after.scrollY || 0) - Number(before.scrollY || 0);
|
|
3847
|
+
const scrollDeltaX = Number(after.scrollX || 0) - Number(before.scrollX || 0);
|
|
3848
|
+
const rectMoved = Math.abs(rectDeltaY) > 3 || Math.abs(rectDeltaX) > 3;
|
|
3849
|
+
const pageMoved = Math.abs(scrollDeltaY) > 3 || Math.abs(scrollDeltaX) > 3;
|
|
3850
|
+
if (!rectMoved && !pageMoved) return true;
|
|
3851
|
+
if (pageMoved && !rectMoved) return true;
|
|
3852
|
+
if (Math.abs(scrollDeltaY) > 12 && Math.abs(rectDeltaY) < Math.min(12, Math.abs(scrollDeltaY) * 0.2)) {
|
|
3853
|
+
return true;
|
|
3854
|
+
}
|
|
3855
|
+
return false;
|
|
3856
|
+
};
|
|
3857
|
+
var restoreWindowFromSnapshot = async (page, before, after) => {
|
|
3858
|
+
if (!before || !after) return;
|
|
3859
|
+
if (Math.abs(Number(after.scrollX || 0) - Number(before.scrollX || 0)) <= 2 && Math.abs(Number(after.scrollY || 0) - Number(before.scrollY || 0)) <= 2) {
|
|
3860
|
+
return;
|
|
3861
|
+
}
|
|
3862
|
+
await page.evaluate(
|
|
3863
|
+
(state) => window.scrollTo(state.x, state.y),
|
|
3864
|
+
{ x: Number(before.scrollX || 0), y: Number(before.scrollY || 0) }
|
|
3865
|
+
).catch(() => {
|
|
3866
|
+
});
|
|
3867
|
+
};
|
|
3829
3868
|
var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
|
|
3830
3869
|
const viewport = resolveViewport(page);
|
|
3831
3870
|
const rawRect = options.rect || null;
|
|
@@ -4006,11 +4045,11 @@ var MobileHumanize = {
|
|
|
4006
4045
|
const scrollRect = await getScrollableRect(element);
|
|
4007
4046
|
if (!scrollRect && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
|
|
4008
4047
|
logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u4E0D\u5728\u89C6\u53E3\u5185\uFF0C\u9875\u9762\u6EDA\u52A8\u65E0\u6CD5\u6539\u53D8\u5176\u4F4D\u7F6E (direction=${status.direction || "unknown"})`);
|
|
4009
|
-
return { element, didScroll, restore: null };
|
|
4048
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4010
4049
|
}
|
|
4011
4050
|
if (!scrollRect && status.isFixed && status.code === "OBSTRUCTED") {
|
|
4012
4051
|
logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
|
|
4013
|
-
return { element, didScroll, restore: null };
|
|
4052
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4014
4053
|
}
|
|
4015
4054
|
if (scrollRect && status.code === "OBSTRUCTED" && status.obstruction?.isFixed) {
|
|
4016
4055
|
const moved = await scrollAwayFromObstruction(element, status);
|
|
@@ -4041,6 +4080,7 @@ var MobileHumanize = {
|
|
|
4041
4080
|
}
|
|
4042
4081
|
}
|
|
4043
4082
|
const beforeWindowState = scrollRect ? await page.evaluate(() => ({ x: window.scrollX, y: window.scrollY })) : null;
|
|
4083
|
+
const beforeElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
|
|
4044
4084
|
const beforeState = scrollRect ? await element.evaluate((el) => {
|
|
4045
4085
|
const isScrollable = (node) => {
|
|
4046
4086
|
const style = window.getComputedStyle(node);
|
|
@@ -4070,6 +4110,21 @@ var MobileHumanize = {
|
|
|
4070
4110
|
logger7.debug(`humanScroll | \u7A97\u53E3\u6EDA\u52A8\u56DE\u6536 from=${Math.round(afterWindowState.y)} to=${Math.round(beforeWindowState.y)}`);
|
|
4071
4111
|
}
|
|
4072
4112
|
}
|
|
4113
|
+
let afterElementSnapshot = null;
|
|
4114
|
+
const readAfterElementSnapshot = async () => {
|
|
4115
|
+
if (!afterElementSnapshot) {
|
|
4116
|
+
afterElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
|
|
4117
|
+
}
|
|
4118
|
+
return afterElementSnapshot;
|
|
4119
|
+
};
|
|
4120
|
+
if (!scrollRect && beforeElementSnapshot) {
|
|
4121
|
+
const afterSnapshot = await readAfterElementSnapshot();
|
|
4122
|
+
if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
|
|
4123
|
+
await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
|
|
4124
|
+
logger7.warn(`humanScroll | \u76EE\u6807\u4E0D\u968F\u9875\u9762\u6EDA\u52A8\u79FB\u52A8\uFF0C\u9875\u9762\u6EDA\u52A8\u65E0\u6CD5\u6539\u53D8\u5176\u4F4D\u7F6E (status=${status.code}, direction=${status.direction || "unknown"})`);
|
|
4125
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4073
4128
|
if (scrollRect && beforeState) {
|
|
4074
4129
|
const afterState = await element.evaluate((el) => {
|
|
4075
4130
|
const isScrollable = (node) => {
|
|
@@ -4107,6 +4162,14 @@ var MobileHumanize = {
|
|
|
4107
4162
|
}
|
|
4108
4163
|
}
|
|
4109
4164
|
}
|
|
4165
|
+
if (scrollRect && beforeElementSnapshot) {
|
|
4166
|
+
const afterSnapshot = await getElementViewportSnapshot(element).catch(() => null);
|
|
4167
|
+
if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
|
|
4168
|
+
await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
|
|
4169
|
+
logger7.warn(`humanScroll | \u76EE\u6807\u4E0D\u968F\u6EDA\u52A8\u5BB9\u5668\u79FB\u52A8\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u6539\u53D8\u5176\u4F4D\u7F6E (status=${status.code}, direction=${status.direction || "unknown"})`);
|
|
4170
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4110
4173
|
didScroll = true;
|
|
4111
4174
|
}
|
|
4112
4175
|
try {
|
|
@@ -4156,21 +4219,28 @@ var MobileHumanize = {
|
|
|
4156
4219
|
logger7.warn(`humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${targetDesc}`);
|
|
4157
4220
|
return false;
|
|
4158
4221
|
}
|
|
4159
|
-
|
|
4160
|
-
await MobileHumanize.humanScroll(page, element, { throwOnMissing });
|
|
4161
|
-
}
|
|
4222
|
+
const scrollResult = scrollIfNeeded ? await MobileHumanize.humanScroll(page, element, { throwOnMissing }) : null;
|
|
4162
4223
|
const status = await checkElementVisibility(element).catch(() => null);
|
|
4163
4224
|
if (status && status.code !== "VISIBLE") {
|
|
4164
|
-
if (fallbackDomClick && status.
|
|
4165
|
-
|
|
4225
|
+
if (fallbackDomClick && (status.code === "OUT_OF_VIEWPORT" || status.code === "OBSTRUCTED") && (status.isFixed || scrollResult?.unscrollable)) {
|
|
4226
|
+
let fallback = await withTimeout(
|
|
4166
4227
|
() => activateElementFallback(element, null, {
|
|
4167
4228
|
editableOnly: true
|
|
4168
4229
|
}),
|
|
4169
4230
|
activateFallbackTimeoutMs,
|
|
4170
4231
|
"focus fallback"
|
|
4171
4232
|
).catch(() => null);
|
|
4233
|
+
if (!fallback?.activated) {
|
|
4234
|
+
fallback = await withTimeout(
|
|
4235
|
+
() => activateElementFallback(element, null, {
|
|
4236
|
+
editableOnly: false
|
|
4237
|
+
}),
|
|
4238
|
+
activateFallbackTimeoutMs,
|
|
4239
|
+
"activation fallback"
|
|
4240
|
+
).catch(() => null);
|
|
4241
|
+
}
|
|
4172
4242
|
if (fallback?.activated) {
|
|
4173
|
-
logger7.warn(`humanClick:
|
|
4243
|
+
logger7.warn(`humanClick: \u4E0D\u53EF\u6EDA\u52A8\u76EE\u6807\u4E0D\u53EF\u7269\u7406\u70B9\u51FB\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
|
|
4174
4244
|
return true;
|
|
4175
4245
|
}
|
|
4176
4246
|
}
|
|
@@ -4287,6 +4357,20 @@ var MobileHumanize = {
|
|
|
4287
4357
|
const locator = page.locator(selector);
|
|
4288
4358
|
await MobileHumanize.humanClick(page, locator, { scrollIfNeeded: true });
|
|
4289
4359
|
await waitJitter(160, 0.4);
|
|
4360
|
+
const readValue = async () => {
|
|
4361
|
+
try {
|
|
4362
|
+
return await locator.inputValue({ timeout: 600 });
|
|
4363
|
+
} catch {
|
|
4364
|
+
return await locator.evaluate((el) => "value" in el ? String(el.value || "") : String(el.textContent || "")).catch(() => "");
|
|
4365
|
+
}
|
|
4366
|
+
};
|
|
4367
|
+
const currentValue = await readValue();
|
|
4368
|
+
if (!currentValue) return;
|
|
4369
|
+
await page.keyboard.press("ControlOrMeta+A");
|
|
4370
|
+
await waitJitter(90, 0.35);
|
|
4371
|
+
await page.keyboard.press("Backspace");
|
|
4372
|
+
await waitJitter(120, 0.35);
|
|
4373
|
+
if (!await readValue()) return;
|
|
4290
4374
|
await locator.evaluate((el) => {
|
|
4291
4375
|
if ("value" in el) {
|
|
4292
4376
|
el.value = "";
|
|
@@ -4876,10 +4960,6 @@ var LiveView = {
|
|
|
4876
4960
|
// src/chaptcha.js
|
|
4877
4961
|
import { v4 as uuidv4 } from "uuid";
|
|
4878
4962
|
|
|
4879
|
-
// src/internals/captcha/bytedance.js
|
|
4880
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
4881
|
-
import path2 from "path";
|
|
4882
|
-
|
|
4883
4963
|
// src/internals/captcha/shared.js
|
|
4884
4964
|
var waitForVisible = async (locator, timeout) => {
|
|
4885
4965
|
try {
|
|
@@ -4897,71 +4977,38 @@ var isAnyCaptchaTextVisible = async (frame, texts, timeout) => {
|
|
|
4897
4977
|
if (!text) {
|
|
4898
4978
|
continue;
|
|
4899
4979
|
}
|
|
4900
|
-
const
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
if (isVisible) {
|
|
4909
|
-
return true;
|
|
4910
|
-
}
|
|
4980
|
+
const candidates = [
|
|
4981
|
+
frame.getByText(text, { exact: false }).first(),
|
|
4982
|
+
frame.locator(`text=${text}`).first()
|
|
4983
|
+
];
|
|
4984
|
+
for (const candidate of candidates) {
|
|
4985
|
+
const isVisible = await candidate.isVisible({ timeout }).catch(() => false);
|
|
4986
|
+
if (isVisible) {
|
|
4987
|
+
return true;
|
|
4911
4988
|
}
|
|
4912
4989
|
}
|
|
4913
4990
|
}
|
|
4914
4991
|
return false;
|
|
4915
4992
|
};
|
|
4916
|
-
var collectVisibleCandidateIndexes = async (candidateGroup, count, timeout) => {
|
|
4917
|
-
const visibleIndexes = [];
|
|
4918
|
-
for (let index = 0; index < count; index += 1) {
|
|
4919
|
-
const candidate = candidateGroup.nth(index);
|
|
4920
|
-
const isVisible = await candidate.isVisible({ timeout }).catch(() => false);
|
|
4921
|
-
if (isVisible) {
|
|
4922
|
-
visibleIndexes.push(index);
|
|
4923
|
-
}
|
|
4924
|
-
}
|
|
4925
|
-
return visibleIndexes;
|
|
4926
|
-
};
|
|
4927
4993
|
var clickCaptchaAction = async (frame, texts, options) => {
|
|
4928
4994
|
for (const text of texts || []) {
|
|
4929
|
-
const
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
textLocator.count().catch(() => 0),
|
|
4933
|
-
locatorText.count().catch(() => 0)
|
|
4934
|
-
]);
|
|
4935
|
-
const [getByTextVisibleIndexes, locatorTextVisibleIndexes] = await Promise.all([
|
|
4936
|
-
collectVisibleCandidateIndexes(textLocator, getByTextCount, options.actionVisibleTimeoutMs),
|
|
4937
|
-
collectVisibleCandidateIndexes(locatorText, locatorTextCount, options.actionVisibleTimeoutMs)
|
|
4938
|
-
]);
|
|
4939
|
-
options.logger?.info(
|
|
4940
|
-
`[CaptchaAction] \u6587\u672C "${text}" \u547D\u4E2D\u6570\u91CF\uFF1AgetByText=${getByTextCount} (visible=${getByTextVisibleIndexes.length}), locator=${locatorTextCount} (visible=${locatorTextVisibleIndexes.length})`
|
|
4941
|
-
);
|
|
4942
|
-
const candidateGroups = [
|
|
4943
|
-
{ label: "getByText", locator: textLocator, count: getByTextCount },
|
|
4944
|
-
{ label: "locator", locator: locatorText, count: locatorTextCount }
|
|
4995
|
+
const candidates = [
|
|
4996
|
+
frame.getByText(text, { exact: false }).first(),
|
|
4997
|
+
frame.locator(`text=${text}`).first()
|
|
4945
4998
|
];
|
|
4946
|
-
for (const
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
if (!isVisible) {
|
|
4951
|
-
continue;
|
|
4952
|
-
}
|
|
4953
|
-
options.logger?.info(
|
|
4954
|
-
`[CaptchaAction] \u6587\u672C "${text}" \u9009\u62E9 ${candidateGroup.label}[${index}] \u4F5C\u4E3A\u7B2C\u4E00\u4E2A\u53EF\u89C1\u8282\u70B9\u6267\u884C\u70B9\u51FB\u3002`
|
|
4955
|
-
);
|
|
4956
|
-
await DeviceInput.click(options.page, candidate, options);
|
|
4957
|
-
return true;
|
|
4999
|
+
for (const candidate of candidates) {
|
|
5000
|
+
const isVisible = await waitForVisible(candidate, options.actionVisibleTimeoutMs);
|
|
5001
|
+
if (!isVisible) {
|
|
5002
|
+
continue;
|
|
4958
5003
|
}
|
|
5004
|
+
await DeviceInput.click(options.page, candidate);
|
|
5005
|
+
return true;
|
|
4959
5006
|
}
|
|
4960
5007
|
}
|
|
4961
5008
|
return false;
|
|
4962
5009
|
};
|
|
4963
|
-
var dragCaptchaAction = async (page, sourceLocator, targetLocator
|
|
4964
|
-
await DeviceInput.drag(page, sourceLocator, targetLocator
|
|
5010
|
+
var dragCaptchaAction = async (page, sourceLocator, targetLocator) => {
|
|
5011
|
+
await DeviceInput.drag(page, sourceLocator, targetLocator);
|
|
4965
5012
|
};
|
|
4966
5013
|
|
|
4967
5014
|
// src/internals/captcha/bytedance.js
|
|
@@ -4972,12 +5019,11 @@ var DEFAULT_BYTEDANCE_CAPTCHA_OPTIONS = Object.freeze({
|
|
|
4972
5019
|
containerSelector: "#captcha_container",
|
|
4973
5020
|
iframeSelector: 'iframe[src*="verifycenter"]',
|
|
4974
5021
|
iframeFallbackSelector: "iframe",
|
|
4975
|
-
sourceImageSelector: ".
|
|
4976
|
-
dropTargetContainerSelector: "
|
|
5022
|
+
sourceImageSelector: "div.canvas-container",
|
|
5023
|
+
dropTargetContainerSelector: "#captcha_verify_image div",
|
|
4977
5024
|
dropTargetTexts: ["\u62D6\u62FD\u5230\u8FD9\u91CC"],
|
|
4978
5025
|
refreshTexts: ["\u5237\u65B0"],
|
|
4979
5026
|
submitTexts: ["\u63D0\u4EA4"],
|
|
4980
|
-
guideMaskSelector: ".play-guide-mask",
|
|
4981
5027
|
recognitionSuccessCode: 1e4,
|
|
4982
5028
|
containerVisibleTimeoutMs: 2e3,
|
|
4983
5029
|
iframeVisibleTimeoutMs: 12e3,
|
|
@@ -5000,111 +5046,10 @@ var DEFAULT_BYTEDANCE_CAPTCHA_OPTIONS = Object.freeze({
|
|
|
5000
5046
|
],
|
|
5001
5047
|
recognitionDelayMs: 2e3,
|
|
5002
5048
|
refreshWaitMs: 3e3,
|
|
5003
|
-
submitWaitMs:
|
|
5004
|
-
submitReadyTimeoutMs: 2500,
|
|
5049
|
+
submitWaitMs: 3e3,
|
|
5005
5050
|
retryDelayBaseMs: 2e3,
|
|
5006
|
-
retryDelayStepMs: 1e3
|
|
5007
|
-
sourceImageRowTolerancePx: 24,
|
|
5008
|
-
dragBetweenWaitMs: 250,
|
|
5009
|
-
promptBadgeCountSelector: ".drag-area .photo-badge .badge span",
|
|
5010
|
-
promptSubmitButtonSelector: ".vc-captcha-verify-mobile-button",
|
|
5011
|
-
promptSelectedSourceSelector: ".img-container .canvas-container.selected",
|
|
5012
|
-
promptActiveSourceSelector: ".img-container .canvas-container.active",
|
|
5013
|
-
promptDragMoveSteps: 16,
|
|
5014
|
-
promptDragStepDelayMs: 55,
|
|
5015
|
-
promptDragHoldDelayMs: 240,
|
|
5016
|
-
promptDragBeforeReleaseDelayMs: 180,
|
|
5017
|
-
promptDragAfterReleaseDelayMs: 240,
|
|
5018
|
-
promptDragFinalMoveRepeats: 3,
|
|
5019
|
-
promptDragRetryDelayMs: 250,
|
|
5020
|
-
debugArtifacts: false
|
|
5051
|
+
retryDelayStepMs: 1e3
|
|
5021
5052
|
});
|
|
5022
|
-
var PROMPT_CAPTCHA_DRAG_PLANS = Object.freeze([
|
|
5023
|
-
{ name: "lower-middle", endXRatio: 0.5, endYRatio: 0.72 },
|
|
5024
|
-
{ name: "center-middle", endXRatio: 0.5, endYRatio: 0.56 },
|
|
5025
|
-
{ name: "upper-middle", endXRatio: 0.5, endYRatio: 0.4 }
|
|
5026
|
-
]);
|
|
5027
|
-
var resolveCaptchaDebugDir = () => path2.resolve(process.cwd(), "storage", "captcha-debug");
|
|
5028
|
-
var rectOf = (rect) => {
|
|
5029
|
-
if (!rect) {
|
|
5030
|
-
return null;
|
|
5031
|
-
}
|
|
5032
|
-
return {
|
|
5033
|
-
x: Number(rect.x.toFixed(2)),
|
|
5034
|
-
y: Number(rect.y.toFixed(2)),
|
|
5035
|
-
width: Number(rect.width.toFixed(2)),
|
|
5036
|
-
height: Number(rect.height.toFixed(2))
|
|
5037
|
-
};
|
|
5038
|
-
};
|
|
5039
|
-
var collectCaptchaDebugInfo = async (page, frame, iframeLocator, attempt, phase, extra = null) => {
|
|
5040
|
-
const timestamp = Date.now();
|
|
5041
|
-
const debugDir = resolveCaptchaDebugDir();
|
|
5042
|
-
await mkdir(debugDir, { recursive: true });
|
|
5043
|
-
const baseName = `bytedance-${timestamp}-attempt${attempt}-${phase}`;
|
|
5044
|
-
const iframeScreenshotPath = path2.join(debugDir, `${baseName}-iframe.png`);
|
|
5045
|
-
const pageScreenshotPath = path2.join(debugDir, `${baseName}-page.png`);
|
|
5046
|
-
const htmlPath = path2.join(debugDir, `${baseName}-iframe.html`);
|
|
5047
|
-
const infoPath = path2.join(debugDir, `${baseName}-info.json`);
|
|
5048
|
-
await iframeLocator.screenshot({ path: iframeScreenshotPath }).catch(() => {
|
|
5049
|
-
});
|
|
5050
|
-
await page.screenshot({ path: pageScreenshotPath, fullPage: true }).catch(() => {
|
|
5051
|
-
});
|
|
5052
|
-
const html = await frame.evaluate(() => document.documentElement.outerHTML).catch(() => "");
|
|
5053
|
-
if (html) {
|
|
5054
|
-
await writeFile(htmlPath, html, "utf8");
|
|
5055
|
-
}
|
|
5056
|
-
const info = await frame.evaluate(() => {
|
|
5057
|
-
const toRect = (element) => {
|
|
5058
|
-
const rect = element.getBoundingClientRect();
|
|
5059
|
-
return {
|
|
5060
|
-
x: Number(rect.x.toFixed(2)),
|
|
5061
|
-
y: Number(rect.y.toFixed(2)),
|
|
5062
|
-
width: Number(rect.width.toFixed(2)),
|
|
5063
|
-
height: Number(rect.height.toFixed(2))
|
|
5064
|
-
};
|
|
5065
|
-
};
|
|
5066
|
-
const toItem = (element, index) => ({
|
|
5067
|
-
index,
|
|
5068
|
-
tag: element.tagName,
|
|
5069
|
-
id: element.id || "",
|
|
5070
|
-
className: typeof element.className === "string" ? element.className : "",
|
|
5071
|
-
text: String(element.textContent || "").trim(),
|
|
5072
|
-
rect: toRect(element)
|
|
5073
|
-
});
|
|
5074
|
-
const visibleNodes = Array.from(document.querySelectorAll("body *")).map(toItem).filter((item) => item.rect.width > 0 && item.rect.height > 0);
|
|
5075
|
-
return {
|
|
5076
|
-
title: document.title,
|
|
5077
|
-
bodyText: String(document.body?.innerText || "").trim(),
|
|
5078
|
-
canvasContainers: visibleNodes.filter((item) => item.className.includes("canvas-container")),
|
|
5079
|
-
canvasNodes: visibleNodes.filter((item) => item.tag === "CANVAS"),
|
|
5080
|
-
captchaNodes: visibleNodes.filter((item) => item.id.startsWith("captcha_") || item.className.includes("captcha") || item.className.includes("verify") || /拖拽到这里|刷新|提交/.test(item.text)),
|
|
5081
|
-
visibleTextNodes: visibleNodes.filter((item) => item.text).slice(0, 300)
|
|
5082
|
-
};
|
|
5083
|
-
}).catch(() => null);
|
|
5084
|
-
if (info) {
|
|
5085
|
-
const payload = {
|
|
5086
|
-
capturedAt: new Date(timestamp).toISOString(),
|
|
5087
|
-
pageUrl: page.url(),
|
|
5088
|
-
attempt,
|
|
5089
|
-
phase,
|
|
5090
|
-
iframeScreenshotPath,
|
|
5091
|
-
pageScreenshotPath,
|
|
5092
|
-
htmlPath,
|
|
5093
|
-
info
|
|
5094
|
-
};
|
|
5095
|
-
if (extra != null) {
|
|
5096
|
-
payload.extra = extra;
|
|
5097
|
-
}
|
|
5098
|
-
await writeFile(infoPath, JSON.stringify(payload, null, 2), "utf8");
|
|
5099
|
-
}
|
|
5100
|
-
logger10.info(`\u5DF2\u5199\u51FA\u9A8C\u8BC1\u7801\u8C03\u8BD5\u4EA7\u7269\uFF1A${debugDir}`);
|
|
5101
|
-
};
|
|
5102
|
-
var maybeCollectCaptchaDebugInfo = async (page, frame, iframeLocator, attempt, phase, options, extra = null) => {
|
|
5103
|
-
if (!options.debugArtifacts) {
|
|
5104
|
-
return;
|
|
5105
|
-
}
|
|
5106
|
-
await collectCaptchaDebugInfo(page, frame, iframeLocator, attempt, phase, extra);
|
|
5107
|
-
};
|
|
5108
5053
|
var extractCaptchaSerialNumbers = (apiResponse) => {
|
|
5109
5054
|
const serialNumbers = apiResponse?.data?.data?.serial_number;
|
|
5110
5055
|
if (!Array.isArray(serialNumbers)) {
|
|
@@ -5113,7 +5058,7 @@ var extractCaptchaSerialNumbers = (apiResponse) => {
|
|
|
5113
5058
|
return serialNumbers.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value >= 0);
|
|
5114
5059
|
};
|
|
5115
5060
|
var resolveContentFrame = async (page, iframeLocator, options) => {
|
|
5116
|
-
for (let attempt = 1; attempt <= options.contentFrameResolveRetries; attempt
|
|
5061
|
+
for (let attempt = 1; attempt <= options.contentFrameResolveRetries; attempt++) {
|
|
5117
5062
|
const iframeHandle = await iframeLocator.elementHandle();
|
|
5118
5063
|
const frame = await iframeHandle?.contentFrame();
|
|
5119
5064
|
if (frame) {
|
|
@@ -5158,15 +5103,20 @@ var getVerifycenterCaptchaContext = async (page, options) => {
|
|
|
5158
5103
|
}
|
|
5159
5104
|
return { iframeLocator, frame };
|
|
5160
5105
|
};
|
|
5161
|
-
var
|
|
5162
|
-
const
|
|
5163
|
-
if (
|
|
5164
|
-
|
|
5106
|
+
var refreshCaptcha = async (page, frame, options) => {
|
|
5107
|
+
const clicked = await clickCaptchaAction(frame, options.refreshTexts, { ...options, page }).catch(() => false);
|
|
5108
|
+
if (!clicked) {
|
|
5109
|
+
logger10.warn("Refresh button not found.");
|
|
5110
|
+
return false;
|
|
5165
5111
|
}
|
|
5112
|
+
await page.waitForTimeout(options.refreshWaitMs);
|
|
5113
|
+
return true;
|
|
5114
|
+
};
|
|
5115
|
+
var findCaptchaDropTarget = async (frame, options) => {
|
|
5166
5116
|
for (const text of options.dropTargetTexts) {
|
|
5167
5117
|
const candidates = [
|
|
5168
|
-
frame.
|
|
5169
|
-
frame.
|
|
5118
|
+
frame.locator(options.dropTargetContainerSelector).filter({ hasText: text }).first(),
|
|
5119
|
+
frame.getByText(text, { exact: false }).first()
|
|
5170
5120
|
];
|
|
5171
5121
|
for (const candidate of candidates) {
|
|
5172
5122
|
const isVisible = await waitForVisible(candidate, options.actionVisibleTimeoutMs);
|
|
@@ -5177,112 +5127,10 @@ var findCaptchaDropTarget = async (frame, options) => {
|
|
|
5177
5127
|
}
|
|
5178
5128
|
return null;
|
|
5179
5129
|
};
|
|
5180
|
-
var readPromptCaptchaState = async (frame, options) => frame.evaluate((selectors) => {
|
|
5181
|
-
const toRect = (element) => {
|
|
5182
|
-
if (!element) {
|
|
5183
|
-
return null;
|
|
5184
|
-
}
|
|
5185
|
-
const rect = element.getBoundingClientRect();
|
|
5186
|
-
return {
|
|
5187
|
-
x: Number(rect.x.toFixed(2)),
|
|
5188
|
-
y: Number(rect.y.toFixed(2)),
|
|
5189
|
-
width: Number(rect.width.toFixed(2)),
|
|
5190
|
-
height: Number(rect.height.toFixed(2))
|
|
5191
|
-
};
|
|
5192
|
-
};
|
|
5193
|
-
const badgeNode = document.querySelector(selectors.badgeCountSelector);
|
|
5194
|
-
const submitButton = document.querySelector(selectors.submitButtonSelector);
|
|
5195
|
-
const dragArea = document.querySelector(selectors.dragAreaSelector);
|
|
5196
|
-
const badgeCount = badgeNode ? Number.parseInt(String(badgeNode.textContent || "").trim(), 10) : 0;
|
|
5197
|
-
return {
|
|
5198
|
-
badgeCount: Number.isFinite(badgeCount) ? badgeCount : 0,
|
|
5199
|
-
selectedCount: document.querySelectorAll(selectors.selectedSourceSelector).length,
|
|
5200
|
-
activeCount: document.querySelectorAll(selectors.activeSourceSelector).length,
|
|
5201
|
-
submitDisabled: submitButton ? submitButton.classList.contains("disable") : null,
|
|
5202
|
-
dragAreaActive: dragArea ? dragArea.classList.contains("active") : false,
|
|
5203
|
-
dragAreaRect: toRect(dragArea)
|
|
5204
|
-
};
|
|
5205
|
-
}, {
|
|
5206
|
-
badgeCountSelector: options.promptBadgeCountSelector,
|
|
5207
|
-
submitButtonSelector: options.promptSubmitButtonSelector,
|
|
5208
|
-
selectedSourceSelector: options.promptSelectedSourceSelector,
|
|
5209
|
-
activeSourceSelector: options.promptActiveSourceSelector,
|
|
5210
|
-
dragAreaSelector: options.dropTargetContainerSelector
|
|
5211
|
-
}).catch(() => ({
|
|
5212
|
-
badgeCount: 0,
|
|
5213
|
-
selectedCount: 0,
|
|
5214
|
-
activeCount: 0,
|
|
5215
|
-
submitDisabled: null,
|
|
5216
|
-
dragAreaActive: false,
|
|
5217
|
-
dragAreaRect: null
|
|
5218
|
-
}));
|
|
5219
|
-
var normalizeCaptchaImageIndexes = (serialNumbers, imageCount) => {
|
|
5220
|
-
if (!Array.isArray(serialNumbers) || imageCount <= 0) {
|
|
5221
|
-
return [];
|
|
5222
|
-
}
|
|
5223
|
-
const areAllOneBased = serialNumbers.every((value) => value >= 1 && value <= imageCount);
|
|
5224
|
-
if (areAllOneBased) {
|
|
5225
|
-
return serialNumbers.map((value) => value - 1);
|
|
5226
|
-
}
|
|
5227
|
-
const areAllZeroBased = serialNumbers.every((value) => value >= 0 && value < imageCount);
|
|
5228
|
-
if (areAllZeroBased) {
|
|
5229
|
-
return [...serialNumbers];
|
|
5230
|
-
}
|
|
5231
|
-
return serialNumbers.map((value) => {
|
|
5232
|
-
if (value >= 1 && value <= imageCount) {
|
|
5233
|
-
return value - 1;
|
|
5234
|
-
}
|
|
5235
|
-
if (value >= 0 && value < imageCount) {
|
|
5236
|
-
return value;
|
|
5237
|
-
}
|
|
5238
|
-
return null;
|
|
5239
|
-
}).filter((value) => Number.isInteger(value));
|
|
5240
|
-
};
|
|
5241
|
-
var resolveCaptchaSourceImagesInVisualOrder = async (frame, options) => {
|
|
5242
|
-
const sourceImages = frame.locator(options.sourceImageSelector);
|
|
5243
|
-
const imageCount = await sourceImages.count().catch(() => 0);
|
|
5244
|
-
const sources = [];
|
|
5245
|
-
for (let domIndex = 0; domIndex < imageCount; domIndex += 1) {
|
|
5246
|
-
const locator = sourceImages.nth(domIndex);
|
|
5247
|
-
const box = await locator.boundingBox().catch(() => null);
|
|
5248
|
-
if (!box || box.width <= 0 || box.height <= 0) {
|
|
5249
|
-
continue;
|
|
5250
|
-
}
|
|
5251
|
-
sources.push({
|
|
5252
|
-
domIndex,
|
|
5253
|
-
locator,
|
|
5254
|
-
box
|
|
5255
|
-
});
|
|
5256
|
-
}
|
|
5257
|
-
sources.sort((left, right) => {
|
|
5258
|
-
const deltaY = left.box.y - right.box.y;
|
|
5259
|
-
if (Math.abs(deltaY) > options.sourceImageRowTolerancePx) {
|
|
5260
|
-
return deltaY;
|
|
5261
|
-
}
|
|
5262
|
-
return left.box.x - right.box.x;
|
|
5263
|
-
});
|
|
5264
|
-
return sources;
|
|
5265
|
-
};
|
|
5266
|
-
var refreshCaptcha = async (page, frame, options) => {
|
|
5267
|
-
const clicked = await clickCaptchaAction(frame, options.refreshTexts, {
|
|
5268
|
-
...options,
|
|
5269
|
-
page,
|
|
5270
|
-
logger: logger10,
|
|
5271
|
-
forceMouse: true
|
|
5272
|
-
}).catch(() => false);
|
|
5273
|
-
if (!clicked) {
|
|
5274
|
-
logger10.warn("Refresh button not found.");
|
|
5275
|
-
return false;
|
|
5276
|
-
}
|
|
5277
|
-
await page.waitForTimeout(options.refreshWaitMs);
|
|
5278
|
-
return true;
|
|
5279
|
-
};
|
|
5280
5130
|
var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
5281
5131
|
const deadline = Date.now() + options.challengeReadyTimeoutMs;
|
|
5282
5132
|
let refreshDeadline = Date.now() + options.challengeReadyRefreshTimeoutMs;
|
|
5283
5133
|
let hasSeenLoading = false;
|
|
5284
|
-
let hasSeenGuideMask = false;
|
|
5285
|
-
let hasLoggedGuideMask = false;
|
|
5286
5134
|
while (Date.now() < deadline) {
|
|
5287
5135
|
const isLoadingVisible = await isAnyCaptchaTextVisible(
|
|
5288
5136
|
frame,
|
|
@@ -5298,17 +5146,8 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5298
5146
|
const sourceImages = frame.locator(options.sourceImageSelector);
|
|
5299
5147
|
const imageCount = await sourceImages.count().catch(() => 0);
|
|
5300
5148
|
const hasVisibleSourceImage = imageCount > 0 ? await sourceImages.first().isVisible({ timeout: options.loadingIndicatorVisibleTimeoutMs }).catch(() => false) : false;
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
hasSeenGuideMask = hasSeenGuideMask || hasGuideMaskVisible;
|
|
5304
|
-
if (hasGuideMaskVisible && !hasLoggedGuideMask) {
|
|
5305
|
-
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");
|
|
5306
|
-
hasLoggedGuideMask = true;
|
|
5307
|
-
}
|
|
5308
|
-
if (!isLoadingVisible && hasVisibleSourceImage && hasVisibleDropTarget && !hasGuideMaskVisible) {
|
|
5309
|
-
logger10.info(
|
|
5310
|
-
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"
|
|
5311
|
-
);
|
|
5149
|
+
if (!isLoadingVisible && hasVisibleSourceImage) {
|
|
5150
|
+
logger10.info(hasSeenLoading ? "\u9A8C\u8BC1\u7801\u56FE\u7247\u5DF2\u52A0\u8F7D\u5B8C\u6210\u3002" : "\u9A8C\u8BC1\u7801\u56FE\u7247\u5DF2\u5C31\u7EEA\u3002");
|
|
5312
5151
|
return;
|
|
5313
5152
|
}
|
|
5314
5153
|
if (hasErrorTextVisible) {
|
|
@@ -5318,8 +5157,8 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5318
5157
|
hasSeenLoading = false;
|
|
5319
5158
|
continue;
|
|
5320
5159
|
}
|
|
5321
|
-
if (
|
|
5322
|
-
logger10.warn(`\u9A8C\u8BC1\u7801\
|
|
5160
|
+
if (!hasVisibleSourceImage && Date.now() >= refreshDeadline) {
|
|
5161
|
+
logger10.warn(`\u9A8C\u8BC1\u7801\u56FE\u7247\u8D85\u8FC7 ${options.challengeReadyRefreshTimeoutMs}ms \u4ECD\u672A\u51FA\u73B0\uFF0C\u5C1D\u8BD5\u5237\u65B0\u9898\u76EE\u3002`);
|
|
5323
5162
|
await refreshCaptcha(page, frame, options);
|
|
5324
5163
|
refreshDeadline = Date.now() + options.challengeReadyRefreshTimeoutMs;
|
|
5325
5164
|
hasSeenLoading = false;
|
|
@@ -5329,69 +5168,6 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5329
5168
|
}
|
|
5330
5169
|
throw new Error("Captcha challenge is still loading and did not become ready in time.");
|
|
5331
5170
|
};
|
|
5332
|
-
var dragPromptCaptchaImage = async (page, frame, iframeLocator, sourceLocator, dropTarget, options, {
|
|
5333
|
-
attempt,
|
|
5334
|
-
visualIndex
|
|
5335
|
-
}) => {
|
|
5336
|
-
const baselineState = await readPromptCaptchaState(frame, options);
|
|
5337
|
-
const dragAttempts = [];
|
|
5338
|
-
for (const plan of PROMPT_CAPTCHA_DRAG_PLANS) {
|
|
5339
|
-
const sourceBox = await sourceLocator.boundingBox().catch(() => null);
|
|
5340
|
-
const targetBox = await dropTarget.boundingBox().catch(() => null);
|
|
5341
|
-
if (!sourceBox || !targetBox) {
|
|
5342
|
-
throw new Error("Unable to resolve prompt captcha drag coordinates.");
|
|
5343
|
-
}
|
|
5344
|
-
const targetOffsetX = (plan.endXRatio - 0.5) * targetBox.width;
|
|
5345
|
-
const targetOffsetY = (plan.endYRatio - 0.5) * targetBox.height;
|
|
5346
|
-
await dragCaptchaAction(page, sourceLocator, dropTarget, {
|
|
5347
|
-
forceMouse: true,
|
|
5348
|
-
targetOffsetX,
|
|
5349
|
-
targetOffsetY,
|
|
5350
|
-
steps: options.promptDragMoveSteps,
|
|
5351
|
-
holdDelayMs: options.promptDragHoldDelayMs,
|
|
5352
|
-
stepDelayMs: options.promptDragStepDelayMs,
|
|
5353
|
-
beforeReleaseDelayMs: options.promptDragBeforeReleaseDelayMs,
|
|
5354
|
-
afterReleaseDelayMs: options.promptDragAfterReleaseDelayMs,
|
|
5355
|
-
finalMoveRepeats: options.promptDragFinalMoveRepeats
|
|
5356
|
-
});
|
|
5357
|
-
const afterState = await readPromptCaptchaState(frame, options);
|
|
5358
|
-
const accepted = afterState.badgeCount > baselineState.badgeCount || afterState.selectedCount > baselineState.selectedCount;
|
|
5359
|
-
const attemptInfo = {
|
|
5360
|
-
planName: plan.name,
|
|
5361
|
-
sourceRect: rectOf(sourceBox),
|
|
5362
|
-
targetRect: rectOf(targetBox),
|
|
5363
|
-
targetOffsetX: Number(targetOffsetX.toFixed(2)),
|
|
5364
|
-
targetOffsetY: Number(targetOffsetY.toFixed(2)),
|
|
5365
|
-
beforeState: baselineState,
|
|
5366
|
-
afterState,
|
|
5367
|
-
accepted
|
|
5368
|
-
};
|
|
5369
|
-
dragAttempts.push(attemptInfo);
|
|
5370
|
-
logger10.info(
|
|
5371
|
-
`\u9A8C\u8BC1\u7801\u62D6\u62FD\u7B2C ${visualIndex + 1} \u5F20\uFF0C\u65B9\u6848 ${plan.name}\uFF0Cbadge ${baselineState.badgeCount} -> ${afterState.badgeCount}\uFF0Cselected ${baselineState.selectedCount} -> ${afterState.selectedCount}`
|
|
5372
|
-
);
|
|
5373
|
-
if (accepted) {
|
|
5374
|
-
return {
|
|
5375
|
-
accepted: true,
|
|
5376
|
-
dragAttempts
|
|
5377
|
-
};
|
|
5378
|
-
}
|
|
5379
|
-
if (options.promptDragRetryDelayMs > 0) {
|
|
5380
|
-
await page.waitForTimeout(options.promptDragRetryDelayMs);
|
|
5381
|
-
}
|
|
5382
|
-
}
|
|
5383
|
-
await maybeCollectCaptchaDebugInfo(page, frame, iframeLocator, attempt, `drag-${visualIndex + 1}-failed`, options, {
|
|
5384
|
-
visualIndex,
|
|
5385
|
-
dragAttempts,
|
|
5386
|
-
finalState: await readPromptCaptchaState(frame, options)
|
|
5387
|
-
}).catch((error) => {
|
|
5388
|
-
logger10.warn(`\u9A8C\u8BC1\u7801\u62D6\u62FD\u5931\u8D25\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5389
|
-
});
|
|
5390
|
-
return {
|
|
5391
|
-
accepted: false,
|
|
5392
|
-
dragAttempts
|
|
5393
|
-
};
|
|
5394
|
-
};
|
|
5395
5171
|
async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
5396
5172
|
const { callCaptchaRecognitionApi: callCaptchaRecognitionApi2 } = dependencies;
|
|
5397
5173
|
if (typeof callCaptchaRecognitionApi2 !== "function") {
|
|
@@ -5406,7 +5182,7 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5406
5182
|
return false;
|
|
5407
5183
|
}
|
|
5408
5184
|
logger10.info("\u5F53\u524D\u4F7F\u7528\u672Ctool\u2014\u2014\u6D4B\u8BD5\u7248\u672C");
|
|
5409
|
-
for (let attempt = 1; attempt <= config.maxRetries; attempt
|
|
5185
|
+
for (let attempt = 1; attempt <= config.maxRetries; attempt++) {
|
|
5410
5186
|
logger10.info(`\u5F00\u59CB\u7B2C ${attempt}/${config.maxRetries} \u6B21 verifycenter \u9A8C\u8BC1\u7801\u8BC6\u522B\u3002`);
|
|
5411
5187
|
try {
|
|
5412
5188
|
const captchaContext = await getVerifycenterCaptchaContext(page, config);
|
|
@@ -5416,16 +5192,6 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5416
5192
|
}
|
|
5417
5193
|
const { iframeLocator, frame } = captchaContext;
|
|
5418
5194
|
await waitForCaptchaChallengeReady(page, frame, config);
|
|
5419
|
-
await maybeCollectCaptchaDebugInfo(
|
|
5420
|
-
page,
|
|
5421
|
-
frame,
|
|
5422
|
-
iframeLocator,
|
|
5423
|
-
attempt,
|
|
5424
|
-
"ready",
|
|
5425
|
-
config
|
|
5426
|
-
).catch((error) => {
|
|
5427
|
-
logger10.warn(`\u9A8C\u8BC1\u7801\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5428
|
-
});
|
|
5429
5195
|
await page.waitForTimeout(config.recognitionDelayMs);
|
|
5430
5196
|
const screenshotBuffer = await iframeLocator.screenshot();
|
|
5431
5197
|
const apiResponse = await callCaptchaRecognitionApi2({
|
|
@@ -5449,74 +5215,33 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5449
5215
|
await refreshCaptcha(page, frame, config);
|
|
5450
5216
|
continue;
|
|
5451
5217
|
}
|
|
5452
|
-
const
|
|
5453
|
-
const
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
}
|
|
5459
|
-
logger10.info(`\u9A8C\u8BC1\u7801\u89C6\u89C9\u4F4D\u5E8F\u6620\u5C04\uFF1A${normalizedIndexes.map((index) => index + 1).join(", ")}`);
|
|
5460
|
-
for (const imageIndex of normalizedIndexes) {
|
|
5461
|
-
if (imageIndex < 0 || imageIndex >= orderedSourceImages.length) {
|
|
5462
|
-
throw new Error(
|
|
5463
|
-
`Captcha image index ${imageIndex} is out of range. count=${orderedSourceImages.length}`
|
|
5464
|
-
);
|
|
5218
|
+
const sourceImages = frame.locator(config.sourceImageSelector);
|
|
5219
|
+
const imageCount = await sourceImages.count();
|
|
5220
|
+
for (const rawIndex of serialNumbers) {
|
|
5221
|
+
let imageIndex = rawIndex;
|
|
5222
|
+
if (imageIndex >= imageCount && imageIndex > 0 && imageIndex - 1 < imageCount) {
|
|
5223
|
+
imageIndex -= 1;
|
|
5465
5224
|
}
|
|
5466
|
-
|
|
5225
|
+
if (imageIndex < 0 || imageIndex >= imageCount) {
|
|
5226
|
+
throw new Error(`Captcha image index ${rawIndex} is out of range. count=${imageCount}`);
|
|
5227
|
+
}
|
|
5228
|
+
const sourceImage = sourceImages.nth(imageIndex);
|
|
5467
5229
|
await sourceImage.waitFor({
|
|
5468
5230
|
state: "visible",
|
|
5469
5231
|
timeout: config.sourceImageVisibleTimeoutMs
|
|
5470
5232
|
});
|
|
5471
|
-
|
|
5472
|
-
page,
|
|
5473
|
-
frame,
|
|
5474
|
-
iframeLocator,
|
|
5475
|
-
sourceImage,
|
|
5476
|
-
dropTarget,
|
|
5477
|
-
config,
|
|
5478
|
-
{
|
|
5479
|
-
attempt,
|
|
5480
|
-
visualIndex: imageIndex
|
|
5481
|
-
}
|
|
5482
|
-
);
|
|
5483
|
-
if (!dragResult.accepted) {
|
|
5484
|
-
throw new Error(`Captcha prompt drag was not accepted for visual index ${imageIndex + 1}.`);
|
|
5485
|
-
}
|
|
5486
|
-
if (config.dragBetweenWaitMs > 0) {
|
|
5487
|
-
await page.waitForTimeout(config.dragBetweenWaitMs);
|
|
5488
|
-
}
|
|
5233
|
+
await dragCaptchaAction(page, sourceImage, dropTarget);
|
|
5489
5234
|
}
|
|
5490
|
-
const
|
|
5491
|
-
logger10.info(
|
|
5492
|
-
`\u63D0\u4EA4\u524D\u9A8C\u8BC1\u7801\u72B6\u6001\uFF1Abadge=${beforeSubmitState.badgeCount}, selected=${beforeSubmitState.selectedCount}, submitDisabled=${beforeSubmitState.submitDisabled}`
|
|
5493
|
-
);
|
|
5494
|
-
const submitted = await clickCaptchaAction(frame, config.submitTexts, {
|
|
5495
|
-
...config,
|
|
5496
|
-
page,
|
|
5497
|
-
logger: logger10,
|
|
5498
|
-
forceMouse: true,
|
|
5499
|
-
actionVisibleTimeoutMs: config.submitReadyTimeoutMs
|
|
5500
|
-
}).catch(() => false);
|
|
5235
|
+
const submitted = await clickCaptchaAction(frame, config.submitTexts, { ...config, page }).catch(() => false);
|
|
5501
5236
|
if (!submitted) {
|
|
5502
5237
|
logger10.warn("\u672A\u627E\u5230\u63D0\u4EA4\u6309\u94AE\uFF0C\u53EF\u80FD\u4F1A\u81EA\u52A8\u63D0\u4EA4\u3002");
|
|
5503
5238
|
}
|
|
5504
5239
|
await page.waitForTimeout(config.submitWaitMs);
|
|
5505
|
-
const afterSubmitState = await readPromptCaptchaState(frame, config);
|
|
5506
|
-
logger10.info(
|
|
5507
|
-
`\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801\u72B6\u6001\uFF1Abadge=${afterSubmitState.badgeCount}, selected=${afterSubmitState.selectedCount}, submitDisabled=${afterSubmitState.submitDisabled}`
|
|
5508
|
-
);
|
|
5509
5240
|
const stillVisible = await iframeLocator.isVisible({ timeout: config.containerVisibleTimeoutMs }).catch(() => false);
|
|
5510
5241
|
if (!stillVisible) {
|
|
5511
5242
|
logger10.info("\u9A8C\u8BC1\u7801\u8BC6\u522B\u5E76\u63D0\u4EA4\u6210\u529F\u3002");
|
|
5512
5243
|
return true;
|
|
5513
5244
|
}
|
|
5514
|
-
await maybeCollectCaptchaDebugInfo(page, frame, iframeLocator, attempt, "submit-still-visible", config, {
|
|
5515
|
-
beforeSubmitState,
|
|
5516
|
-
afterSubmitState
|
|
5517
|
-
}).catch((error) => {
|
|
5518
|
-
logger10.warn(`\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5519
|
-
});
|
|
5520
5245
|
logger10.warn("\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801 iframe \u4ECD\u7136\u53EF\u89C1\uFF0C\u51C6\u5907\u5237\u65B0\u540E\u91CD\u8BD5\u3002");
|
|
5521
5246
|
await page.waitForTimeout(2e3);
|
|
5522
5247
|
await refreshCaptcha(page, frame, config);
|
|
@@ -5959,14 +5684,14 @@ var Mutation = {
|
|
|
5959
5684
|
const isFrameElement = tagName === "IFRAME" || tagName === "FRAME";
|
|
5960
5685
|
const nodeName = descriptor?.id || descriptor?.name || "no-id";
|
|
5961
5686
|
let source = "main";
|
|
5962
|
-
let
|
|
5687
|
+
let path2 = `${selector}[${index}]`;
|
|
5963
5688
|
let text = "";
|
|
5964
5689
|
let html = "";
|
|
5965
5690
|
let frameUrl = "";
|
|
5966
5691
|
let readyState = "";
|
|
5967
5692
|
if (isFrameElement) {
|
|
5968
5693
|
source = "iframe";
|
|
5969
|
-
|
|
5694
|
+
path2 = `${selector}[${index}]::iframe(${nodeName})`;
|
|
5970
5695
|
const frame = await handle.contentFrame();
|
|
5971
5696
|
if (frame) {
|
|
5972
5697
|
try {
|
|
@@ -5996,7 +5721,7 @@ var Mutation = {
|
|
|
5996
5721
|
items.push({
|
|
5997
5722
|
selector,
|
|
5998
5723
|
source,
|
|
5999
|
-
path:
|
|
5724
|
+
path: path2,
|
|
6000
5725
|
text,
|
|
6001
5726
|
html,
|
|
6002
5727
|
frameUrl,
|