123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- const ProductApiClient = require("../src/services/productApiClient");
- const axios = require("axios");
-
- // 本地服务端实例
- const localClient = new ProductApiClient({
- // 根据实际部署环境修改baseURL
- baseURL: "http://localhost:8991",
- });
-
- // 外网服务端实例
- const serverClient = {
- baseURL: "http://192.168.1.107:8080",
- timeout: 10000 * 30, // 30秒
- params: {
- pageNum: 1,
- pageSize: 500,
- },
- };
-
- axios.defaults.baseURL = serverClient.baseURL;
- axios.defaults.timeout = serverClient.timeout;
-
- // 获取商品列表和抓取配置的执行频率
- const frequency = 1000 * 60 * 60 * 24; // 24小时
-
- // 设置抓取配置
- const config = {
- platform: "amazon", // 平台
- needScreenshot: true, // 是否需要截图
- warnTimeRange: 2, // 监控频率(小时)
- goodsList: [], // 商品列表
- isRunning: false, // 是否正在执行抓取任务
- timer: null, // 定时器
- };
-
- /**
- * 获取商品信息
- * @param {Object} goods - 商品对象
- * @param {boolean} isRetry - 是否为重试操作
- * @returns {Promise<Object|null>} - 返回商品信息或null
- */
- async function fetchProductInfo(goods, isRetry = false) {
- try {
- console.log(`${isRetry ? "重试" : "开始"}抓取商品: ${goods.goodsSkuSn}`);
- const productInfo = await localClient.getProductInfo({
- url: goods.goodsSkuUrl,
- platform: goods.platform,
- needScreenshot: config.needScreenshot,
- });
- console.log(
- `${isRetry ? "重试" : "商品"} 抓取成功: ${goods.goodsSkuSn} - ${new Date().toLocaleString()}`
- );
- console.log(productInfo);
- return productInfo;
- } catch (error) {
- console.error(
- `抓取失败: ${goods.goodsSkuSn} - ${new Date().toLocaleString()}`,
- error.message
- );
- return null;
- }
- }
-
- /**
- * 保存商品信息到服务器
- * @param {Object} goods - 商品对象
- * @param {Object} productInfo - 抓取到的商品信息
- * @returns {Promise<boolean>} - 是否保存成功
- */
- async function saveProductInfo(goods, productInfo) {
- try {
- console.log(
- `开始保存商品信息: ${goods.goodsSkuSn} - ${new Date().toLocaleString()}`
- );
- const { title, price, sku, remark, screenshotUrl } = productInfo[0];
- const res = await axios.post(
- serverClient.baseURL +
- "/system/operationWarnresult/receiveLatestGoodsInfo",
- {
- title,
- price: price.toString(),
- sku,
- url: goods.goodsSkuUrl,
- remark,
- screenshotUrl: screenshotUrl,
- }
- );
- console.log(res.data);
- return true;
- } catch (saveError) {
- console.error(
- `商品信息保存失败: ${goods.goodsSkuSn} - ${new Date().toLocaleString()}`,
- saveError.message
- );
- return false;
- }
- }
-
- /**
- * 处理单个商品的抓取和保存
- * @param {Object} goods - 商品对象
- * @returns {Promise<void>}
- */
- async function processProduct(goods) {
- // 第一次尝试抓取
- let productInfo = await fetchProductInfo(goods);
-
- // 如果第一次抓取成功,保存结果
- if (productInfo) {
- await saveProductInfo(goods, productInfo);
- return;
- }
-
- // 第一次失败,进行重试
- productInfo = await fetchProductInfo(goods, true);
-
- // 如果重试成功,保存结果
- if (productInfo) {
- await saveProductInfo(goods, productInfo);
- }
- // 重试失败,跳过该商品
- }
-
- /**
- * 获取抓取配置
- * @returns {Promise<void>}
- */
- async function fetchConfig() {
- try {
- console.log(`开始获取抓取配置: ${new Date().toLocaleString()}`);
- const res = await axios.get(serverClient.baseURL + "/system/operationWarnconfig/noVerifyList", {
- params: serverClient.params,
- });
- console.log(res.data);
- const { rows } = res.data;
- if (rows.length > 0) {
- config.warnTimeRange = rows[0].warnTimeRange;
- } else {
- config.warnTimeRange = 2; // 默认2小时
- }
- console.log(`抓取频率设置为 ${config.warnTimeRange} 小时`);
- return true;
- } catch (error) {
- console.error(`获取抓取配置失败: ${new Date().toLocaleString()}`, error.message);
- return false;
- }
- }
-
- /**
- * 获取商品列表并处理
- * @returns {Promise<void>}
- */
- async function fetchGoodsListAndProcess() {
- if (config.isRunning) {
- console.log(`上一次任务尚未完成,跳过本次执行: ${new Date().toLocaleString()}`);
- return;
- }
-
- config.isRunning = true;
- console.log(`开始执行抓取任务: ${new Date().toLocaleString()}`);
-
- try {
- const res = await axios.get(serverClient.baseURL + "/system/operationGoods/noVerifyList", {
- params: {
- ...serverClient.params,
- isDisabled: 1,
- },
- });
- console.log(res.data);
- const { rows } = res.data;
- config.goodsList = rows;
-
- // 使用for...of循环按顺序处理每个商品
- for (const goods of config.goodsList) {
- await processProduct(goods);
- }
-
- console.log("所有商品抓取完成", new Date().toLocaleString());
- } catch (error) {
- console.error(`获取商品列表失败: ${new Date().toLocaleString()}`, error.message);
- } finally {
- config.isRunning = false;
- }
- }
-
- /**
- * 启动定时任务
- */
- async function startScheduler() {
- // 先获取配置
- await fetchConfig();
-
- // 立即执行一次
- await fetchGoodsListAndProcess();
-
- // 清除之前的定时器(如果存在)
- if (config.timer) {
- clearInterval(config.timer);
- }
-
- // 设置定时器,根据warnTimeRange的小时数定时执行
- const intervalMs = config.warnTimeRange * 60 * 60 * 1000; // 转换为毫秒
- console.log(`设置定时任务,每 ${config.warnTimeRange} 小时执行一次,下次执行时间: ${new Date(Date.now() + intervalMs).toLocaleString()}`);
-
- config.timer = setInterval(async () => {
- console.log(`定时任务触发: ${new Date().toLocaleString()}`);
- // 重新获取配置(频率可能会改变)
- await fetchConfig();
- // 执行抓取处理
- await fetchGoodsListAndProcess();
-
- // 如果warnTimeRange发生变化,重新设置定时器
- const newIntervalMs = config.warnTimeRange * 60 * 60 * 1000;
- if (newIntervalMs !== intervalMs) {
- console.log(`监控频率已变更为 ${config.warnTimeRange} 小时,重新设置定时器`);
- clearInterval(config.timer);
- startScheduler(); // 重新启动调度器
- }
- }, intervalMs);
-
- // 添加防止程序崩溃的错误处理
- process.on('uncaughtException', (error) => {
- console.error(`未捕获的异常: ${new Date().toLocaleString()}`, error);
- // 尝试继续执行定时任务
- if (!config.timer) {
- startScheduler();
- }
- });
- }
-
- // 启动调度器
- startScheduler();
-
- // 输出启动信息
- console.log(`抓取服务已启动: ${new Date().toLocaleString()}`);
- console.log(`初始监控频率: ${config.warnTimeRange} 小时`);
|