修复whatshub工单
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
47demv6l5lvam1gzqdkzrih64pb0tzqd.gddJCefh0gXT5ZBsRHlHGniOhraU34wwA4o-jjmdTFw
|
||||||
Executable
+1
@@ -0,0 +1 @@
|
|||||||
|
1213
|
||||||
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
Executable
+210
@@ -0,0 +1,210 @@
|
|||||||
|
<?php
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
ini_set('display_errors', 'ON');
|
||||||
|
echo 1111;exit;
|
||||||
|
// 文件名: run.php
|
||||||
|
// require_once __DIR__ . '/Chatknow.php'; // ChatKnow SCRM
|
||||||
|
require_once __DIR__ . '/A2c.php'; // A2c云控
|
||||||
|
// require_once __DIR__ . '/Xinghe2.php'; // 星河云控
|
||||||
|
require_once __DIR__ . '/Huojian.php'; // 火箭
|
||||||
|
// require_once __DIR__ . '/SsCustomer.php'; // SS云控(Customer)
|
||||||
|
// require_once __DIR__ . '/Haiwang.php'; // 海王
|
||||||
|
// require_once __DIR__ . '/Whatshub.php'; // Whatshub 工单平台
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// /*
|
||||||
|
// 命令行可以测试Cloudflare防火墙
|
||||||
|
// curl -s -X POST http://127.0.0.1:3001/api/auth-and-intercept \
|
||||||
|
// -H 'Content-Type: application/json' \
|
||||||
|
// -d '{
|
||||||
|
// "pageUrl": "https://web.whatshub.cc/m/iTYsWKQH5030/1",
|
||||||
|
// "apiUrls": ["/api/whatshub-counter/workShare/open/detail"],
|
||||||
|
// "authActions": [
|
||||||
|
// {"type": "vue_fill", "selector": ".el-input__inner", "value": "745030"},
|
||||||
|
// {"type": "wait", "ms": 500},
|
||||||
|
// {"type": "vue_click", "selector": ".vxe-button-group .theme--primary"},
|
||||||
|
// {"type": "wait", "ms": 2200}
|
||||||
|
// ],
|
||||||
|
// "antiBot": {
|
||||||
|
// "enabled": true,
|
||||||
|
// "profile": "real",
|
||||||
|
// "turnstile": true,
|
||||||
|
// "solverFallback": true,
|
||||||
|
// "sessionKey": "whatshub:t.flowerbells.top",
|
||||||
|
// "challengeTimeoutMs": 60000
|
||||||
|
// }
|
||||||
|
// }' | jq .
|
||||||
|
// */
|
||||||
|
|
||||||
|
// echo "🚀 开始执行<Whatshub 工单平台>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
// $pageUrl = 'https://web.whatshub.cc/m/iTYsWKQH5030/1'; // PageUrl 入口授权页
|
||||||
|
// $username = ""; // 登录账号
|
||||||
|
// $password = "745030"; // 登录密码
|
||||||
|
// $spider = new Whatshub($pageUrl, $username, $password);
|
||||||
|
// $finalData = $spider->run();
|
||||||
|
|
||||||
|
// echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
// echo "----------------------------------------\n\r";
|
||||||
|
// echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
// echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
// echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
// echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
// echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
// echo "号码列表:\n\r";
|
||||||
|
// echo dd($finalData->numbers);
|
||||||
|
// } catch (Exception $e) {
|
||||||
|
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// echo "🚀 开始执行<ChatKnow SCRM>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
// $pageUrl = 'https://user.chatknow.com/child/workorder-share?shareKey=jf5t6MNrJ2mC76N'; // PageUrl 入口授权页
|
||||||
|
// $username = ""; // 登录账号
|
||||||
|
// $password = ""; // 登录密码
|
||||||
|
// $spider = new Chatknow($pageUrl, $username, $password);
|
||||||
|
// $finalData = $spider->run();
|
||||||
|
|
||||||
|
// echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
// echo "----------------------------------------\n\r";
|
||||||
|
// echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
// echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
// echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
// echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
// echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
// echo "号码列表:\n\r";
|
||||||
|
// echo dd($finalData->numbers);
|
||||||
|
// } catch (Exception $e) {
|
||||||
|
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// echo "🚀 开始执行<A2c云控>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
// $pageUrl = 'https://yyk.ink/52oXZRG'; // PageUrl 入口授权页
|
||||||
|
// $username = ""; // 登录账号
|
||||||
|
// $password = ""; // 登录密码
|
||||||
|
// $spider = new A2c($pageUrl, $username, $password);
|
||||||
|
// $finalData = $spider->run();
|
||||||
|
|
||||||
|
// echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
// echo "----------------------------------------\n\r";
|
||||||
|
// echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
// echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
// echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
// echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
// echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
// echo "号码列表:\n\r";
|
||||||
|
// echo dd($finalData->numbers);
|
||||||
|
|
||||||
|
// } catch (Exception $e) {
|
||||||
|
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// echo "🚀 开始执行<星河云控>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
// $pageUrl = 'http://8.218.14.51/share/share/index.html?token=hn6z3egq4nnnebkv4063pcdouzr4ug5js902mlqo2n3yp9gzhe'; // PageUrl 入口授权页
|
||||||
|
// $username = ""; // 登录账号
|
||||||
|
// $password = ""; // 登录密码
|
||||||
|
// $spider = new Xinghe($pageUrl, $username, $password);
|
||||||
|
// $finalData = $spider->run();
|
||||||
|
|
||||||
|
// echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
// echo "----------------------------------------\n\r";
|
||||||
|
// echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
// echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
// echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
// echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
// echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
// echo "号码列表:\n\r";
|
||||||
|
// echo dd($finalData->numbers);
|
||||||
|
// } catch (Exception $e) {
|
||||||
|
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
// }
|
||||||
|
|
||||||
|
try {
|
||||||
|
echo "🚀 开始执行<火箭工单>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
$pageUrl = 'https://s.url99.me/50q3622j'; // PageUrl 入口授权页
|
||||||
|
$username = ""; // 登录账号
|
||||||
|
$password = "666666"; // 登录密码
|
||||||
|
$spider = new Huojian($pageUrl, $username, $password);
|
||||||
|
$finalData = $spider->run();
|
||||||
|
|
||||||
|
echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
echo "----------------------------------------\n\r";
|
||||||
|
echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
echo "号码列表:\n\r";
|
||||||
|
echo dd($finalData->numbers);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
}
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// echo "🚀 开始执行<SS云控(Customer)>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
// $pageUrl = 'https://app.salesmartly.vip/next/share/reports/verify/customer/fwt7cg'; // PageUrl 入口授权页
|
||||||
|
// $username = ""; // 登录账号
|
||||||
|
// $password = "123456"; // 登录密码
|
||||||
|
// $spider = new SsCustomer($pageUrl, $username, $password);
|
||||||
|
// $finalData = $spider->run();
|
||||||
|
|
||||||
|
// echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
// echo "----------------------------------------\n\r";
|
||||||
|
// echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
// echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
// echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
// echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
// echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
// echo "号码列表:\n\r";
|
||||||
|
// echo dd($finalData->numbers);
|
||||||
|
|
||||||
|
|
||||||
|
// } catch (Exception $e) {
|
||||||
|
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// echo "🚀 开始执行<海王>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
// $pageUrl = 'https://admin.haiwangweb.com/web#/accountshow/pZsEulYrb'; // PageUrl 入口授权页
|
||||||
|
// $username = ""; // 登录账号
|
||||||
|
// $password = "9999"; // 登录密码
|
||||||
|
// $spider = new Haiwang($pageUrl, $username, $password);
|
||||||
|
// $finalData = $spider->run();
|
||||||
|
|
||||||
|
// echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
// echo "----------------------------------------\n\r";
|
||||||
|
// echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
// echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
// echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
// echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
// echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
// echo "号码列表:\n\r";
|
||||||
|
// echo dd($finalData->numbers);
|
||||||
|
|
||||||
|
// } catch (Exception $e) {
|
||||||
|
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// echo "🚀 开始执行<CEO SCRM>抓取任务 (多引擎智能调度)...\n\r";
|
||||||
|
// $pageUrl = 'https://admin.scrmceo.com/#/workShareDetail?code=XgGTK5yN'; // PageUrl 入口授权页
|
||||||
|
// $username = ""; // 登录账号
|
||||||
|
// $password = "a2222"; // 登录密码
|
||||||
|
// $spider = new SsCustomer($pageUrl, $username, $password);
|
||||||
|
// $finalData = $spider->run();
|
||||||
|
|
||||||
|
// echo "✅ 任务完成!统一数据如下:\n\r";
|
||||||
|
// echo "----------------------------------------\n\r";
|
||||||
|
// echo "当日新增:{$finalData->todayNewCount} 人\n\r";
|
||||||
|
// echo "在线号码:{$finalData->totalOnline} 个\n\r";
|
||||||
|
// echo "离线号码:{$finalData->totalOffline} 个\n\r";
|
||||||
|
// echo "Total:" . $finalData->total . " 个号码\n\r";
|
||||||
|
// echo "实际总共抓取:" . count($finalData->numbers) . " 个号码\n\r";
|
||||||
|
// echo "号码列表:\n\r";
|
||||||
|
// echo dd($finalData->numbers);
|
||||||
|
// } catch (Exception $e) {
|
||||||
|
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
|
||||||
|
// }
|
||||||
Regular → Executable
Regular → Executable
Regular → Executable
Regular → Executable
@@ -4,7 +4,7 @@ return array (
|
|||||||
'name' => 'link管理系统',
|
'name' => 'link管理系统',
|
||||||
'beian' => '',
|
'beian' => '',
|
||||||
'cdnurl' => '',
|
'cdnurl' => '',
|
||||||
'version' => '1.0.9',
|
'version' => '1.0.10',
|
||||||
'timezone' => 'Asia/Shanghai',
|
'timezone' => 'Asia/Shanghai',
|
||||||
'forbiddenip' => '',
|
'forbiddenip' => '',
|
||||||
'languages' =>
|
'languages' =>
|
||||||
|
|||||||
Regular → Executable
Regular → Executable
+3
-3
@@ -114,10 +114,10 @@ class WhatshubSpider extends AbstractScrmSpider
|
|||||||
return parent::run();
|
return parent::run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whatshub vxe 密码表单:placeholder 含「密码」+ 确认按钮,与业务页搜索框区分 */
|
/** Whatshub vxe 密码表单内 input / 确认按钮(避免误填业务页搜索框) */
|
||||||
private const AUTH_PASSWORD_INPUT = '.vxe-form .el-input__inner[placeholder*="密码"]';
|
private const AUTH_PASSWORD_INPUT = '.vxe-form .el-input__inner';
|
||||||
|
|
||||||
private const AUTH_CONFIRM_BUTTON = '.vxe-form .vxe-button-group button.theme--primary[type="submit"]';
|
private const AUTH_CONFIRM_BUTTON = '.vxe-form button.theme--primary[type="submit"]';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node 监听 statistics API,返回 dayNewFans + reDayNewFans 总和;失败返回 null
|
* Node 监听 statistics API,返回 dayNewFans + reDayNewFans 总和;失败返回 null
|
||||||
|
|||||||
Regular → Executable
+38
-328
@@ -213,30 +213,6 @@ async function waitForUrlSettled(page, { maxAttempts = 15, stableMs = 500, redir
|
|||||||
return currentUrl;
|
return currentUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** PHP → Node 透传的 Whatshub/auth 扩展字段(normalizeAntiBot 不含这些项) */
|
|
||||||
const WHATSHUB_AUTH_EXTRA_KEYS = [
|
|
||||||
'authSkipIfNoPasswordDialog',
|
|
||||||
'authSelectorTimeoutMs',
|
|
||||||
'earlyApiIntercept',
|
|
||||||
'skipPostCfReadyApi',
|
|
||||||
'purgeSession',
|
|
||||||
'postCfReadySelectorOptional',
|
|
||||||
'skipShortLinkCfPurgeOnReuse',
|
|
||||||
];
|
|
||||||
|
|
||||||
function pickAntiBotExtraFields(rawAntiBot, keys) {
|
|
||||||
const extras = {};
|
|
||||||
if (!rawAntiBot || typeof rawAntiBot !== 'object') {
|
|
||||||
return extras;
|
|
||||||
}
|
|
||||||
for (const key of keys) {
|
|
||||||
if (rawAntiBot[key] !== undefined) {
|
|
||||||
extras[key] = rawAntiBot[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return extras;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 合并 antiBot 扩展字段(postCfReady* 由 PHP 按工单类型传入,未配置则跳过) */
|
/** 合并 antiBot 扩展字段(postCfReady* 由 PHP 按工单类型传入,未配置则跳过) */
|
||||||
function resolveAntiBot(rawAntiBot) {
|
function resolveAntiBot(rawAntiBot) {
|
||||||
const base = normalizeAntiBot(rawAntiBot);
|
const base = normalizeAntiBot(rawAntiBot);
|
||||||
@@ -245,7 +221,6 @@ function resolveAntiBot(rawAntiBot) {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...base,
|
...base,
|
||||||
...pickAntiBotExtraFields(rawAntiBot, WHATSHUB_AUTH_EXTRA_KEYS),
|
|
||||||
postCfReadyUrlContains: rawAntiBot.postCfReadyUrlContains || '',
|
postCfReadyUrlContains: rawAntiBot.postCfReadyUrlContains || '',
|
||||||
postCfReadySelector: rawAntiBot.postCfReadySelector || '',
|
postCfReadySelector: rawAntiBot.postCfReadySelector || '',
|
||||||
postCfReadyApiUrl: rawAntiBot.postCfReadyApiUrl || '',
|
postCfReadyApiUrl: rawAntiBot.postCfReadyApiUrl || '',
|
||||||
@@ -291,7 +266,6 @@ function applyWhatshubPostCfDefaults(antiBot, pageUrl) {
|
|||||||
postCfSettleMs: antiBot.postCfSettleMs || 500,
|
postCfSettleMs: antiBot.postCfSettleMs || 500,
|
||||||
postCfSpaWaitMs: antiBot.postCfSpaWaitMs || 4000,
|
postCfSpaWaitMs: antiBot.postCfSpaWaitMs || 4000,
|
||||||
skipShortLinkCfPurgeOnReuse: antiBot.skipShortLinkCfPurgeOnReuse !== false,
|
skipShortLinkCfPurgeOnReuse: antiBot.skipShortLinkCfPurgeOnReuse !== false,
|
||||||
authSkipIfNoPasswordDialog: antiBot.authSkipIfNoPasswordDialog !== false,
|
|
||||||
};
|
};
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return antiBot;
|
return antiBot;
|
||||||
@@ -481,11 +455,7 @@ function isWhatshubHost(url) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whatshub 密码弹窗 DOM 选择器(与 PHP WhatshubSpider authActions 保持一致) */
|
/** Whatshub 密码 UI 是否可见(vxe-form / vxe-modal + Element dialog) */
|
||||||
const WHATSHUB_PASSWORD_INPUT_SEL = '.vxe-form .el-input__inner[placeholder*="密码"]';
|
|
||||||
const WHATSHUB_PASSWORD_CONFIRM_SEL = '.vxe-form .vxe-button-group button.theme--primary[type="submit"]';
|
|
||||||
|
|
||||||
/** Whatshub 密码 UI 是否可见(必须密码 input + 确认按钮同框,排除搜索区 vxe-form) */
|
|
||||||
async function isWhatshubPasswordDialogVisible(page) {
|
async function isWhatshubPasswordDialogVisible(page) {
|
||||||
return page.evaluate(() => {
|
return page.evaluate(() => {
|
||||||
const isVisible = (el) => {
|
const isVisible = (el) => {
|
||||||
@@ -495,53 +465,26 @@ async function isWhatshubPasswordDialogVisible(page) {
|
|||||||
const style = window.getComputedStyle(el);
|
const style = window.getComputedStyle(el);
|
||||||
return style.display !== 'none' && style.visibility !== 'hidden';
|
return style.display !== 'none' && style.visibility !== 'hidden';
|
||||||
};
|
};
|
||||||
const isPasswordInput = (input) => {
|
const hasVisiblePasswordInput = (root) => {
|
||||||
if (!input || !isVisible(input)) return false;
|
const pwd = root.querySelector('.vxe-form .el-input__inner, .el-input__inner[placeholder*="密码"]');
|
||||||
const placeholder = (input.getAttribute('placeholder') || '').trim();
|
return pwd && isVisible(pwd);
|
||||||
if (placeholder.includes('密码')) return true;
|
|
||||||
return input.getAttribute('maxlength') === '8';
|
|
||||||
};
|
|
||||||
const rootHasPasswordForm = (root) => {
|
|
||||||
if (!root || !isVisible(root)) return false;
|
|
||||||
const pwd = root.querySelector('.el-input__inner[placeholder*="密码"], .el-input__inner[maxlength="8"]');
|
|
||||||
if (!isPasswordInput(pwd)) return false;
|
|
||||||
const confirm = root.querySelector(
|
|
||||||
'.vxe-button-group button.theme--primary[type="submit"], button.theme--primary[type="submit"]'
|
|
||||||
);
|
|
||||||
return !!(confirm && isVisible(confirm));
|
|
||||||
};
|
};
|
||||||
const roots = document.querySelectorAll(
|
const roots = document.querySelectorAll(
|
||||||
'form.vxe-form, .vxe-modal--wrapper, .vxe-modal, '
|
'form.vxe-form, .vxe-modal--wrapper, .vxe-modal, '
|
||||||
+ '.el-message-box, .el-overlay-message-box, .el-dialog, .el-overlay-dialog'
|
+ '.el-message-box, .el-overlay-message-box, .el-dialog, .el-overlay-dialog'
|
||||||
);
|
);
|
||||||
for (const root of roots) {
|
for (const root of roots) {
|
||||||
if (rootHasPasswordForm(root)) return true;
|
if (!isVisible(root)) continue;
|
||||||
|
if (hasVisiblePasswordInput(root)) return true;
|
||||||
|
}
|
||||||
|
const standaloneForm = document.querySelector('form.vxe-form');
|
||||||
|
if (standaloneForm && isVisible(standaloneForm) && hasVisiblePasswordInput(standaloneForm)) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}).catch(() => false);
|
}).catch(() => false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 业务页表格已就绪且页面上无密码确认按钮 → 视为 session 已登录 */
|
|
||||||
async function isWhatshubBusinessLoggedIn(page) {
|
|
||||||
return page.evaluate(() => {
|
|
||||||
const isVisible = (el) => {
|
|
||||||
if (!el) return false;
|
|
||||||
const rect = el.getBoundingClientRect();
|
|
||||||
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
||||||
const style = window.getComputedStyle(el);
|
|
||||||
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
||||||
};
|
|
||||||
const tableReady = !!document.querySelector('.vxe-table, .vxe-grid');
|
|
||||||
const pwdDialog = document.querySelector('.vxe-form .el-input__inner[placeholder*="密码"]');
|
|
||||||
const confirmBtn = document.querySelector(
|
|
||||||
'.vxe-form .vxe-button-group button.theme--primary[type="submit"]'
|
|
||||||
);
|
|
||||||
const hasPasswordUi = (pwdDialog && isVisible(pwdDialog))
|
|
||||||
&& (confirmBtn && isVisible(confirmBtn));
|
|
||||||
return tableReady && !hasPasswordUi;
|
|
||||||
}).catch(() => false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** statistics-only 等场景:导航后立即挂 API 拦截器,避免 session 复用时响应早于监听 */
|
/** statistics-only 等场景:导航后立即挂 API 拦截器,避免 session 复用时响应早于监听 */
|
||||||
function shouldUseEarlyApiIntercept(antiBot, apiUrls) {
|
function shouldUseEarlyApiIntercept(antiBot, apiUrls) {
|
||||||
if (antiBot?.earlyApiIntercept === true) {
|
if (antiBot?.earlyApiIntercept === true) {
|
||||||
@@ -1450,8 +1393,8 @@ async function collectPageDiagnostics(page) {
|
|||||||
bodyText: (document.body && document.body.innerText ? document.body.innerText : '').slice(0, 500),
|
bodyText: (document.body && document.body.innerText ? document.body.innerText : '').slice(0, 500),
|
||||||
elInputInner: document.querySelectorAll('.el-input__inner').length,
|
elInputInner: document.querySelectorAll('.el-input__inner').length,
|
||||||
vxeForm: document.querySelectorAll('form.vxe-form').length,
|
vxeForm: document.querySelectorAll('form.vxe-form').length,
|
||||||
vxePasswordInput: document.querySelectorAll('.vxe-form .el-input__inner[placeholder*="密码"]').length,
|
vxePasswordInput: document.querySelectorAll('.vxe-form .el-input__inner').length,
|
||||||
vxeConfirmBtn: document.querySelectorAll('.vxe-form .vxe-button-group button.theme--primary[type="submit"]').length,
|
vxeConfirmBtn: document.querySelectorAll('.vxe-form button.theme--primary').length,
|
||||||
elTable: document.querySelectorAll('.el-table').length,
|
elTable: document.querySelectorAll('.el-table').length,
|
||||||
vxeTable: document.querySelectorAll('.vxe-table, .vxe-grid').length,
|
vxeTable: document.querySelectorAll('.vxe-table, .vxe-grid').length,
|
||||||
btnNext: document.querySelectorAll('.btn-next').length,
|
btnNext: document.querySelectorAll('.btn-next').length,
|
||||||
@@ -1518,11 +1461,6 @@ async function awaitPostCfBusinessReady(page, antiBot, waitForUrlSettledFn, stor
|
|||||||
}
|
}
|
||||||
if (!skipApiWait) {
|
if (!skipApiWait) {
|
||||||
await waitForPostCfListApi(page, antiBot, timeoutMs);
|
await waitForPostCfListApi(page, antiBot, timeoutMs);
|
||||||
} else if (antiBot?.authSkipIfNoPasswordDialog && isStatisticsOnlyApiUrls(apiUrls)) {
|
|
||||||
console.log(
|
|
||||||
'[CF] 跳过 pre-auth statistics 等待'
|
|
||||||
+ '(sid 直进业务页:auth 跳过后 reload 补捕获;需填密码:auth 提交后 waitForApis)'
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
console.log('[CF] 跳过 pre-auth 业务 API 等待(statistics 在密码验证后触发)');
|
console.log('[CF] 跳过 pre-auth 业务 API 等待(statistics 在密码验证后触发)');
|
||||||
}
|
}
|
||||||
@@ -1607,180 +1545,54 @@ async function awaitPostCfBusinessReady(page, antiBot, waitForUrlSettledFn, stor
|
|||||||
|
|
||||||
async function executeAuthActionsWithDiagnostics(page, authActions, antiBot = null) {
|
async function executeAuthActionsWithDiagnostics(page, authActions, antiBot = null) {
|
||||||
try {
|
try {
|
||||||
return await executeAuthActions(page, authActions, antiBot);
|
await executeAuthActions(page, authActions, antiBot);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
err.pageDiagnostics = await collectPageDiagnostics(page);
|
err.pageDiagnostics = await collectPageDiagnostics(page);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 采集 Whatshub auth 决策所需的 DOM 计数(与 collectPageDiagnostics 字段对齐) */
|
async function shouldSkipWhatshubAuthActions(page, antiBot) {
|
||||||
async function collectWhatshubAuthDomCounts(page) {
|
|
||||||
return page.evaluate(() => ({
|
|
||||||
vxeTable: document.querySelectorAll('.vxe-table, .vxe-grid').length,
|
|
||||||
vxePasswordInput: document.querySelectorAll(
|
|
||||||
'.vxe-form .el-input__inner[placeholder*="密码"]'
|
|
||||||
).length,
|
|
||||||
vxeConfirmBtn: document.querySelectorAll(
|
|
||||||
'.vxe-form .vxe-button-group button.theme--primary[type="submit"]'
|
|
||||||
).length,
|
|
||||||
})).catch(() => ({ vxeTable: 0, vxePasswordInput: 0, vxeConfirmBtn: 0 }));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whatshub skip-auth 决策:URL 仅确认路由,登录/业务态靠 DOM
|
|
||||||
* @returns {Promise<{skip: boolean, reason: string, pwdVisible?: boolean, businessLoggedIn?: boolean, dom?: object, url?: string}>}
|
|
||||||
*/
|
|
||||||
async function resolveWhatshubAuthSkipDecision(page, antiBot) {
|
|
||||||
if (!antiBot?.authSkipIfNoPasswordDialog) {
|
if (!antiBot?.authSkipIfNoPasswordDialog) {
|
||||||
return { skip: false, reason: 'authSkipIfNoPasswordDialog_disabled' };
|
return false;
|
||||||
}
|
}
|
||||||
const urlContains = (antiBot.postCfReadyUrlContains || 'work-order-sharing').trim();
|
const urlContains = (antiBot.postCfReadyUrlContains || 'work-order-sharing').trim();
|
||||||
let currentUrl = '';
|
|
||||||
try {
|
try {
|
||||||
currentUrl = page.url();
|
const onBusiness = !urlContains || page.url().includes(urlContains);
|
||||||
} catch (_) {
|
if (!onBusiness) {
|
||||||
return { skip: false, reason: 'page_url_unavailable' };
|
return false;
|
||||||
}
|
}
|
||||||
const onBusinessRoute = !urlContains || currentUrl.includes(urlContains);
|
|
||||||
if (!onBusinessRoute) {
|
|
||||||
return { skip: false, reason: 'not_on_business_route', url: currentUrl };
|
|
||||||
}
|
|
||||||
|
|
||||||
const pwdVisible = await isWhatshubPasswordDialogVisible(page);
|
const pwdVisible = await isWhatshubPasswordDialogVisible(page);
|
||||||
const businessLoggedIn = await isWhatshubBusinessLoggedIn(page);
|
if (!pwdVisible) {
|
||||||
const dom = await collectWhatshubAuthDomCounts(page);
|
return true;
|
||||||
|
|
||||||
if (pwdVisible) {
|
|
||||||
return {
|
|
||||||
skip: false,
|
|
||||||
reason: 'password_dialog_visible',
|
|
||||||
pwdVisible,
|
|
||||||
businessLoggedIn,
|
|
||||||
dom,
|
|
||||||
url: currentUrl,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
const tableReadyNoPassword = dom.vxeTable > 0
|
} catch (_) {
|
||||||
&& dom.vxePasswordInput === 0
|
/* ignore */
|
||||||
&& dom.vxeConfirmBtn === 0;
|
|
||||||
if (businessLoggedIn || tableReadyNoPassword) {
|
|
||||||
return {
|
|
||||||
skip: true,
|
|
||||||
reason: businessLoggedIn ? 'business_logged_in' : 'table_ready_no_password_ui',
|
|
||||||
pwdVisible,
|
|
||||||
businessLoggedIn,
|
|
||||||
dom,
|
|
||||||
url: currentUrl,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return {
|
return false;
|
||||||
skip: true,
|
|
||||||
reason: 'no_password_dialog_on_business_route',
|
|
||||||
pwdVisible,
|
|
||||||
businessLoggedIn,
|
|
||||||
dom,
|
|
||||||
url: currentUrl,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function logWhatshubAuthSkipDecision(decision) {
|
|
||||||
const dom = decision.dom || {};
|
|
||||||
console.log(
|
|
||||||
'[Whatshub] auth skip 决策'
|
|
||||||
+ ` skip=${decision.skip}`
|
|
||||||
+ ` reason=${decision.reason}`
|
|
||||||
+ ` pwdVisible=${decision.pwdVisible}`
|
|
||||||
+ ` businessLoggedIn=${decision.businessLoggedIn}`
|
|
||||||
+ ` vxeTable=${dom.vxeTable ?? '?'}`
|
|
||||||
+ ` vxePasswordInput=${dom.vxePasswordInput ?? '?'}`
|
|
||||||
+ ` vxeConfirmBtn=${dom.vxeConfirmBtn ?? '?'}`
|
|
||||||
+ ` url=${decision.url || ''}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function shouldSkipWhatshubAuthActions(page, antiBot) {
|
|
||||||
const decision = await resolveWhatshubAuthSkipDecision(page, antiBot);
|
|
||||||
logWhatshubAuthSkipDecision(decision);
|
|
||||||
return decision.skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loading 结束后才会出现密码框或业务表格;先等二者之一再决定是否需要填密码
|
|
||||||
* @returns {Promise<boolean>} true=应跳过 authActions
|
|
||||||
*/
|
|
||||||
async function waitForWhatshubPasswordFormIfNeeded(page, antiBot) {
|
async function waitForWhatshubPasswordFormIfNeeded(page, antiBot) {
|
||||||
if (!antiBot || !(isWhatshubHost(page.url()) || page.url().includes('work-order-sharing'))) {
|
if (!antiBot || !(isWhatshubHost(page.url()) || page.url().includes('work-order-sharing'))) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
const initial = await resolveWhatshubAuthSkipDecision(page, antiBot);
|
if (await shouldSkipWhatshubAuthActions(page, antiBot)) {
|
||||||
logWhatshubAuthSkipDecision({ ...initial, reason: `pre_wait_${initial.reason}` });
|
return;
|
||||||
if (initial.skip) {
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeout = resolveAuthSelectorTimeoutMs(antiBot);
|
const timeout = resolveAuthSelectorTimeoutMs(antiBot);
|
||||||
const surfaceTimeout = Math.min(timeout, 10000);
|
console.log('[Whatshub] 等待 vxe 密码表单出现...');
|
||||||
console.log('[Whatshub] 等待密码框或业务表格渲染(Loading 结束后)...');
|
await page.waitForSelector('.vxe-form .el-input__inner', { visible: true, timeout }).catch(() => null);
|
||||||
await page.waitForFunction(
|
|
||||||
() => {
|
|
||||||
const isVisible = (el) => {
|
|
||||||
if (!el) return false;
|
|
||||||
const rect = el.getBoundingClientRect();
|
|
||||||
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
||||||
const style = window.getComputedStyle(el);
|
|
||||||
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
||||||
};
|
|
||||||
if (document.querySelector('.vxe-table, .vxe-grid')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const roots = document.querySelectorAll(
|
|
||||||
'form.vxe-form, .vxe-modal--wrapper, .vxe-modal, .el-dialog, .el-overlay-dialog'
|
|
||||||
);
|
|
||||||
for (const root of roots) {
|
|
||||||
const pwd = root.querySelector('.el-input__inner[placeholder*="密码"], .el-input__inner[maxlength="8"]');
|
|
||||||
const confirm = root.querySelector(
|
|
||||||
'.vxe-button-group button.theme--primary[type="submit"], button.theme--primary[type="submit"]'
|
|
||||||
);
|
|
||||||
if (isVisible(pwd) && isVisible(confirm)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
{ timeout: surfaceTimeout, polling: 200 }
|
|
||||||
).catch(() => null);
|
|
||||||
|
|
||||||
const afterSurface = await resolveWhatshubAuthSkipDecision(page, antiBot);
|
|
||||||
logWhatshubAuthSkipDecision({ ...afterSurface, reason: `after_surface_${afterSurface.reason}` });
|
|
||||||
if (afterSurface.skip) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[Whatshub] 等待 vxe 密码表单出现(password input + confirm)...');
|
|
||||||
await page.waitForSelector(WHATSHUB_PASSWORD_INPUT_SEL, { visible: true, timeout }).catch(() => null);
|
|
||||||
await page.waitForSelector(WHATSHUB_PASSWORD_CONFIRM_SEL, { visible: true, timeout }).catch(() => null);
|
|
||||||
|
|
||||||
const afterWait = await resolveWhatshubAuthSkipDecision(page, antiBot);
|
|
||||||
logWhatshubAuthSkipDecision({ ...afterWait, reason: `after_password_wait_${afterWait.reason}` });
|
|
||||||
return afterWait.skip;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function executeAuthActions(page, authActions, antiBot = null) {
|
async function executeAuthActions(page, authActions, antiBot = null) {
|
||||||
if (!Array.isArray(authActions)) {
|
if (!Array.isArray(authActions)) return;
|
||||||
return { skipped: false, ran: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await shouldSkipWhatshubAuthActions(page, antiBot)) {
|
if (await shouldSkipWhatshubAuthActions(page, antiBot)) {
|
||||||
console.log('[Whatshub] Session 已登录且无密码弹窗,跳过 authActions');
|
console.log('[Whatshub] Session 已登录且无密码弹窗,跳过 authActions');
|
||||||
return { skipped: true, ran: false };
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const skipAfterWait = await waitForWhatshubPasswordFormIfNeeded(page, antiBot);
|
await waitForWhatshubPasswordFormIfNeeded(page, antiBot);
|
||||||
if (skipAfterWait) {
|
|
||||||
console.log('[Whatshub] 密码等待后复检:业务页已就绪,跳过 authActions');
|
|
||||||
return { skipped: true, ran: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectorTimeout = resolveAuthSelectorTimeoutMs(antiBot);
|
const selectorTimeout = resolveAuthSelectorTimeoutMs(antiBot);
|
||||||
|
|
||||||
@@ -1859,78 +1671,6 @@ async function executeAuthActions(page, authActions, antiBot = null) {
|
|||||||
}, action.selector, action.text);
|
}, action.selector, action.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { skipped: false, ran: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 是否 statistics-only 拦截(Whatshub 完成量) */
|
|
||||||
function isStatisticsOnlyApiUrls(apiUrls) {
|
|
||||||
if (!Array.isArray(apiUrls) || apiUrls.length === 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return apiUrls.every((u) => String(u).includes('/open/statistics'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function areAllApisIntercepted(interceptor, apiUrls) {
|
|
||||||
if (!interceptor || !Array.isArray(apiUrls)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return apiUrls.every((api) => !!interceptor.interceptedApis[api]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createApiInterceptorHandle() {
|
|
||||||
return { interceptor: null, boundPage: null, cleanup: null };
|
|
||||||
}
|
|
||||||
|
|
||||||
function attachApiInterceptorToPage(handle, page, apiUrls, timeoutMs, label = '') {
|
|
||||||
if (handle.interceptor && handle.boundPage === page) {
|
|
||||||
return handle.interceptor;
|
|
||||||
}
|
|
||||||
if (handle.cleanup) {
|
|
||||||
handle.cleanup();
|
|
||||||
handle.cleanup = null;
|
|
||||||
}
|
|
||||||
handle.interceptor = createApiInterceptor(page, apiUrls, timeoutMs);
|
|
||||||
handle.boundPage = page;
|
|
||||||
handle.cleanup = handle.interceptor.cleanup;
|
|
||||||
const tag = label ? ` (${label})` : '';
|
|
||||||
console.log(`[API] 拦截器已挂载${tag} apis=${apiUrls.join(',')} url=${page.url()}`);
|
|
||||||
return handle.interceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ensureWhatshubStatisticsAfterAuthSkip(page, interceptor, apiUrls, authSkipped, interceptTimeout) {
|
|
||||||
if (!authSkipped || !isStatisticsOnlyApiUrls(apiUrls)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (areAllApisIntercepted(interceptor, apiUrls)) {
|
|
||||||
console.log('[Whatshub] statistics 已在页面加载时捕获');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
'[Whatshub] auth 已跳过但 statistics 未捕获'
|
|
||||||
+ '(可能 CF 换页后漏包或 sid 直进业务页时 pre-auth 未等待),reload 补触发'
|
|
||||||
);
|
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
||||||
if (areAllApisIntercepted(interceptor, apiUrls)) {
|
|
||||||
console.log('[Whatshub] statistics 延迟响应已捕获');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const reloadTimeout = Math.min(60000, interceptTimeout);
|
|
||||||
try {
|
|
||||||
await page.reload({ waitUntil: 'domcontentloaded', timeout: reloadTimeout });
|
|
||||||
await page.waitForSelector('.vxe-table, .vxe-grid', { timeout: 30000 }).catch(() => null);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
||||||
} catch (err) {
|
|
||||||
console.warn(`[Whatshub] reload 触发 statistics 失败: ${err.message}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (areAllApisIntercepted(interceptor, apiUrls)) {
|
|
||||||
console.log('[Whatshub] reload 后 statistics 已捕获');
|
|
||||||
} else {
|
|
||||||
console.warn('[Whatshub] reload 后 statistics 仍未捕获,继续 waitForApis');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createApiInterceptor(page, apiUrls, defaultTimeoutMs = API_INTERCEPT_TIMEOUT_MS) {
|
function createApiInterceptor(page, apiUrls, defaultTimeoutMs = API_INTERCEPT_TIMEOUT_MS) {
|
||||||
@@ -2188,13 +1928,12 @@ app.post('/api/auth-and-intercept', async (req, res) => {
|
|||||||
|
|
||||||
await prepareWhatshubShortLinkBeforeNav(page, navigationUrl, antiBot, storedSession);
|
await prepareWhatshubShortLinkBeforeNav(page, navigationUrl, antiBot, storedSession);
|
||||||
|
|
||||||
const apiHandle = createApiInterceptorHandle();
|
|
||||||
let interceptor = null;
|
let interceptor = null;
|
||||||
const useEarlyIntercept = shouldUseEarlyApiIntercept(antiBot, apiUrls);
|
const useEarlyIntercept = shouldUseEarlyApiIntercept(antiBot, apiUrls);
|
||||||
if (useEarlyIntercept) {
|
if (useEarlyIntercept) {
|
||||||
interceptor = attachApiInterceptorToPage(
|
interceptor = createApiInterceptor(page, apiUrls, interceptTimeout);
|
||||||
apiHandle, page, apiUrls, interceptTimeout, 'pre-nav'
|
interceptorCleanup = interceptor.cleanup;
|
||||||
);
|
console.log('[Whatshub] statistics 早挂 API 拦截器(session 复用防漏包)');
|
||||||
}
|
}
|
||||||
|
|
||||||
await navigateToPage(page, navigationUrl);
|
await navigateToPage(page, navigationUrl);
|
||||||
@@ -2222,12 +1961,6 @@ app.post('/api/auth-and-intercept', async (req, res) => {
|
|||||||
browserSession = browserCtx.browserSession;
|
browserSession = browserCtx.browserSession;
|
||||||
page = browserCtx.page;
|
page = browserCtx.page;
|
||||||
|
|
||||||
if (useEarlyIntercept) {
|
|
||||||
interceptor = attachApiInterceptorToPage(
|
|
||||||
apiHandle, page, apiUrls, interceptTimeout, 'post-cf-proxy'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (antiBot.enabled) {
|
if (antiBot.enabled) {
|
||||||
const cfResult = await runCloudflareWithBusinessGuard(
|
const cfResult = await runCloudflareWithBusinessGuard(
|
||||||
page, antiBot, waitForUrlSettled, storedSession, pageUrl, browserCtx
|
page, antiBot, waitForUrlSettled, storedSession, pageUrl, browserCtx
|
||||||
@@ -2265,37 +1998,14 @@ app.post('/api/auth-and-intercept', async (req, res) => {
|
|||||||
await seedShareTokenCookie(page, finalPageUrl);
|
await seedShareTokenCookie(page, finalPageUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useEarlyIntercept) {
|
if (!interceptor) {
|
||||||
interceptor = attachApiInterceptorToPage(
|
interceptor = createApiInterceptor(page, apiUrls, interceptTimeout);
|
||||||
apiHandle, page, apiUrls, interceptTimeout, 'post-cf-ready'
|
interceptorCleanup = interceptor.cleanup;
|
||||||
);
|
|
||||||
} else {
|
|
||||||
interceptor = attachApiInterceptorToPage(
|
|
||||||
apiHandle, page, apiUrls, interceptTimeout, 'pre-auth'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
interceptorCleanup = apiHandle.cleanup;
|
|
||||||
|
|
||||||
await attachHttpIpRewriteInterceptor(page, 'auth-and-intercept', { shareToken });
|
await attachHttpIpRewriteInterceptor(page, 'auth-and-intercept', { shareToken });
|
||||||
|
|
||||||
const authResult = await executeAuthActionsWithDiagnostics(page, authActions, antiBot);
|
await executeAuthActionsWithDiagnostics(page, authActions, antiBot);
|
||||||
await ensureWhatshubStatisticsAfterAuthSkip(
|
|
||||||
page,
|
|
||||||
interceptor,
|
|
||||||
apiUrls,
|
|
||||||
!!authResult?.skipped,
|
|
||||||
interceptTimeout
|
|
||||||
);
|
|
||||||
|
|
||||||
const capturedBeforeWait = Object.keys(interceptor.interceptedApis).join(',') || 'none';
|
|
||||||
console.log(
|
|
||||||
`[API] 等待 intercept apis=${apiUrls.join(',')} timeout=${interceptTimeout}ms`
|
|
||||||
+ ` already=${capturedBeforeWait}`
|
|
||||||
);
|
|
||||||
await interceptor.waitForApis(interceptTimeout);
|
await interceptor.waitForApis(interceptTimeout);
|
||||||
console.log(
|
|
||||||
`[API] intercept 完成 captured=${Object.keys(interceptor.interceptedApis).join(',') || 'none'}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const rawCookies = await page.cookies();
|
const rawCookies = await page.cookies();
|
||||||
const cookiePayload = rawCookies.map((c) => ({
|
const cookiePayload = rawCookies.map((c) => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user