@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.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: path3 }) => {
|
|
137
137
|
const safeProtocol = String(protocol2).trim();
|
|
138
138
|
const safeDomain = normalizeDomain(domain2);
|
|
139
|
-
const safePath = normalizePath(
|
|
139
|
+
const safePath = normalizePath(path3);
|
|
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 path2 = 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: path2,
|
|
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 path2 = 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: path2,
|
|
1525
1525
|
...domain ? { domain } : {},
|
|
1526
1526
|
...!domain && url ? { url } : {},
|
|
1527
1527
|
...sameSite ? { sameSite } : {},
|
|
@@ -2592,10 +2592,6 @@ 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
|
-
};
|
|
2599
2595
|
var dispatchMouseMove = (page, point, options = {}) => page.mouse.move(point.x, point.y, options);
|
|
2600
2596
|
var dispatchMouseStart = (page, options = {}) => page.mouse.down(options);
|
|
2601
2597
|
var dispatchMouseEnd = (page, options = {}) => page.mouse.up(options);
|
|
@@ -2615,11 +2611,6 @@ var dragWithMouse = async (page, points, options = {}) => {
|
|
|
2615
2611
|
}, { steps: 2 });
|
|
2616
2612
|
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2617
2613
|
}
|
|
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
|
-
}
|
|
2623
2614
|
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2624
2615
|
await dispatchMouseEnd(page);
|
|
2625
2616
|
await waitFor(page, options.afterReleaseDelayMs ?? 100);
|
|
@@ -2629,7 +2620,6 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2629
2620
|
let client = null;
|
|
2630
2621
|
try {
|
|
2631
2622
|
client = await page.context().newCDPSession(page);
|
|
2632
|
-
await waitFor(page, options.initialDelayMs ?? 250);
|
|
2633
2623
|
await client.send("Input.dispatchTouchEvent", {
|
|
2634
2624
|
type: "touchStart",
|
|
2635
2625
|
touchPoints: [{ x: points.start.x, y: points.start.y, id: 1 }]
|
|
@@ -2651,14 +2641,6 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2651
2641
|
});
|
|
2652
2642
|
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2653
2643
|
}
|
|
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
|
-
}
|
|
2662
2644
|
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2663
2645
|
await client.send("Input.dispatchTouchEvent", {
|
|
2664
2646
|
type: "touchEnd",
|
|
@@ -2676,7 +2658,7 @@ var dragWithTouch = async (page, points, options = {}) => {
|
|
|
2676
2658
|
var clickTargetWithDevice = async (page, target, options = {}) => {
|
|
2677
2659
|
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2678
2660
|
const resolvedDevice = resolveDeviceFromPage(page);
|
|
2679
|
-
if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick
|
|
2661
|
+
if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick) {
|
|
2680
2662
|
if (typeof target.tap === "function") {
|
|
2681
2663
|
await target.tap(normalizedOptions.tapOptions);
|
|
2682
2664
|
return true;
|
|
@@ -2876,26 +2858,20 @@ var DeviceInput = {
|
|
|
2876
2858
|
throw new Error("Unable to resolve drag coordinates.");
|
|
2877
2859
|
}
|
|
2878
2860
|
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;
|
|
2885
2861
|
const liftOffsetX = Math.min(18, Math.max(8, sourceBox.width * 0.12));
|
|
2886
2862
|
const liftOffsetY = Math.min(12, Math.max(4, sourceBox.height * 0.08));
|
|
2887
2863
|
const points = {
|
|
2888
2864
|
start: {
|
|
2889
|
-
x:
|
|
2890
|
-
y:
|
|
2865
|
+
x: sourceBox.x + sourceBox.width / 2,
|
|
2866
|
+
y: sourceBox.y + sourceBox.height / 2
|
|
2891
2867
|
},
|
|
2892
2868
|
lift: {
|
|
2893
|
-
x:
|
|
2894
|
-
y:
|
|
2869
|
+
x: sourceBox.x + sourceBox.width / 2 + liftOffsetX,
|
|
2870
|
+
y: sourceBox.y + sourceBox.height / 2 + liftOffsetY
|
|
2895
2871
|
},
|
|
2896
2872
|
end: {
|
|
2897
|
-
x: targetBox.x + targetBox.width / 2
|
|
2898
|
-
y: targetBox.y + targetBox.height / 2
|
|
2873
|
+
x: targetBox.x + targetBox.width / 2,
|
|
2874
|
+
y: targetBox.y + targetBox.height / 2
|
|
2899
2875
|
},
|
|
2900
2876
|
steps
|
|
2901
2877
|
};
|
|
@@ -3460,23 +3436,6 @@ var initializedPages = /* @__PURE__ */ new WeakSet();
|
|
|
3460
3436
|
var DEFAULT_TAP_TIMEOUT_MS = 2500;
|
|
3461
3437
|
var DEFAULT_MOUSE_TAP_FALLBACK_TIMEOUT_MS = 1200;
|
|
3462
3438
|
var DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS = 900;
|
|
3463
|
-
var INTERACTIVE_SELECTOR = [
|
|
3464
|
-
"button",
|
|
3465
|
-
'[role="button"]',
|
|
3466
|
-
"a[href]",
|
|
3467
|
-
"label",
|
|
3468
|
-
"input",
|
|
3469
|
-
"textarea",
|
|
3470
|
-
"select",
|
|
3471
|
-
"summary",
|
|
3472
|
-
'[contenteditable="true"]',
|
|
3473
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
3474
|
-
].join(",");
|
|
3475
|
-
var EDITABLE_SELECTOR = [
|
|
3476
|
-
"input",
|
|
3477
|
-
"textarea",
|
|
3478
|
-
'[contenteditable="true"]'
|
|
3479
|
-
].join(",");
|
|
3480
3439
|
var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
|
|
3481
3440
|
var resolveViewport = (page) => page?.viewportSize?.() || { width: 390, height: 844 };
|
|
3482
3441
|
var describeTarget = (target) => {
|
|
@@ -3516,7 +3475,7 @@ var withTimeout = async (operation, timeoutMs, label) => {
|
|
|
3516
3475
|
}
|
|
3517
3476
|
};
|
|
3518
3477
|
var checkElementVisibility = async (element) => {
|
|
3519
|
-
return element.evaluate((el
|
|
3478
|
+
return element.evaluate((el) => {
|
|
3520
3479
|
const targetStyle = window.getComputedStyle(el);
|
|
3521
3480
|
if (!targetStyle || targetStyle.display === "none" || targetStyle.visibility === "hidden" || targetStyle.visibility === "collapse") {
|
|
3522
3481
|
return { code: "NOT_INTERACTABLE", reason: "\u5143\u7D20\u4E0D\u53EF\u89C1", direction: "down" };
|
|
@@ -3578,16 +3537,30 @@ var checkElementVisibility = async (element) => {
|
|
|
3578
3537
|
positioning
|
|
3579
3538
|
};
|
|
3580
3539
|
}
|
|
3581
|
-
const
|
|
3582
|
-
const
|
|
3540
|
+
const isRootNode = (node) => !node || node === document || node === document.body || node === document.documentElement;
|
|
3541
|
+
const commonAncestor = (a, b) => {
|
|
3542
|
+
for (let current = a; current && !isRootNode(current); current = current.parentElement) {
|
|
3543
|
+
if (current.contains(b)) return current;
|
|
3544
|
+
}
|
|
3545
|
+
return null;
|
|
3546
|
+
};
|
|
3547
|
+
const sameTapTarget = (pointElement) => {
|
|
3583
3548
|
if (!pointElement) return false;
|
|
3584
3549
|
if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
|
|
3585
3550
|
return true;
|
|
3586
3551
|
}
|
|
3587
|
-
|
|
3552
|
+
const common = commonAncestor(el, pointElement);
|
|
3553
|
+
if (!common) return false;
|
|
3554
|
+
const commonRect = common.getBoundingClientRect?.();
|
|
3555
|
+
if (!commonRect || commonRect.width <= 0 || commonRect.height <= 0) return false;
|
|
3556
|
+
const commonArea = commonRect.width * commonRect.height;
|
|
3557
|
+
const targetArea = Math.max(1, rect.width * rect.height);
|
|
3558
|
+
const maxSharedRegionArea = Math.max(targetArea * 12, 4096);
|
|
3559
|
+
if (commonArea > maxSharedRegionArea) return false;
|
|
3560
|
+
if (commonRect.width > Math.max(rect.width * 8, 120) || commonRect.height > Math.max(rect.height * 8, 120)) {
|
|
3588
3561
|
return false;
|
|
3589
3562
|
}
|
|
3590
|
-
return
|
|
3563
|
+
return common.contains(el) && common.contains(pointElement);
|
|
3591
3564
|
};
|
|
3592
3565
|
const describeElement = (node) => {
|
|
3593
3566
|
if (!node) return null;
|
|
@@ -3616,7 +3589,7 @@ var checkElementVisibility = async (element) => {
|
|
|
3616
3589
|
let obstruction = null;
|
|
3617
3590
|
for (const point of samplePoints) {
|
|
3618
3591
|
const pointElement = document.elementFromPoint(point.x, point.y);
|
|
3619
|
-
if (
|
|
3592
|
+
if (sameTapTarget(pointElement)) {
|
|
3620
3593
|
return { code: "VISIBLE", isFixed, positioning };
|
|
3621
3594
|
}
|
|
3622
3595
|
obstruction = obstruction || describeElement(pointElement);
|
|
@@ -3634,10 +3607,10 @@ var checkElementVisibility = async (element) => {
|
|
|
3634
3607
|
};
|
|
3635
3608
|
}
|
|
3636
3609
|
return { code: "VISIBLE", isFixed, positioning };
|
|
3637
|
-
}
|
|
3610
|
+
});
|
|
3638
3611
|
};
|
|
3639
3612
|
var resolveSafeTapPoint = async (element) => {
|
|
3640
|
-
return element.evaluate((el
|
|
3613
|
+
return element.evaluate((el) => {
|
|
3641
3614
|
const rect = el.getBoundingClientRect();
|
|
3642
3615
|
if (!rect || rect.width <= 0 || rect.height <= 0) {
|
|
3643
3616
|
return null;
|
|
@@ -3674,16 +3647,30 @@ var resolveSafeTapPoint = async (element) => {
|
|
|
3674
3647
|
if (visibleWidth <= 1 || visibleHeight <= 1) {
|
|
3675
3648
|
return null;
|
|
3676
3649
|
}
|
|
3677
|
-
const
|
|
3678
|
-
const
|
|
3650
|
+
const isRootNode = (node) => !node || node === document || node === document.body || node === document.documentElement;
|
|
3651
|
+
const commonAncestor = (a, b) => {
|
|
3652
|
+
for (let current = a; current && !isRootNode(current); current = current.parentElement) {
|
|
3653
|
+
if (current.contains(b)) return current;
|
|
3654
|
+
}
|
|
3655
|
+
return null;
|
|
3656
|
+
};
|
|
3657
|
+
const sameTapTarget = (pointElement) => {
|
|
3679
3658
|
if (!pointElement) return false;
|
|
3680
3659
|
if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
|
|
3681
3660
|
return true;
|
|
3682
3661
|
}
|
|
3683
|
-
|
|
3662
|
+
const common = commonAncestor(el, pointElement);
|
|
3663
|
+
if (!common) return false;
|
|
3664
|
+
const commonRect = common.getBoundingClientRect?.();
|
|
3665
|
+
if (!commonRect || commonRect.width <= 0 || commonRect.height <= 0) return false;
|
|
3666
|
+
const commonArea = commonRect.width * commonRect.height;
|
|
3667
|
+
const targetArea = Math.max(1, rect.width * rect.height);
|
|
3668
|
+
const maxSharedRegionArea = Math.max(targetArea * 12, 4096);
|
|
3669
|
+
if (commonArea > maxSharedRegionArea) return false;
|
|
3670
|
+
if (commonRect.width > Math.max(rect.width * 8, 120) || commonRect.height > Math.max(rect.height * 8, 120)) {
|
|
3684
3671
|
return false;
|
|
3685
3672
|
}
|
|
3686
|
-
return
|
|
3673
|
+
return common.contains(el) && common.contains(pointElement);
|
|
3687
3674
|
};
|
|
3688
3675
|
const cx = visibleLeft + visibleWidth / 2;
|
|
3689
3676
|
const cy = visibleTop + visibleHeight / 2;
|
|
@@ -3702,7 +3689,7 @@ var resolveSafeTapPoint = async (element) => {
|
|
|
3702
3689
|
];
|
|
3703
3690
|
const safePoints = points.filter((point) => {
|
|
3704
3691
|
const pointElement = document.elementFromPoint(point.x, point.y);
|
|
3705
|
-
return
|
|
3692
|
+
return sameTapTarget(pointElement);
|
|
3706
3693
|
});
|
|
3707
3694
|
const candidates = safePoints.length ? safePoints : points;
|
|
3708
3695
|
const chosen = candidates[Math.floor(Math.random() * candidates.length)];
|
|
@@ -3711,46 +3698,57 @@ var resolveSafeTapPoint = async (element) => {
|
|
|
3711
3698
|
x: chosen.x,
|
|
3712
3699
|
y: chosen.y
|
|
3713
3700
|
};
|
|
3714
|
-
}
|
|
3701
|
+
});
|
|
3715
3702
|
};
|
|
3716
3703
|
var activateElementFallback = async (element, point = null, options = {}) => {
|
|
3717
|
-
return element.evaluate((el, {
|
|
3718
|
-
const
|
|
3719
|
-
|
|
3720
|
-
if (
|
|
3721
|
-
return node.
|
|
3704
|
+
return element.evaluate((el, { innerOptions }) => {
|
|
3705
|
+
const isEditable = (node) => {
|
|
3706
|
+
if (!node || node.nodeType !== Node.ELEMENT_NODE) return false;
|
|
3707
|
+
if (node.isContentEditable) return true;
|
|
3708
|
+
if (node instanceof HTMLTextAreaElement) return !node.disabled && !node.readOnly;
|
|
3709
|
+
if (node instanceof HTMLInputElement) {
|
|
3710
|
+
return !node.disabled && !node.readOnly && typeof node.select === "function";
|
|
3711
|
+
}
|
|
3712
|
+
return false;
|
|
3722
3713
|
};
|
|
3723
|
-
const
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
}
|
|
3729
|
-
|
|
3730
|
-
const editable = typeof target.closest === "function" ? target.closest(editableSelector) : null;
|
|
3714
|
+
const findEditable = (node) => {
|
|
3715
|
+
for (let current = node; current && current !== document.body; current = current.parentElement) {
|
|
3716
|
+
if (isEditable(current)) return current;
|
|
3717
|
+
}
|
|
3718
|
+
return null;
|
|
3719
|
+
};
|
|
3720
|
+
const editable = findEditable(el);
|
|
3731
3721
|
if (editable && typeof editable.focus === "function") {
|
|
3732
3722
|
editable.focus({ preventScroll: true });
|
|
3733
3723
|
if (innerOptions.editableOnly) {
|
|
3734
3724
|
return { activated: true, method: "focus", tag: editable.tagName || "" };
|
|
3735
3725
|
}
|
|
3736
3726
|
}
|
|
3737
|
-
if (
|
|
3738
|
-
|
|
3727
|
+
if (innerOptions.editableOnly) {
|
|
3728
|
+
return { activated: false, method: "none", tag: el?.tagName || "" };
|
|
3739
3729
|
}
|
|
3740
|
-
if (
|
|
3741
|
-
|
|
3742
|
-
|
|
3730
|
+
if (typeof el.focus === "function") {
|
|
3731
|
+
el.focus({ preventScroll: true });
|
|
3732
|
+
}
|
|
3733
|
+
if (typeof el.click === "function") {
|
|
3734
|
+
el.click();
|
|
3735
|
+
return { activated: true, method: "dom-click", tag: el.tagName || "" };
|
|
3736
|
+
}
|
|
3737
|
+
if (typeof el.dispatchEvent === "function") {
|
|
3738
|
+
el.dispatchEvent(new MouseEvent("click", {
|
|
3739
|
+
bubbles: true,
|
|
3740
|
+
cancelable: true,
|
|
3741
|
+
view: window
|
|
3742
|
+
}));
|
|
3743
|
+
return { activated: true, method: "dispatch-click", tag: el.tagName || "" };
|
|
3743
3744
|
}
|
|
3744
3745
|
return {
|
|
3745
3746
|
activated: Boolean(editable),
|
|
3746
3747
|
method: editable ? "focus" : "none",
|
|
3747
|
-
tag:
|
|
3748
|
+
tag: el?.tagName || ""
|
|
3748
3749
|
};
|
|
3749
3750
|
}, {
|
|
3750
|
-
|
|
3751
|
-
innerOptions: options || {},
|
|
3752
|
-
interactiveSelector: INTERACTIVE_SELECTOR,
|
|
3753
|
-
editableSelector: EDITABLE_SELECTOR
|
|
3751
|
+
innerOptions: options || {}
|
|
3754
3752
|
});
|
|
3755
3753
|
};
|
|
3756
3754
|
var getScrollableRect = async (element) => {
|
|
@@ -3854,6 +3852,47 @@ var scrollAwayFromObstruction = async (element, status) => {
|
|
|
3854
3852
|
};
|
|
3855
3853
|
}, status);
|
|
3856
3854
|
};
|
|
3855
|
+
var getElementViewportSnapshot = async (element) => {
|
|
3856
|
+
return element.evaluate((el) => {
|
|
3857
|
+
const rect = el.getBoundingClientRect();
|
|
3858
|
+
return {
|
|
3859
|
+
top: rect.top,
|
|
3860
|
+
bottom: rect.bottom,
|
|
3861
|
+
left: rect.left,
|
|
3862
|
+
right: rect.right,
|
|
3863
|
+
width: rect.width,
|
|
3864
|
+
height: rect.height,
|
|
3865
|
+
scrollX: window.scrollX,
|
|
3866
|
+
scrollY: window.scrollY
|
|
3867
|
+
};
|
|
3868
|
+
});
|
|
3869
|
+
};
|
|
3870
|
+
var isTargetImmobileAfterScroll = (before, after) => {
|
|
3871
|
+
if (!before || !after) return false;
|
|
3872
|
+
const rectDeltaY = Number(after.top || 0) - Number(before.top || 0);
|
|
3873
|
+
const rectDeltaX = Number(after.left || 0) - Number(before.left || 0);
|
|
3874
|
+
const scrollDeltaY = Number(after.scrollY || 0) - Number(before.scrollY || 0);
|
|
3875
|
+
const scrollDeltaX = Number(after.scrollX || 0) - Number(before.scrollX || 0);
|
|
3876
|
+
const rectMoved = Math.abs(rectDeltaY) > 3 || Math.abs(rectDeltaX) > 3;
|
|
3877
|
+
const pageMoved = Math.abs(scrollDeltaY) > 3 || Math.abs(scrollDeltaX) > 3;
|
|
3878
|
+
if (!rectMoved && !pageMoved) return true;
|
|
3879
|
+
if (pageMoved && !rectMoved) return true;
|
|
3880
|
+
if (Math.abs(scrollDeltaY) > 12 && Math.abs(rectDeltaY) < Math.min(12, Math.abs(scrollDeltaY) * 0.2)) {
|
|
3881
|
+
return true;
|
|
3882
|
+
}
|
|
3883
|
+
return false;
|
|
3884
|
+
};
|
|
3885
|
+
var restoreWindowFromSnapshot = async (page, before, after) => {
|
|
3886
|
+
if (!before || !after) return;
|
|
3887
|
+
if (Math.abs(Number(after.scrollX || 0) - Number(before.scrollX || 0)) <= 2 && Math.abs(Number(after.scrollY || 0) - Number(before.scrollY || 0)) <= 2) {
|
|
3888
|
+
return;
|
|
3889
|
+
}
|
|
3890
|
+
await page.evaluate(
|
|
3891
|
+
(state) => window.scrollTo(state.x, state.y),
|
|
3892
|
+
{ x: Number(before.scrollX || 0), y: Number(before.scrollY || 0) }
|
|
3893
|
+
).catch(() => {
|
|
3894
|
+
});
|
|
3895
|
+
};
|
|
3857
3896
|
var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
|
|
3858
3897
|
const viewport = resolveViewport(page);
|
|
3859
3898
|
const rawRect = options.rect || null;
|
|
@@ -4034,11 +4073,11 @@ var MobileHumanize = {
|
|
|
4034
4073
|
const scrollRect = await getScrollableRect(element);
|
|
4035
4074
|
if (!scrollRect && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
|
|
4036
4075
|
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"})`);
|
|
4037
|
-
return { element, didScroll, restore: null };
|
|
4076
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4038
4077
|
}
|
|
4039
4078
|
if (!scrollRect && status.isFixed && status.code === "OBSTRUCTED") {
|
|
4040
4079
|
logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
|
|
4041
|
-
return { element, didScroll, restore: null };
|
|
4080
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4042
4081
|
}
|
|
4043
4082
|
if (scrollRect && status.code === "OBSTRUCTED" && status.obstruction?.isFixed) {
|
|
4044
4083
|
const moved = await scrollAwayFromObstruction(element, status);
|
|
@@ -4069,6 +4108,7 @@ var MobileHumanize = {
|
|
|
4069
4108
|
}
|
|
4070
4109
|
}
|
|
4071
4110
|
const beforeWindowState = scrollRect ? await page.evaluate(() => ({ x: window.scrollX, y: window.scrollY })) : null;
|
|
4111
|
+
const beforeElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
|
|
4072
4112
|
const beforeState = scrollRect ? await element.evaluate((el) => {
|
|
4073
4113
|
const isScrollable = (node) => {
|
|
4074
4114
|
const style = window.getComputedStyle(node);
|
|
@@ -4098,6 +4138,21 @@ var MobileHumanize = {
|
|
|
4098
4138
|
logger7.debug(`humanScroll | \u7A97\u53E3\u6EDA\u52A8\u56DE\u6536 from=${Math.round(afterWindowState.y)} to=${Math.round(beforeWindowState.y)}`);
|
|
4099
4139
|
}
|
|
4100
4140
|
}
|
|
4141
|
+
let afterElementSnapshot = null;
|
|
4142
|
+
const readAfterElementSnapshot = async () => {
|
|
4143
|
+
if (!afterElementSnapshot) {
|
|
4144
|
+
afterElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
|
|
4145
|
+
}
|
|
4146
|
+
return afterElementSnapshot;
|
|
4147
|
+
};
|
|
4148
|
+
if (!scrollRect && beforeElementSnapshot) {
|
|
4149
|
+
const afterSnapshot = await readAfterElementSnapshot();
|
|
4150
|
+
if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
|
|
4151
|
+
await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
|
|
4152
|
+
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"})`);
|
|
4153
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4101
4156
|
if (scrollRect && beforeState) {
|
|
4102
4157
|
const afterState = await element.evaluate((el) => {
|
|
4103
4158
|
const isScrollable = (node) => {
|
|
@@ -4135,6 +4190,14 @@ var MobileHumanize = {
|
|
|
4135
4190
|
}
|
|
4136
4191
|
}
|
|
4137
4192
|
}
|
|
4193
|
+
if (scrollRect && beforeElementSnapshot) {
|
|
4194
|
+
const afterSnapshot = await getElementViewportSnapshot(element).catch(() => null);
|
|
4195
|
+
if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
|
|
4196
|
+
await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
|
|
4197
|
+
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"})`);
|
|
4198
|
+
return { element, didScroll, restore: null, unscrollable: true };
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4138
4201
|
didScroll = true;
|
|
4139
4202
|
}
|
|
4140
4203
|
try {
|
|
@@ -4184,21 +4247,28 @@ var MobileHumanize = {
|
|
|
4184
4247
|
logger7.warn(`humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${targetDesc}`);
|
|
4185
4248
|
return false;
|
|
4186
4249
|
}
|
|
4187
|
-
|
|
4188
|
-
await MobileHumanize.humanScroll(page, element, { throwOnMissing });
|
|
4189
|
-
}
|
|
4250
|
+
const scrollResult = scrollIfNeeded ? await MobileHumanize.humanScroll(page, element, { throwOnMissing }) : null;
|
|
4190
4251
|
const status = await checkElementVisibility(element).catch(() => null);
|
|
4191
4252
|
if (status && status.code !== "VISIBLE") {
|
|
4192
|
-
if (fallbackDomClick && status.
|
|
4193
|
-
|
|
4253
|
+
if (fallbackDomClick && (status.code === "OUT_OF_VIEWPORT" || status.code === "OBSTRUCTED") && (status.isFixed || scrollResult?.unscrollable)) {
|
|
4254
|
+
let fallback = await withTimeout(
|
|
4194
4255
|
() => activateElementFallback(element, null, {
|
|
4195
4256
|
editableOnly: true
|
|
4196
4257
|
}),
|
|
4197
4258
|
activateFallbackTimeoutMs,
|
|
4198
4259
|
"focus fallback"
|
|
4199
4260
|
).catch(() => null);
|
|
4261
|
+
if (!fallback?.activated) {
|
|
4262
|
+
fallback = await withTimeout(
|
|
4263
|
+
() => activateElementFallback(element, null, {
|
|
4264
|
+
editableOnly: false
|
|
4265
|
+
}),
|
|
4266
|
+
activateFallbackTimeoutMs,
|
|
4267
|
+
"activation fallback"
|
|
4268
|
+
).catch(() => null);
|
|
4269
|
+
}
|
|
4200
4270
|
if (fallback?.activated) {
|
|
4201
|
-
logger7.warn(`humanClick:
|
|
4271
|
+
logger7.warn(`humanClick: \u4E0D\u53EF\u6EDA\u52A8\u76EE\u6807\u4E0D\u53EF\u7269\u7406\u70B9\u51FB\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
|
|
4202
4272
|
return true;
|
|
4203
4273
|
}
|
|
4204
4274
|
}
|
|
@@ -4315,6 +4385,20 @@ var MobileHumanize = {
|
|
|
4315
4385
|
const locator = page.locator(selector);
|
|
4316
4386
|
await MobileHumanize.humanClick(page, locator, { scrollIfNeeded: true });
|
|
4317
4387
|
await waitJitter(160, 0.4);
|
|
4388
|
+
const readValue = async () => {
|
|
4389
|
+
try {
|
|
4390
|
+
return await locator.inputValue({ timeout: 600 });
|
|
4391
|
+
} catch {
|
|
4392
|
+
return await locator.evaluate((el) => "value" in el ? String(el.value || "") : String(el.textContent || "")).catch(() => "");
|
|
4393
|
+
}
|
|
4394
|
+
};
|
|
4395
|
+
const currentValue = await readValue();
|
|
4396
|
+
if (!currentValue) return;
|
|
4397
|
+
await page.keyboard.press("ControlOrMeta+A");
|
|
4398
|
+
await waitJitter(90, 0.35);
|
|
4399
|
+
await page.keyboard.press("Backspace");
|
|
4400
|
+
await waitJitter(120, 0.35);
|
|
4401
|
+
if (!await readValue()) return;
|
|
4318
4402
|
await locator.evaluate((el) => {
|
|
4319
4403
|
if ("value" in el) {
|
|
4320
4404
|
el.value = "";
|
|
@@ -4904,10 +4988,6 @@ var LiveView = {
|
|
|
4904
4988
|
// src/chaptcha.js
|
|
4905
4989
|
var import_uuid = require("uuid");
|
|
4906
4990
|
|
|
4907
|
-
// src/internals/captcha/bytedance.js
|
|
4908
|
-
var import_promises = require("fs/promises");
|
|
4909
|
-
var import_path2 = __toESM(require("path"), 1);
|
|
4910
|
-
|
|
4911
4991
|
// src/internals/captcha/shared.js
|
|
4912
4992
|
var waitForVisible = async (locator, timeout) => {
|
|
4913
4993
|
try {
|
|
@@ -4925,71 +5005,38 @@ var isAnyCaptchaTextVisible = async (frame, texts, timeout) => {
|
|
|
4925
5005
|
if (!text) {
|
|
4926
5006
|
continue;
|
|
4927
5007
|
}
|
|
4928
|
-
const
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
if (isVisible) {
|
|
4937
|
-
return true;
|
|
4938
|
-
}
|
|
5008
|
+
const candidates = [
|
|
5009
|
+
frame.getByText(text, { exact: false }).first(),
|
|
5010
|
+
frame.locator(`text=${text}`).first()
|
|
5011
|
+
];
|
|
5012
|
+
for (const candidate of candidates) {
|
|
5013
|
+
const isVisible = await candidate.isVisible({ timeout }).catch(() => false);
|
|
5014
|
+
if (isVisible) {
|
|
5015
|
+
return true;
|
|
4939
5016
|
}
|
|
4940
5017
|
}
|
|
4941
5018
|
}
|
|
4942
5019
|
return false;
|
|
4943
5020
|
};
|
|
4944
|
-
var collectVisibleCandidateIndexes = async (candidateGroup, count, timeout) => {
|
|
4945
|
-
const visibleIndexes = [];
|
|
4946
|
-
for (let index = 0; index < count; index += 1) {
|
|
4947
|
-
const candidate = candidateGroup.nth(index);
|
|
4948
|
-
const isVisible = await candidate.isVisible({ timeout }).catch(() => false);
|
|
4949
|
-
if (isVisible) {
|
|
4950
|
-
visibleIndexes.push(index);
|
|
4951
|
-
}
|
|
4952
|
-
}
|
|
4953
|
-
return visibleIndexes;
|
|
4954
|
-
};
|
|
4955
5021
|
var clickCaptchaAction = async (frame, texts, options) => {
|
|
4956
5022
|
for (const text of texts || []) {
|
|
4957
|
-
const
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
textLocator.count().catch(() => 0),
|
|
4961
|
-
locatorText.count().catch(() => 0)
|
|
4962
|
-
]);
|
|
4963
|
-
const [getByTextVisibleIndexes, locatorTextVisibleIndexes] = await Promise.all([
|
|
4964
|
-
collectVisibleCandidateIndexes(textLocator, getByTextCount, options.actionVisibleTimeoutMs),
|
|
4965
|
-
collectVisibleCandidateIndexes(locatorText, locatorTextCount, options.actionVisibleTimeoutMs)
|
|
4966
|
-
]);
|
|
4967
|
-
options.logger?.info(
|
|
4968
|
-
`[CaptchaAction] \u6587\u672C "${text}" \u547D\u4E2D\u6570\u91CF\uFF1AgetByText=${getByTextCount} (visible=${getByTextVisibleIndexes.length}), locator=${locatorTextCount} (visible=${locatorTextVisibleIndexes.length})`
|
|
4969
|
-
);
|
|
4970
|
-
const candidateGroups = [
|
|
4971
|
-
{ label: "getByText", locator: textLocator, count: getByTextCount },
|
|
4972
|
-
{ label: "locator", locator: locatorText, count: locatorTextCount }
|
|
5023
|
+
const candidates = [
|
|
5024
|
+
frame.getByText(text, { exact: false }).first(),
|
|
5025
|
+
frame.locator(`text=${text}`).first()
|
|
4973
5026
|
];
|
|
4974
|
-
for (const
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
if (!isVisible) {
|
|
4979
|
-
continue;
|
|
4980
|
-
}
|
|
4981
|
-
options.logger?.info(
|
|
4982
|
-
`[CaptchaAction] \u6587\u672C "${text}" \u9009\u62E9 ${candidateGroup.label}[${index}] \u4F5C\u4E3A\u7B2C\u4E00\u4E2A\u53EF\u89C1\u8282\u70B9\u6267\u884C\u70B9\u51FB\u3002`
|
|
4983
|
-
);
|
|
4984
|
-
await DeviceInput.click(options.page, candidate, options);
|
|
4985
|
-
return true;
|
|
5027
|
+
for (const candidate of candidates) {
|
|
5028
|
+
const isVisible = await waitForVisible(candidate, options.actionVisibleTimeoutMs);
|
|
5029
|
+
if (!isVisible) {
|
|
5030
|
+
continue;
|
|
4986
5031
|
}
|
|
5032
|
+
await DeviceInput.click(options.page, candidate);
|
|
5033
|
+
return true;
|
|
4987
5034
|
}
|
|
4988
5035
|
}
|
|
4989
5036
|
return false;
|
|
4990
5037
|
};
|
|
4991
|
-
var dragCaptchaAction = async (page, sourceLocator, targetLocator
|
|
4992
|
-
await DeviceInput.drag(page, sourceLocator, targetLocator
|
|
5038
|
+
var dragCaptchaAction = async (page, sourceLocator, targetLocator) => {
|
|
5039
|
+
await DeviceInput.drag(page, sourceLocator, targetLocator);
|
|
4993
5040
|
};
|
|
4994
5041
|
|
|
4995
5042
|
// src/internals/captcha/bytedance.js
|
|
@@ -5000,12 +5047,11 @@ var DEFAULT_BYTEDANCE_CAPTCHA_OPTIONS = Object.freeze({
|
|
|
5000
5047
|
containerSelector: "#captcha_container",
|
|
5001
5048
|
iframeSelector: 'iframe[src*="verifycenter"]',
|
|
5002
5049
|
iframeFallbackSelector: "iframe",
|
|
5003
|
-
sourceImageSelector: ".
|
|
5004
|
-
dropTargetContainerSelector: "
|
|
5050
|
+
sourceImageSelector: "div.canvas-container",
|
|
5051
|
+
dropTargetContainerSelector: "#captcha_verify_image div",
|
|
5005
5052
|
dropTargetTexts: ["\u62D6\u62FD\u5230\u8FD9\u91CC"],
|
|
5006
5053
|
refreshTexts: ["\u5237\u65B0"],
|
|
5007
5054
|
submitTexts: ["\u63D0\u4EA4"],
|
|
5008
|
-
guideMaskSelector: ".play-guide-mask",
|
|
5009
5055
|
recognitionSuccessCode: 1e4,
|
|
5010
5056
|
containerVisibleTimeoutMs: 2e3,
|
|
5011
5057
|
iframeVisibleTimeoutMs: 12e3,
|
|
@@ -5028,111 +5074,10 @@ var DEFAULT_BYTEDANCE_CAPTCHA_OPTIONS = Object.freeze({
|
|
|
5028
5074
|
],
|
|
5029
5075
|
recognitionDelayMs: 2e3,
|
|
5030
5076
|
refreshWaitMs: 3e3,
|
|
5031
|
-
submitWaitMs:
|
|
5032
|
-
submitReadyTimeoutMs: 2500,
|
|
5077
|
+
submitWaitMs: 3e3,
|
|
5033
5078
|
retryDelayBaseMs: 2e3,
|
|
5034
|
-
retryDelayStepMs: 1e3
|
|
5035
|
-
sourceImageRowTolerancePx: 24,
|
|
5036
|
-
dragBetweenWaitMs: 250,
|
|
5037
|
-
promptBadgeCountSelector: ".drag-area .photo-badge .badge span",
|
|
5038
|
-
promptSubmitButtonSelector: ".vc-captcha-verify-mobile-button",
|
|
5039
|
-
promptSelectedSourceSelector: ".img-container .canvas-container.selected",
|
|
5040
|
-
promptActiveSourceSelector: ".img-container .canvas-container.active",
|
|
5041
|
-
promptDragMoveSteps: 16,
|
|
5042
|
-
promptDragStepDelayMs: 55,
|
|
5043
|
-
promptDragHoldDelayMs: 240,
|
|
5044
|
-
promptDragBeforeReleaseDelayMs: 180,
|
|
5045
|
-
promptDragAfterReleaseDelayMs: 240,
|
|
5046
|
-
promptDragFinalMoveRepeats: 3,
|
|
5047
|
-
promptDragRetryDelayMs: 250,
|
|
5048
|
-
debugArtifacts: false
|
|
5079
|
+
retryDelayStepMs: 1e3
|
|
5049
5080
|
});
|
|
5050
|
-
var PROMPT_CAPTCHA_DRAG_PLANS = Object.freeze([
|
|
5051
|
-
{ name: "lower-middle", endXRatio: 0.5, endYRatio: 0.72 },
|
|
5052
|
-
{ name: "center-middle", endXRatio: 0.5, endYRatio: 0.56 },
|
|
5053
|
-
{ name: "upper-middle", endXRatio: 0.5, endYRatio: 0.4 }
|
|
5054
|
-
]);
|
|
5055
|
-
var resolveCaptchaDebugDir = () => import_path2.default.resolve(process.cwd(), "storage", "captcha-debug");
|
|
5056
|
-
var rectOf = (rect) => {
|
|
5057
|
-
if (!rect) {
|
|
5058
|
-
return null;
|
|
5059
|
-
}
|
|
5060
|
-
return {
|
|
5061
|
-
x: Number(rect.x.toFixed(2)),
|
|
5062
|
-
y: Number(rect.y.toFixed(2)),
|
|
5063
|
-
width: Number(rect.width.toFixed(2)),
|
|
5064
|
-
height: Number(rect.height.toFixed(2))
|
|
5065
|
-
};
|
|
5066
|
-
};
|
|
5067
|
-
var collectCaptchaDebugInfo = async (page, frame, iframeLocator, attempt, phase, extra = null) => {
|
|
5068
|
-
const timestamp = Date.now();
|
|
5069
|
-
const debugDir = resolveCaptchaDebugDir();
|
|
5070
|
-
await (0, import_promises.mkdir)(debugDir, { recursive: true });
|
|
5071
|
-
const baseName = `bytedance-${timestamp}-attempt${attempt}-${phase}`;
|
|
5072
|
-
const iframeScreenshotPath = import_path2.default.join(debugDir, `${baseName}-iframe.png`);
|
|
5073
|
-
const pageScreenshotPath = import_path2.default.join(debugDir, `${baseName}-page.png`);
|
|
5074
|
-
const htmlPath = import_path2.default.join(debugDir, `${baseName}-iframe.html`);
|
|
5075
|
-
const infoPath = import_path2.default.join(debugDir, `${baseName}-info.json`);
|
|
5076
|
-
await iframeLocator.screenshot({ path: iframeScreenshotPath }).catch(() => {
|
|
5077
|
-
});
|
|
5078
|
-
await page.screenshot({ path: pageScreenshotPath, fullPage: true }).catch(() => {
|
|
5079
|
-
});
|
|
5080
|
-
const html = await frame.evaluate(() => document.documentElement.outerHTML).catch(() => "");
|
|
5081
|
-
if (html) {
|
|
5082
|
-
await (0, import_promises.writeFile)(htmlPath, html, "utf8");
|
|
5083
|
-
}
|
|
5084
|
-
const info = await frame.evaluate(() => {
|
|
5085
|
-
const toRect = (element) => {
|
|
5086
|
-
const rect = element.getBoundingClientRect();
|
|
5087
|
-
return {
|
|
5088
|
-
x: Number(rect.x.toFixed(2)),
|
|
5089
|
-
y: Number(rect.y.toFixed(2)),
|
|
5090
|
-
width: Number(rect.width.toFixed(2)),
|
|
5091
|
-
height: Number(rect.height.toFixed(2))
|
|
5092
|
-
};
|
|
5093
|
-
};
|
|
5094
|
-
const toItem = (element, index) => ({
|
|
5095
|
-
index,
|
|
5096
|
-
tag: element.tagName,
|
|
5097
|
-
id: element.id || "",
|
|
5098
|
-
className: typeof element.className === "string" ? element.className : "",
|
|
5099
|
-
text: String(element.textContent || "").trim(),
|
|
5100
|
-
rect: toRect(element)
|
|
5101
|
-
});
|
|
5102
|
-
const visibleNodes = Array.from(document.querySelectorAll("body *")).map(toItem).filter((item) => item.rect.width > 0 && item.rect.height > 0);
|
|
5103
|
-
return {
|
|
5104
|
-
title: document.title,
|
|
5105
|
-
bodyText: String(document.body?.innerText || "").trim(),
|
|
5106
|
-
canvasContainers: visibleNodes.filter((item) => item.className.includes("canvas-container")),
|
|
5107
|
-
canvasNodes: visibleNodes.filter((item) => item.tag === "CANVAS"),
|
|
5108
|
-
captchaNodes: visibleNodes.filter((item) => item.id.startsWith("captcha_") || item.className.includes("captcha") || item.className.includes("verify") || /拖拽到这里|刷新|提交/.test(item.text)),
|
|
5109
|
-
visibleTextNodes: visibleNodes.filter((item) => item.text).slice(0, 300)
|
|
5110
|
-
};
|
|
5111
|
-
}).catch(() => null);
|
|
5112
|
-
if (info) {
|
|
5113
|
-
const payload = {
|
|
5114
|
-
capturedAt: new Date(timestamp).toISOString(),
|
|
5115
|
-
pageUrl: page.url(),
|
|
5116
|
-
attempt,
|
|
5117
|
-
phase,
|
|
5118
|
-
iframeScreenshotPath,
|
|
5119
|
-
pageScreenshotPath,
|
|
5120
|
-
htmlPath,
|
|
5121
|
-
info
|
|
5122
|
-
};
|
|
5123
|
-
if (extra != null) {
|
|
5124
|
-
payload.extra = extra;
|
|
5125
|
-
}
|
|
5126
|
-
await (0, import_promises.writeFile)(infoPath, JSON.stringify(payload, null, 2), "utf8");
|
|
5127
|
-
}
|
|
5128
|
-
logger10.info(`\u5DF2\u5199\u51FA\u9A8C\u8BC1\u7801\u8C03\u8BD5\u4EA7\u7269\uFF1A${debugDir}`);
|
|
5129
|
-
};
|
|
5130
|
-
var maybeCollectCaptchaDebugInfo = async (page, frame, iframeLocator, attempt, phase, options, extra = null) => {
|
|
5131
|
-
if (!options.debugArtifacts) {
|
|
5132
|
-
return;
|
|
5133
|
-
}
|
|
5134
|
-
await collectCaptchaDebugInfo(page, frame, iframeLocator, attempt, phase, extra);
|
|
5135
|
-
};
|
|
5136
5081
|
var extractCaptchaSerialNumbers = (apiResponse) => {
|
|
5137
5082
|
const serialNumbers = apiResponse?.data?.data?.serial_number;
|
|
5138
5083
|
if (!Array.isArray(serialNumbers)) {
|
|
@@ -5141,7 +5086,7 @@ var extractCaptchaSerialNumbers = (apiResponse) => {
|
|
|
5141
5086
|
return serialNumbers.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value >= 0);
|
|
5142
5087
|
};
|
|
5143
5088
|
var resolveContentFrame = async (page, iframeLocator, options) => {
|
|
5144
|
-
for (let attempt = 1; attempt <= options.contentFrameResolveRetries; attempt
|
|
5089
|
+
for (let attempt = 1; attempt <= options.contentFrameResolveRetries; attempt++) {
|
|
5145
5090
|
const iframeHandle = await iframeLocator.elementHandle();
|
|
5146
5091
|
const frame = await iframeHandle?.contentFrame();
|
|
5147
5092
|
if (frame) {
|
|
@@ -5186,15 +5131,20 @@ var getVerifycenterCaptchaContext = async (page, options) => {
|
|
|
5186
5131
|
}
|
|
5187
5132
|
return { iframeLocator, frame };
|
|
5188
5133
|
};
|
|
5189
|
-
var
|
|
5190
|
-
const
|
|
5191
|
-
if (
|
|
5192
|
-
|
|
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;
|
|
5193
5139
|
}
|
|
5140
|
+
await page.waitForTimeout(options.refreshWaitMs);
|
|
5141
|
+
return true;
|
|
5142
|
+
};
|
|
5143
|
+
var findCaptchaDropTarget = async (frame, options) => {
|
|
5194
5144
|
for (const text of options.dropTargetTexts) {
|
|
5195
5145
|
const candidates = [
|
|
5196
|
-
frame.
|
|
5197
|
-
frame.
|
|
5146
|
+
frame.locator(options.dropTargetContainerSelector).filter({ hasText: text }).first(),
|
|
5147
|
+
frame.getByText(text, { exact: false }).first()
|
|
5198
5148
|
];
|
|
5199
5149
|
for (const candidate of candidates) {
|
|
5200
5150
|
const isVisible = await waitForVisible(candidate, options.actionVisibleTimeoutMs);
|
|
@@ -5205,112 +5155,10 @@ var findCaptchaDropTarget = async (frame, options) => {
|
|
|
5205
5155
|
}
|
|
5206
5156
|
return null;
|
|
5207
5157
|
};
|
|
5208
|
-
var readPromptCaptchaState = async (frame, options) => frame.evaluate((selectors) => {
|
|
5209
|
-
const toRect = (element) => {
|
|
5210
|
-
if (!element) {
|
|
5211
|
-
return null;
|
|
5212
|
-
}
|
|
5213
|
-
const rect = element.getBoundingClientRect();
|
|
5214
|
-
return {
|
|
5215
|
-
x: Number(rect.x.toFixed(2)),
|
|
5216
|
-
y: Number(rect.y.toFixed(2)),
|
|
5217
|
-
width: Number(rect.width.toFixed(2)),
|
|
5218
|
-
height: Number(rect.height.toFixed(2))
|
|
5219
|
-
};
|
|
5220
|
-
};
|
|
5221
|
-
const badgeNode = document.querySelector(selectors.badgeCountSelector);
|
|
5222
|
-
const submitButton = document.querySelector(selectors.submitButtonSelector);
|
|
5223
|
-
const dragArea = document.querySelector(selectors.dragAreaSelector);
|
|
5224
|
-
const badgeCount = badgeNode ? Number.parseInt(String(badgeNode.textContent || "").trim(), 10) : 0;
|
|
5225
|
-
return {
|
|
5226
|
-
badgeCount: Number.isFinite(badgeCount) ? badgeCount : 0,
|
|
5227
|
-
selectedCount: document.querySelectorAll(selectors.selectedSourceSelector).length,
|
|
5228
|
-
activeCount: document.querySelectorAll(selectors.activeSourceSelector).length,
|
|
5229
|
-
submitDisabled: submitButton ? submitButton.classList.contains("disable") : null,
|
|
5230
|
-
dragAreaActive: dragArea ? dragArea.classList.contains("active") : false,
|
|
5231
|
-
dragAreaRect: toRect(dragArea)
|
|
5232
|
-
};
|
|
5233
|
-
}, {
|
|
5234
|
-
badgeCountSelector: options.promptBadgeCountSelector,
|
|
5235
|
-
submitButtonSelector: options.promptSubmitButtonSelector,
|
|
5236
|
-
selectedSourceSelector: options.promptSelectedSourceSelector,
|
|
5237
|
-
activeSourceSelector: options.promptActiveSourceSelector,
|
|
5238
|
-
dragAreaSelector: options.dropTargetContainerSelector
|
|
5239
|
-
}).catch(() => ({
|
|
5240
|
-
badgeCount: 0,
|
|
5241
|
-
selectedCount: 0,
|
|
5242
|
-
activeCount: 0,
|
|
5243
|
-
submitDisabled: null,
|
|
5244
|
-
dragAreaActive: false,
|
|
5245
|
-
dragAreaRect: null
|
|
5246
|
-
}));
|
|
5247
|
-
var normalizeCaptchaImageIndexes = (serialNumbers, imageCount) => {
|
|
5248
|
-
if (!Array.isArray(serialNumbers) || imageCount <= 0) {
|
|
5249
|
-
return [];
|
|
5250
|
-
}
|
|
5251
|
-
const areAllOneBased = serialNumbers.every((value) => value >= 1 && value <= imageCount);
|
|
5252
|
-
if (areAllOneBased) {
|
|
5253
|
-
return serialNumbers.map((value) => value - 1);
|
|
5254
|
-
}
|
|
5255
|
-
const areAllZeroBased = serialNumbers.every((value) => value >= 0 && value < imageCount);
|
|
5256
|
-
if (areAllZeroBased) {
|
|
5257
|
-
return [...serialNumbers];
|
|
5258
|
-
}
|
|
5259
|
-
return serialNumbers.map((value) => {
|
|
5260
|
-
if (value >= 1 && value <= imageCount) {
|
|
5261
|
-
return value - 1;
|
|
5262
|
-
}
|
|
5263
|
-
if (value >= 0 && value < imageCount) {
|
|
5264
|
-
return value;
|
|
5265
|
-
}
|
|
5266
|
-
return null;
|
|
5267
|
-
}).filter((value) => Number.isInteger(value));
|
|
5268
|
-
};
|
|
5269
|
-
var resolveCaptchaSourceImagesInVisualOrder = async (frame, options) => {
|
|
5270
|
-
const sourceImages = frame.locator(options.sourceImageSelector);
|
|
5271
|
-
const imageCount = await sourceImages.count().catch(() => 0);
|
|
5272
|
-
const sources = [];
|
|
5273
|
-
for (let domIndex = 0; domIndex < imageCount; domIndex += 1) {
|
|
5274
|
-
const locator = sourceImages.nth(domIndex);
|
|
5275
|
-
const box = await locator.boundingBox().catch(() => null);
|
|
5276
|
-
if (!box || box.width <= 0 || box.height <= 0) {
|
|
5277
|
-
continue;
|
|
5278
|
-
}
|
|
5279
|
-
sources.push({
|
|
5280
|
-
domIndex,
|
|
5281
|
-
locator,
|
|
5282
|
-
box
|
|
5283
|
-
});
|
|
5284
|
-
}
|
|
5285
|
-
sources.sort((left, right) => {
|
|
5286
|
-
const deltaY = left.box.y - right.box.y;
|
|
5287
|
-
if (Math.abs(deltaY) > options.sourceImageRowTolerancePx) {
|
|
5288
|
-
return deltaY;
|
|
5289
|
-
}
|
|
5290
|
-
return left.box.x - right.box.x;
|
|
5291
|
-
});
|
|
5292
|
-
return sources;
|
|
5293
|
-
};
|
|
5294
|
-
var refreshCaptcha = async (page, frame, options) => {
|
|
5295
|
-
const clicked = await clickCaptchaAction(frame, options.refreshTexts, {
|
|
5296
|
-
...options,
|
|
5297
|
-
page,
|
|
5298
|
-
logger: logger10,
|
|
5299
|
-
forceMouse: true
|
|
5300
|
-
}).catch(() => false);
|
|
5301
|
-
if (!clicked) {
|
|
5302
|
-
logger10.warn("Refresh button not found.");
|
|
5303
|
-
return false;
|
|
5304
|
-
}
|
|
5305
|
-
await page.waitForTimeout(options.refreshWaitMs);
|
|
5306
|
-
return true;
|
|
5307
|
-
};
|
|
5308
5158
|
var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
5309
5159
|
const deadline = Date.now() + options.challengeReadyTimeoutMs;
|
|
5310
5160
|
let refreshDeadline = Date.now() + options.challengeReadyRefreshTimeoutMs;
|
|
5311
5161
|
let hasSeenLoading = false;
|
|
5312
|
-
let hasSeenGuideMask = false;
|
|
5313
|
-
let hasLoggedGuideMask = false;
|
|
5314
5162
|
while (Date.now() < deadline) {
|
|
5315
5163
|
const isLoadingVisible = await isAnyCaptchaTextVisible(
|
|
5316
5164
|
frame,
|
|
@@ -5326,17 +5174,8 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5326
5174
|
const sourceImages = frame.locator(options.sourceImageSelector);
|
|
5327
5175
|
const imageCount = await sourceImages.count().catch(() => 0);
|
|
5328
5176
|
const hasVisibleSourceImage = imageCount > 0 ? await sourceImages.first().isVisible({ timeout: options.loadingIndicatorVisibleTimeoutMs }).catch(() => false) : false;
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
hasSeenGuideMask = hasSeenGuideMask || hasGuideMaskVisible;
|
|
5332
|
-
if (hasGuideMaskVisible && !hasLoggedGuideMask) {
|
|
5333
|
-
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");
|
|
5334
|
-
hasLoggedGuideMask = true;
|
|
5335
|
-
}
|
|
5336
|
-
if (!isLoadingVisible && hasVisibleSourceImage && hasVisibleDropTarget && !hasGuideMaskVisible) {
|
|
5337
|
-
logger10.info(
|
|
5338
|
-
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"
|
|
5339
|
-
);
|
|
5177
|
+
if (!isLoadingVisible && hasVisibleSourceImage) {
|
|
5178
|
+
logger10.info(hasSeenLoading ? "\u9A8C\u8BC1\u7801\u56FE\u7247\u5DF2\u52A0\u8F7D\u5B8C\u6210\u3002" : "\u9A8C\u8BC1\u7801\u56FE\u7247\u5DF2\u5C31\u7EEA\u3002");
|
|
5340
5179
|
return;
|
|
5341
5180
|
}
|
|
5342
5181
|
if (hasErrorTextVisible) {
|
|
@@ -5346,8 +5185,8 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5346
5185
|
hasSeenLoading = false;
|
|
5347
5186
|
continue;
|
|
5348
5187
|
}
|
|
5349
|
-
if (
|
|
5350
|
-
logger10.warn(`\u9A8C\u8BC1\u7801\
|
|
5188
|
+
if (!hasVisibleSourceImage && Date.now() >= refreshDeadline) {
|
|
5189
|
+
logger10.warn(`\u9A8C\u8BC1\u7801\u56FE\u7247\u8D85\u8FC7 ${options.challengeReadyRefreshTimeoutMs}ms \u4ECD\u672A\u51FA\u73B0\uFF0C\u5C1D\u8BD5\u5237\u65B0\u9898\u76EE\u3002`);
|
|
5351
5190
|
await refreshCaptcha(page, frame, options);
|
|
5352
5191
|
refreshDeadline = Date.now() + options.challengeReadyRefreshTimeoutMs;
|
|
5353
5192
|
hasSeenLoading = false;
|
|
@@ -5357,69 +5196,6 @@ var waitForCaptchaChallengeReady = async (page, frame, options) => {
|
|
|
5357
5196
|
}
|
|
5358
5197
|
throw new Error("Captcha challenge is still loading and did not become ready in time.");
|
|
5359
5198
|
};
|
|
5360
|
-
var dragPromptCaptchaImage = async (page, frame, iframeLocator, sourceLocator, dropTarget, options, {
|
|
5361
|
-
attempt,
|
|
5362
|
-
visualIndex
|
|
5363
|
-
}) => {
|
|
5364
|
-
const baselineState = await readPromptCaptchaState(frame, options);
|
|
5365
|
-
const dragAttempts = [];
|
|
5366
|
-
for (const plan of PROMPT_CAPTCHA_DRAG_PLANS) {
|
|
5367
|
-
const sourceBox = await sourceLocator.boundingBox().catch(() => null);
|
|
5368
|
-
const targetBox = await dropTarget.boundingBox().catch(() => null);
|
|
5369
|
-
if (!sourceBox || !targetBox) {
|
|
5370
|
-
throw new Error("Unable to resolve prompt captcha drag coordinates.");
|
|
5371
|
-
}
|
|
5372
|
-
const targetOffsetX = (plan.endXRatio - 0.5) * targetBox.width;
|
|
5373
|
-
const targetOffsetY = (plan.endYRatio - 0.5) * targetBox.height;
|
|
5374
|
-
await dragCaptchaAction(page, sourceLocator, dropTarget, {
|
|
5375
|
-
forceMouse: true,
|
|
5376
|
-
targetOffsetX,
|
|
5377
|
-
targetOffsetY,
|
|
5378
|
-
steps: options.promptDragMoveSteps,
|
|
5379
|
-
holdDelayMs: options.promptDragHoldDelayMs,
|
|
5380
|
-
stepDelayMs: options.promptDragStepDelayMs,
|
|
5381
|
-
beforeReleaseDelayMs: options.promptDragBeforeReleaseDelayMs,
|
|
5382
|
-
afterReleaseDelayMs: options.promptDragAfterReleaseDelayMs,
|
|
5383
|
-
finalMoveRepeats: options.promptDragFinalMoveRepeats
|
|
5384
|
-
});
|
|
5385
|
-
const afterState = await readPromptCaptchaState(frame, options);
|
|
5386
|
-
const accepted = afterState.badgeCount > baselineState.badgeCount || afterState.selectedCount > baselineState.selectedCount;
|
|
5387
|
-
const attemptInfo = {
|
|
5388
|
-
planName: plan.name,
|
|
5389
|
-
sourceRect: rectOf(sourceBox),
|
|
5390
|
-
targetRect: rectOf(targetBox),
|
|
5391
|
-
targetOffsetX: Number(targetOffsetX.toFixed(2)),
|
|
5392
|
-
targetOffsetY: Number(targetOffsetY.toFixed(2)),
|
|
5393
|
-
beforeState: baselineState,
|
|
5394
|
-
afterState,
|
|
5395
|
-
accepted
|
|
5396
|
-
};
|
|
5397
|
-
dragAttempts.push(attemptInfo);
|
|
5398
|
-
logger10.info(
|
|
5399
|
-
`\u9A8C\u8BC1\u7801\u62D6\u62FD\u7B2C ${visualIndex + 1} \u5F20\uFF0C\u65B9\u6848 ${plan.name}\uFF0Cbadge ${baselineState.badgeCount} -> ${afterState.badgeCount}\uFF0Cselected ${baselineState.selectedCount} -> ${afterState.selectedCount}`
|
|
5400
|
-
);
|
|
5401
|
-
if (accepted) {
|
|
5402
|
-
return {
|
|
5403
|
-
accepted: true,
|
|
5404
|
-
dragAttempts
|
|
5405
|
-
};
|
|
5406
|
-
}
|
|
5407
|
-
if (options.promptDragRetryDelayMs > 0) {
|
|
5408
|
-
await page.waitForTimeout(options.promptDragRetryDelayMs);
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5411
|
-
await maybeCollectCaptchaDebugInfo(page, frame, iframeLocator, attempt, `drag-${visualIndex + 1}-failed`, options, {
|
|
5412
|
-
visualIndex,
|
|
5413
|
-
dragAttempts,
|
|
5414
|
-
finalState: await readPromptCaptchaState(frame, options)
|
|
5415
|
-
}).catch((error) => {
|
|
5416
|
-
logger10.warn(`\u9A8C\u8BC1\u7801\u62D6\u62FD\u5931\u8D25\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5417
|
-
});
|
|
5418
|
-
return {
|
|
5419
|
-
accepted: false,
|
|
5420
|
-
dragAttempts
|
|
5421
|
-
};
|
|
5422
|
-
};
|
|
5423
5199
|
async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
5424
5200
|
const { callCaptchaRecognitionApi: callCaptchaRecognitionApi2 } = dependencies;
|
|
5425
5201
|
if (typeof callCaptchaRecognitionApi2 !== "function") {
|
|
@@ -5434,7 +5210,7 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5434
5210
|
return false;
|
|
5435
5211
|
}
|
|
5436
5212
|
logger10.info("\u5F53\u524D\u4F7F\u7528\u672Ctool\u2014\u2014\u6D4B\u8BD5\u7248\u672C");
|
|
5437
|
-
for (let attempt = 1; attempt <= config.maxRetries; attempt
|
|
5213
|
+
for (let attempt = 1; attempt <= config.maxRetries; attempt++) {
|
|
5438
5214
|
logger10.info(`\u5F00\u59CB\u7B2C ${attempt}/${config.maxRetries} \u6B21 verifycenter \u9A8C\u8BC1\u7801\u8BC6\u522B\u3002`);
|
|
5439
5215
|
try {
|
|
5440
5216
|
const captchaContext = await getVerifycenterCaptchaContext(page, config);
|
|
@@ -5444,16 +5220,6 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5444
5220
|
}
|
|
5445
5221
|
const { iframeLocator, frame } = captchaContext;
|
|
5446
5222
|
await waitForCaptchaChallengeReady(page, frame, config);
|
|
5447
|
-
await maybeCollectCaptchaDebugInfo(
|
|
5448
|
-
page,
|
|
5449
|
-
frame,
|
|
5450
|
-
iframeLocator,
|
|
5451
|
-
attempt,
|
|
5452
|
-
"ready",
|
|
5453
|
-
config
|
|
5454
|
-
).catch((error) => {
|
|
5455
|
-
logger10.warn(`\u9A8C\u8BC1\u7801\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5456
|
-
});
|
|
5457
5223
|
await page.waitForTimeout(config.recognitionDelayMs);
|
|
5458
5224
|
const screenshotBuffer = await iframeLocator.screenshot();
|
|
5459
5225
|
const apiResponse = await callCaptchaRecognitionApi2({
|
|
@@ -5477,74 +5243,33 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
5477
5243
|
await refreshCaptcha(page, frame, config);
|
|
5478
5244
|
continue;
|
|
5479
5245
|
}
|
|
5480
|
-
const
|
|
5481
|
-
const
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
}
|
|
5487
|
-
logger10.info(`\u9A8C\u8BC1\u7801\u89C6\u89C9\u4F4D\u5E8F\u6620\u5C04\uFF1A${normalizedIndexes.map((index) => index + 1).join(", ")}`);
|
|
5488
|
-
for (const imageIndex of normalizedIndexes) {
|
|
5489
|
-
if (imageIndex < 0 || imageIndex >= orderedSourceImages.length) {
|
|
5490
|
-
throw new Error(
|
|
5491
|
-
`Captcha image index ${imageIndex} is out of range. count=${orderedSourceImages.length}`
|
|
5492
|
-
);
|
|
5246
|
+
const sourceImages = frame.locator(config.sourceImageSelector);
|
|
5247
|
+
const imageCount = await sourceImages.count();
|
|
5248
|
+
for (const rawIndex of serialNumbers) {
|
|
5249
|
+
let imageIndex = rawIndex;
|
|
5250
|
+
if (imageIndex >= imageCount && imageIndex > 0 && imageIndex - 1 < imageCount) {
|
|
5251
|
+
imageIndex -= 1;
|
|
5493
5252
|
}
|
|
5494
|
-
|
|
5253
|
+
if (imageIndex < 0 || imageIndex >= imageCount) {
|
|
5254
|
+
throw new Error(`Captcha image index ${rawIndex} is out of range. count=${imageCount}`);
|
|
5255
|
+
}
|
|
5256
|
+
const sourceImage = sourceImages.nth(imageIndex);
|
|
5495
5257
|
await sourceImage.waitFor({
|
|
5496
5258
|
state: "visible",
|
|
5497
5259
|
timeout: config.sourceImageVisibleTimeoutMs
|
|
5498
5260
|
});
|
|
5499
|
-
|
|
5500
|
-
page,
|
|
5501
|
-
frame,
|
|
5502
|
-
iframeLocator,
|
|
5503
|
-
sourceImage,
|
|
5504
|
-
dropTarget,
|
|
5505
|
-
config,
|
|
5506
|
-
{
|
|
5507
|
-
attempt,
|
|
5508
|
-
visualIndex: imageIndex
|
|
5509
|
-
}
|
|
5510
|
-
);
|
|
5511
|
-
if (!dragResult.accepted) {
|
|
5512
|
-
throw new Error(`Captcha prompt drag was not accepted for visual index ${imageIndex + 1}.`);
|
|
5513
|
-
}
|
|
5514
|
-
if (config.dragBetweenWaitMs > 0) {
|
|
5515
|
-
await page.waitForTimeout(config.dragBetweenWaitMs);
|
|
5516
|
-
}
|
|
5261
|
+
await dragCaptchaAction(page, sourceImage, dropTarget);
|
|
5517
5262
|
}
|
|
5518
|
-
const
|
|
5519
|
-
logger10.info(
|
|
5520
|
-
`\u63D0\u4EA4\u524D\u9A8C\u8BC1\u7801\u72B6\u6001\uFF1Abadge=${beforeSubmitState.badgeCount}, selected=${beforeSubmitState.selectedCount}, submitDisabled=${beforeSubmitState.submitDisabled}`
|
|
5521
|
-
);
|
|
5522
|
-
const submitted = await clickCaptchaAction(frame, config.submitTexts, {
|
|
5523
|
-
...config,
|
|
5524
|
-
page,
|
|
5525
|
-
logger: logger10,
|
|
5526
|
-
forceMouse: true,
|
|
5527
|
-
actionVisibleTimeoutMs: config.submitReadyTimeoutMs
|
|
5528
|
-
}).catch(() => false);
|
|
5263
|
+
const submitted = await clickCaptchaAction(frame, config.submitTexts, { ...config, page }).catch(() => false);
|
|
5529
5264
|
if (!submitted) {
|
|
5530
5265
|
logger10.warn("\u672A\u627E\u5230\u63D0\u4EA4\u6309\u94AE\uFF0C\u53EF\u80FD\u4F1A\u81EA\u52A8\u63D0\u4EA4\u3002");
|
|
5531
5266
|
}
|
|
5532
5267
|
await page.waitForTimeout(config.submitWaitMs);
|
|
5533
|
-
const afterSubmitState = await readPromptCaptchaState(frame, config);
|
|
5534
|
-
logger10.info(
|
|
5535
|
-
`\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801\u72B6\u6001\uFF1Abadge=${afterSubmitState.badgeCount}, selected=${afterSubmitState.selectedCount}, submitDisabled=${afterSubmitState.submitDisabled}`
|
|
5536
|
-
);
|
|
5537
5268
|
const stillVisible = await iframeLocator.isVisible({ timeout: config.containerVisibleTimeoutMs }).catch(() => false);
|
|
5538
5269
|
if (!stillVisible) {
|
|
5539
5270
|
logger10.info("\u9A8C\u8BC1\u7801\u8BC6\u522B\u5E76\u63D0\u4EA4\u6210\u529F\u3002");
|
|
5540
5271
|
return true;
|
|
5541
5272
|
}
|
|
5542
|
-
await maybeCollectCaptchaDebugInfo(page, frame, iframeLocator, attempt, "submit-still-visible", config, {
|
|
5543
|
-
beforeSubmitState,
|
|
5544
|
-
afterSubmitState
|
|
5545
|
-
}).catch((error) => {
|
|
5546
|
-
logger10.warn(`\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801\u8C03\u8BD5\u6293\u53D6\u5931\u8D25\uFF1A${error?.message || error}`);
|
|
5547
|
-
});
|
|
5548
5273
|
logger10.warn("\u63D0\u4EA4\u540E\u9A8C\u8BC1\u7801 iframe \u4ECD\u7136\u53EF\u89C1\uFF0C\u51C6\u5907\u5237\u65B0\u540E\u91CD\u8BD5\u3002");
|
|
5549
5274
|
await page.waitForTimeout(2e3);
|
|
5550
5275
|
await refreshCaptcha(page, frame, config);
|
|
@@ -5987,14 +5712,14 @@ var Mutation = {
|
|
|
5987
5712
|
const isFrameElement = tagName === "IFRAME" || tagName === "FRAME";
|
|
5988
5713
|
const nodeName = descriptor?.id || descriptor?.name || "no-id";
|
|
5989
5714
|
let source = "main";
|
|
5990
|
-
let
|
|
5715
|
+
let path2 = `${selector}[${index}]`;
|
|
5991
5716
|
let text = "";
|
|
5992
5717
|
let html = "";
|
|
5993
5718
|
let frameUrl = "";
|
|
5994
5719
|
let readyState = "";
|
|
5995
5720
|
if (isFrameElement) {
|
|
5996
5721
|
source = "iframe";
|
|
5997
|
-
|
|
5722
|
+
path2 = `${selector}[${index}]::iframe(${nodeName})`;
|
|
5998
5723
|
const frame = await handle.contentFrame();
|
|
5999
5724
|
if (frame) {
|
|
6000
5725
|
try {
|
|
@@ -6024,7 +5749,7 @@ var Mutation = {
|
|
|
6024
5749
|
items.push({
|
|
6025
5750
|
selector,
|
|
6026
5751
|
source,
|
|
6027
|
-
path:
|
|
5752
|
+
path: path2,
|
|
6028
5753
|
text,
|
|
6029
5754
|
html,
|
|
6030
5755
|
frameUrl,
|