File size: 2,794 Bytes
ea67eaf
 
ec4bf22
 
 
ea67eaf
 
 
69b3255
ea67eaf
4164c72
ea67eaf
 
4164c72
ea67eaf
ec4bf22
ea67eaf
 
4164c72
ea67eaf
4164c72
ec4bf22
 
4164c72
ea67eaf
 
 
 
 
 
 
 
 
 
4164c72
ea67eaf
4164c72
ea67eaf
 
 
4164c72
ea67eaf
 
7668e81
4164c72
 
7668e81
4164c72
 
 
 
 
ea67eaf
 
 
 
 
 
 
 
4164c72
7668e81
4164c72
 
7668e81
4164c72
 
 
7668e81
ea67eaf
7668e81
 
4164c72
ea67eaf
 
 
7668e81
ea67eaf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4164c72
 
 
 
ea67eaf
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import express from 'express';
import cors from 'cors';
import { runOttoCrawler } from './src/otto-crawler.js';
import { runAmazonCrawler } from './src/amazon-crawler.js';
import { ProductData } from './src/productData.js';
import { log } from 'crawlee';

const app = express();
const PORT = process.env.PORT || 7860;

// ==================== 爬虫映射表 ====================

/**
 * 支持的爬虫源类型
 */
type CrawlerPlatform = 'Otto' | 'Amazon';

/**
 * 爬虫函数映射表
 */
const crawlerMap: Record<CrawlerPlatform, (urls: string[], options?: any) => Promise<ProductData[]>> = {
  'Otto': runOttoCrawler,
  'Amazon': runAmazonCrawler
};

// ==================== Express 中间件配置 ====================

app.use(cors());
app.use(express.json({ limit: '10mb' }));

// 1. 健康检查接口
app.get('/health', (req, res) => {
  res.json({ 
    status: 'ok', 
    service: 'smart-search-crawler',
    timestamp: new Date().toISOString(),
    supportedPlatforms: Object.keys(crawlerMap)
  });
});

// 2. 执行爬取任务接口
app.post('/crawl', async (req, res) => {
  try {
    const { platform, urls, preset = 'stable' } = req.body;

    // 参数验证
    if (!platform || typeof platform !== 'string') {
      return res.status(400).json({ 
        success: false, 
        error: '请提供有效的 platform 参数 (例如: "Otto")' 
      });
    }

    if (!urls || !Array.isArray(urls) || urls.length === 0) {
      return res.status(400).json({ 
        success: false, 
        error: '请提供有效的 URL 数组 (urls)' 
      });
    }

    // 检查是否支持该源
    if (!(platform in crawlerMap)) {
      return res.status(400).json({ 
        success: false, 
        error: `不支持的爬虫源: ${platform}。支持的源: ${Object.keys(crawlerMap).join(', ')}` 
      });
    }

    log.info(`[API] 收到爬取请求: platform=${platform}, ${urls.length} 个 URL, preset=${preset}`);

    // 根据 platform 选择对应的爬虫执行
    const crawler = crawlerMap[platform as CrawlerPlatform];
    const results: ProductData[] = await crawler(urls, { preset });

    res.json({
      success: true,
      platform: platform,
      count: results.length,
      data: results
    });

  } catch (error: any) {
    log.error('[API] 爬取任务执行失败:', error.message);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

// 启动服务
app.listen(PORT, () => {
  console.log(`\n🚀 Smart Search Crawler API is running on http://localhost:${PORT}`);
  console.log(`   - Health:  GET  http://localhost:${PORT}/health`);
  console.log(`   - Crawl:   POST http://localhost:${PORT}/crawl`);
  console.log(`   - Supported Platforms: ${Object.keys(crawlerMap).join(', ')}`);
  console.log('');
});