添加whatshub工单

This commit is contained in:
root
2026-06-20 04:47:34 +08:00
parent a6c87e8e25
commit d5a0ffa6db
271 changed files with 9377 additions and 303 deletions
Regular → Executable
View File
+10 -3
View File
@@ -107,6 +107,11 @@ abstract class AbstractScrmSpider
if ($detailApi) { $apiUrlsToIntercept[] = $detailApi; }
if ($countApi) { $apiUrlsToIntercept[] = $countApi; }
// var_dump($apiUrlsToIntercept);
// dump([
// 'pageUrl' => $config['pageUrl'],
// 'apiUrls' => $apiUrlsToIntercept,
// 'authActions' => $config['authActions']
// ]);
// 【阶段一】:初始化并首屏拦截
$initResult = $this->requestNode('/api/auth-and-intercept', [
'pageUrl' => $config['pageUrl'],
@@ -120,7 +125,8 @@ abstract class AbstractScrmSpider
$interceptedApis = $initResult['interceptedApis'];
$cookies = $initResult['cookies'];
// dd($interceptedApis);
$finalPageUrl = $initResult['finalPageUrl'] ?? $config['pageUrl'];
// 必须拦截到 List 接口,否则无法继续
if (!isset($interceptedApis[$listApi])) {
throw new Exception("致命错误:未能拦截到必须的列表接口 [{$listApi}]");
@@ -133,7 +139,7 @@ abstract class AbstractScrmSpider
// dd($countData);
$listApiNode = $interceptedApis[$listApi];
$allListPagesData = [$listApiNode['data']]; // 初始化列表容器,装入第一页数据
// dd($allListPagesData);exit;
$totalPages = $this->extractListTotalPages($listApiNode['data'], $countData);
$mode = $config['paginationMode'] ?? self::MODE_FETCH;
@@ -163,7 +169,7 @@ abstract class AbstractScrmSpider
if ($pResult['success']) $allListPagesData[] = $pResult['data'];
}
}
}
}
// 策略 2:强制 UI 点击
elseif ($mode === self::MODE_UI) {
$uiConfig = $this->getUiPaginationConfig();
@@ -176,6 +182,7 @@ abstract class AbstractScrmSpider
$uiResult = $this->requestNode('/api/ui-pagination', [
'apiUrl' => $listApi,
'pageUrl' => $config['pageUrl'],
'finalPageUrl' => $finalPageUrl,
'nextBtnSelector' => $uiConfig['nextBtnSelector'],
'waitMs' => $uiConfig['waitMs'] ?? 2000,
'clicksToPerform' => $clicksToPerform,
+99
View File
@@ -0,0 +1,99 @@
<?php
// Chatknow SCRM工单
require_once __DIR__ . '/AbstractScrmSpider.class.php';
class Chatknow extends AbstractScrmSpider
{
const API_LIST = '/user/user/UserInfoChildChannel/list'; // 列表API地址
const API_DETAILS = ''; // 详情API地址
const API_COUNT = ''; // 总数API地址
const DEFAULT_PER_PAGE_COUNT = 10; // List默认每页显示的数量
private $pageUrl;
private $account;
private $password;
private $unifiedData;
// 实例化时动态传入账号和密码
public function __construct($pageUrl, $account, $password, $nodeHost = 'http://127.0.0.1:3001')
{
parent::__construct($nodeHost);
$this->account = $account;
$this->password = $password;
$this->pageUrl = $pageUrl;
$this->unifiedData = new UnifiedScrmData();
}
protected function getSpiderConfig()
{
return [
'pageUrl' => $this->pageUrl,
'apiUrls' => [self::API_LIST],
'listApi' => self::API_LIST, // 必须,第一页的列表数据
// 'detailApi' => self::API_DETAILS, // 选填
// 'countApi' => self::API_COUNT,
'listMethod' => 'GET',
'paginationMode' => self::MODE_UI,
'authActions' => [
// ['type' => 'vue_select', 'selector' => 'input[type="password"]', 'value' => $this->password],
// ['type' => 'type', 'selector' => '#username_input', 'value' => $this->account],
// ['type' => 'vue_click', 'selector' => '.layui-btn', 'text' => '搜索'],
['type' => 'wait', 'ms' => 4000]
]
];
}
// 只负责解析 List 的总页数
protected function extractListTotalPages($listFirstPageData, $countData = null)
{
$default_per_page_count = self::DEFAULT_PER_PAGE_COUNT;
$this->unifiedData->total = $listFirstPageData['total'];
$this->unifiedData->todayNewCount = $listFirstPageData['data']['today_num'];
if($listFirstPageData['total'] <= $default_per_page_count) {
return 1;
}
return ceil($listFirstPageData['total']/$default_per_page_count);
}
// 只负责组装 List 的翻页参数
protected function buildListPageParams($page)
{
return ['page' => $page, 'limit' => self::DEFAULT_PER_PAGE_COUNT];
}
// 提供 List 的下一页按钮信息
protected function getUiPaginationConfig()
{
return [
'nextBtnSelector' => '.tabs-content .arco-pagination-item-next',
'waitMs' => 2000
];
}
// 清爽至极的数据清洗:详情是详情,列表是列表
protected function parseToUnifiedData($detailData, $allListPagesData)
{
$unifiedData = $this->unifiedData;
// 循环合并了所有页数的 List 数组
foreach ($allListPagesData as $pageRaw) {
$records = $pageRaw['rows'] ?? [];
foreach ($records as $item) {
if(!empty($item['username'])) {
$number = $item['username'] ?? null;
$isOnline = (isset($item['state']) && $item['state'] == 1);
$unifiedData->addNumber($number, $isOnline, $item['today_num']);
}
}
}
return $unifiedData;
}
}
Regular → Executable
View File
Regular → Executable
View File
Regular → Executable
View File
View File
+124
View File
@@ -0,0 +1,124 @@
<?php
// Whatshub 工单平台
require_once __DIR__ . '/AbstractScrmSpider.class.php';
class Whatshub extends AbstractScrmSpider
{
const API_LIST = '/api/whatshub-counter/workShare/open/detail'; // 列表API地址
const API_DETAILS = '/api/whatshub-counter/workShare/open/statistics'; // 详情API地址
const API_COUNT = ''; // 总数API地址
const DEFAULT_PER_PAGE_COUNT = 20; // List默认每页显示的数量
private $pageUrl;
private $account;
private $password;
private $unifiedData;
// 实例化时动态传入账号和密码
public function __construct($pageUrl, $account, $password, $nodeHost = 'http://127.0.0.1:3001')
{
parent::__construct($nodeHost);
$this->account = $account;
$this->password = $password;
$this->pageUrl = $pageUrl;
$this->unifiedData = new UnifiedScrmData();
}
protected function getSpiderConfig()
{
$host = (string) parse_url($this->pageUrl, PHP_URL_HOST);
return [
'pageUrl' => $this->pageUrl,
'apiUrls' => [self::API_LIST, self::API_DETAILS],
// 明确指派角色
'listApi' => self::API_LIST, // 必须
'listMethod' => 'POST',
'paginationMode' => self::MODE_UI,
'authActions' => [
// 1. 填入密码:寻找 class 包含 el-message-box__input 下面的任意 input
// Node.js 会自动扫描所有匹配项,并只把密码强行注入到那个“肉眼可见”的框里
['type' => 'vue_fill', 'selector' => '.el-input__inner', 'value' => $this->password],
// 2. 停顿 500ms,让 Vue 绑定的 v-model 彻底反应过来
['type' => 'wait', 'ms' => 500],
// 3. 点击确认:寻找 MessageBox 底部的蓝色 primary 确认按钮
// 同样利用 vue_click 的可见性过滤,无视隐藏的旧弹窗按钮
['type' => 'vue_click', 'selector' => '.vxe-button-group .theme--primary'],
// 4. 等待弹窗淡出,接口开始请求
['type' => 'wait', 'ms' => 2200]
],
// Whatshub 专用:Real Browser + Turnstile + Captcha API 兜底 + 会话复用
'antiBot' => [
'enabled' => true,
'profile' => 'real',
'turnstile' => true,
'solverFallback' => true,
'sessionKey' => 'whatshub:' . $host,
'challengeTimeoutMs' => 60000,
],
];
}
// 只负责解析 List 的总页数
protected function extractListTotalPages($listFirstPageData, $countData = null)
{
$default_per_page_count = self::DEFAULT_PER_PAGE_COUNT;
$this->unifiedData->total = $listFirstPageData['data']['total'];
if($this->unifiedData->total <= $default_per_page_count) {
return 1;
}
return ceil($this->unifiedData->total/$default_per_page_count);
}
// 没有分页返回空数组
protected function buildListPageParams($page)
{
return ['pageNum' => $page, 'pageSize' => self::DEFAULT_PER_PAGE_COUNT];
}
// 提供 List 的下一页按钮信息
protected function getUiPaginationConfig()
{
return [
'nextBtnSelector' => '.vxe-pager--next-btn',
'waitMs' => 1500
];
}
// 清爽至极的数据清洗:详情是详情,列表是列表
protected function parseToUnifiedData($detailData, $allListPagesData)
{
$unifiedData = $this->unifiedData;
// 1. 如果捕获到了详情数据,提取今日新增
if ($detailData) {
$unifiedData->todayNewCount = (int)($detailData['data']['dayNewFans'] ?? 0);
}
// 2. 循环合并了所有页数的 List 数组
foreach ($allListPagesData as $pageRaw) {
$records = $pageRaw['data']['rows'] ?? [];
foreach ($records as $item) {
if(!empty($item['account'])) {
$number = $item['account'] ?? null;
$isOnline = (isset($item['isOnline']) && $item['isOnline'] == 1);
$unifiedData->addNumber($number, $isOnline, $item['dayNewFans']);
}
}
}
// 🚀 3. 终极统计:所有翻页数据均已入库,此时再统计真实的 Total 总数
$unifiedData->total = count($unifiedData->numbers);
return $unifiedData;
}
}
Regular → Executable
+9 -9
View File
@@ -5,10 +5,10 @@ require_once __DIR__ . '/AbstractScrmSpider.class.php';
class Xinghe extends AbstractScrmSpider
{
const API_LIST = '/share/share/api_yinliu_count.html'; // 列表API地址
const API_DETAILS = ''; // 详情API地址
const API_COUNT = ''; // 总数API地址
const DEFAULT_PER_PAGE_COUNT = 10; // List默认每页显示的数量
const API_LIST = '/share/share/api_yinliu_count.html'; // 列表API地址
const API_DETAILS = ''; // 详情API地址
const API_COUNT = ''; // 总数API地址
const DEFAULT_PER_PAGE_COUNT = 10; // List默认每页显示的数量
private $pageUrl;
private $account;
private $password;
@@ -29,7 +29,7 @@ class Xinghe extends AbstractScrmSpider
{
return [
'pageUrl' => $this->pageUrl,
'apiUrls' => [self::API_LIST . "?page=1&limit=10"],
'apiUrls' => [self::API_LIST . "?page=1&limit=10&is_repet=1"],
'listApi' => self::API_LIST, // 必须,第一页的列表数据
// 'detailApi' => self::API_DETAILS, // 选填
// 'countApi' => self::API_COUNT,
@@ -39,9 +39,9 @@ class Xinghe extends AbstractScrmSpider
'paginationMode' => self::MODE_FETCH,
'authActions' => [
// ['type' => 'type', 'selector' => 'input[type="password"]', 'value' => $this->password],
// ['type' => 'vue_select', 'selector' => 'input[type="password"]', 'value' => $this->password],
// ['type' => 'type', 'selector' => '#username_input', 'value' => $this->account],
// ['type' => 'press', 'key' => 'Enter'],
// ['type' => 'vue_click', 'selector' => '.layui-btn', 'text' => '搜索'],
['type' => 'wait', 'ms' => 2000]
]
@@ -53,7 +53,7 @@ class Xinghe extends AbstractScrmSpider
{
$default_per_page_count = self::DEFAULT_PER_PAGE_COUNT;
$this->unifiedData->total = $listFirstPageData['count'];
$this->unifiedData->todayNewCount = $listFirstPageData['totalRow']['day_sum'];
// $this->unifiedData->todayNewCount = $listFirstPageData['totalRow']['day_sum'];
if($listFirstPageData['count'] <= $default_per_page_count) {
return 1;
@@ -84,7 +84,7 @@ class Xinghe extends AbstractScrmSpider
// 循环合并了所有页数的 List 数组
foreach ($allListPagesData as $pageRaw) {
$records = $pageRaw['data'] ?? [];
$records = $pageRaw['data'] ?? [];
foreach ($records as $item) {
if(!empty($item['user'])) {
$number = $item['user'] ?? null;
+176
View File
@@ -0,0 +1,176 @@
<?php
require_once __DIR__ . '/UnifiedScrmData.class.php';
/**
* 数据爬虫类
* 用于处理需要先获取 Token 授权,再读取接口数据的场景
*/
class Xinghe
{
private $cookieFile;
private $ch; // cURL 句柄
private $pageUrl;
private $account;
private $password;
private $unifiedData;
private $baseUrl;
/**
* 构造函数:初始化 cURL 和 Cookie 文件
*/
public function __construct($pageUrl, $username, $password)
{
$this->pageUrl = $pageUrl;
$this->username = $username;
$this->password = $password;
$parsedUrl = parse_url($pageUrl);
$scheme = isset($parsedUrl['scheme']) ? $parsedUrl['scheme'] . '://' : '';
$host = isset($parsedUrl['host']) ? $parsedUrl['host'] : '';
$baseUrl = $scheme . $host;
$this->baseUrl = $baseUrl;
$this->unifiedData = new UnifiedScrmData();
}
public function run()
{
// 1. 创建临时 Cookie 文件
$this->cookieFile = tempnam(sys_get_temp_dir(), 'spider_cookie_');
if ($this->cookieFile === false) {
throw new \RuntimeException("无法在系统临时目录创建 Cookie 文件");
}
// 2. 初始化 cURL 并设置全局参数
$this->ch = curl_init();
$apiUrl = '/share/share/api_yinliu_count.html?page=1&limit=10&id=&class_id=&is_repet=1&start_time=&end_time=';
$defaultOptions = [
CURLOPT_RETURNTRANSFER => true, // 将结果返回为字符串
CURLOPT_HEADER => false, // 不输出响应头
CURLOPT_TIMEOUT => 15, // 设置超时时间(秒)
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
// 核心优化:同时指定读写 Cookie 为同一个文件,cURL 会自动维护会话
CURLOPT_COOKIEJAR => $this->cookieFile,
CURLOPT_COOKIEFILE => $this->cookieFile,
];
curl_setopt_array($this->ch, $defaultOptions);
$this->authenticate();
$first_page_data = $this->fetchApiData($apiUrl); // 首页数据
$this->unifiedData->total = $first_page_data['count']; // 总在线人数
$this->unifiedData->todayNewCount = $first_page_data['totalRow']['day_sum']; // 今日新增在线人数
$total_pages = ceil($this->unifiedData->total/10); // 总页数
$allListPagesData = [$first_page_data['data']]; // 初始化列表容器,装入第一页数据
for ($page = 2; $page <= $total_pages; $page++) {
$apiUrl = '/share/share/api_yinliu_count.html?page=' . $page . '&limit=10&id=&class_id=&is_repet=1&start_time=&end_time=';
$page_data = $this->fetchApiData($apiUrl);
$allListPagesData[] = $page_data['data'];
}
return $this->parseToUnifiedData($first_page_data, $allListPagesData);
}
// 清爽至极的数据清洗:详情是详情,列表是列表
protected function parseToUnifiedData($detailData, $allListPagesData)
{
$unifiedData = $this->unifiedData;
// 循环合并了所有页数的 List 数组
foreach ($allListPagesData as $records) {
foreach ($records as $item) {
if(!empty($item['user'])) {
$number = $item['user'] ?? null;
$isOnline = (isset($item['online']) && $item['online'] == 1);
$unifiedData->addNumber($number, $isOnline, $item['day_sum']);
}
}
}
return $unifiedData;
}
/**
* 析构函数:释放资源,清理垃圾
*/
public function __destruct()
{
// 关闭 cURL 会话
if (is_resource($this->ch) || $this->ch instanceof \CurlHandle) {
curl_close($this->ch);
}
// 删除临时 Cookie 文件
if (file_exists($this->cookieFile)) {
unlink($this->cookieFile);
}
}
/**
* 第一步:访问授权页面,建立会话
*
* @param string $authUrl 包含 token 的授权地址
* @return bool 授权请求是否成功
* @throws \Exception
*/
public function authenticate()
{
$this->sendRequest($this->pageUrl);
return true; // 如果没有抛出异常,则认为请求成功
}
/**
* 第二步:请求 API 接口获取数据
*
* @param string $apiUrl 接口数据地址
* @return array|null 解析后的数组数据,如果解析失败返回 null
* @throws \Exception
*/
public function fetchApiData($apiUrl)
{
$response = $this->sendRequest($this->baseUrl . $apiUrl);
// 尝试解析 JSON 数据
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \RuntimeException("JSON 解析失败: " . json_last_error_msg() . "。原始响应: " . $response);
}
return $data;
}
/**
* 发送 cURL 请求的底层私有方法
*
* @param string $url 目标地址
* @return string 服务器响应内容
* @throws \Exception
*/
private function sendRequest($url)
{
curl_setopt($this->ch, CURLOPT_URL, $url);
$response = curl_exec($this->ch);
// 检查是否有网络或 cURL 底层错误
if ($response === false) {
$error = curl_error($this->ch);
throw new \RuntimeException("请求失败 [{$url}]: {$error}");
}
// 检查 HTTP 状态码
$httpCode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
if ($httpCode >= 400) {
throw new \RuntimeException("HTTP 请求异常 [{$url}],状态码: {$httpCode}");
}
return (string)$response;
}
}
Regular → Executable
+98 -28
View File
@@ -1,15 +1,86 @@
<?php
// 文件名: run.php
error_reporting(E_ALL);
ini_set('display_errors', 'ON');
require_once __DIR__ . '/A2c.php'; // A2c云控
require_once __DIR__ . '/Xinghe.php'; // 星河云控
// 文件名: 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__ . '/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://user.a2c.chat/visitors/counter/share?id=33e449dc83c24ee59275bf03a2d82234'; // PageUrl 入口授权页
// $pageUrl = 'https://yyk.ink/8415O53'; // PageUrl 入口授权页
// $username = ""; // 登录账号
// $password = ""; // 登录密码
// $spider = new A2c($pageUrl, $username, $password);
@@ -31,7 +102,7 @@ require_once __DIR__ . '/Haiwang.php'; // 海王
// try {
// echo "🚀 开始执行<星河云控>抓取任务 (多引擎智能调度)...\n\r";
// $pageUrl = 'http://103.251.112.35:10158/share/share/index.html?token=pds65jl202t2kjis5firb8epu4d8a83ptfhc63d89l3mv11nwa'; // PageUrl 入口授权页
// $pageUrl = 'http://8.218.14.51/share/share/index.html?token=hn6z3egq4nnnebkv4063pcdouzr4ug5js902mlqo2n3yp9gzhe'; // PageUrl 入口授权页
// $username = ""; // 登录账号
// $password = ""; // 登录密码
// $spider = new Xinghe($pageUrl, $username, $password);
@@ -46,16 +117,15 @@ require_once __DIR__ . '/Haiwang.php'; // 海王
// 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/ygn9zjr8'; // PageUrl 入口授权页
// $pageUrl = 'https://s.url99.me/68vfje8m'; // PageUrl 入口授权页
// $username = ""; // 登录账号
// $password = "123456"; // 登录密码
// $password = "542187"; // 登录密码
// $spider = new Huojian($pageUrl, $username, $password);
// $finalData = $spider->run();
@@ -96,27 +166,27 @@ require_once __DIR__ . '/Haiwang.php'; // 海王
// 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();
// 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);
// 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";
}
// } catch (Exception $e) {
// echo "🚨 抓取异常:" . $e->getMessage() . "\n\r";
// }
// try {
// echo "🚀 开始执行<CEO SCRM>抓取任务 (多引擎智能调度)...\n\r";