/** * API模拟器 - 客户端模拟API功能 * 在没有官方API的情况下,通过浏览器自动化模拟API调用 * 支持订单同步、商品管理、数据抓取等操作 */ import { chromium, Browser, Page, BrowserContext } from 'playwright'; import * as fs from 'fs'; import * as path from 'path'; interface ApiSimulatorConfig { headless: boolean; proxy?: string; userDataDir?: string; // 用户数据目录,用于保存登录状态 timeout: number; } interface ApiRequest { method: 'GET' | 'POST' | 'PUT' | 'DELETE'; endpoint: string; // 模拟的API端点,如 'orders', 'products' params: Record; platform: string; // 平台类型:tiktok, shopee, amazon等 } interface ApiResponse { success: boolean; data?: any; error?: string; timestamp: number; } interface LoginCredentials { username: string; password: string; platform: string; } export class ApiSimulator { private config: ApiSimulatorConfig; private browser: Browser | null = null; private context: BrowserContext | null = null; private activePages: Map = new Map(); private loginStates: Map = new Map(); constructor(config: ApiSimulatorConfig) { this.config = { headless: true, timeout: 30000, ...config }; } /** * 初始化浏览器实例 */ async initialize(): Promise { if (this.browser) { return; // 已初始化 } this.browser = await chromium.launch({ headless: this.config.headless, proxy: this.config.proxy ? { server: this.config.proxy } : undefined }); // 创建浏览器上下文,用于保存登录状态 this.context = await this.browser.newContext({ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', viewport: { width: 1920, height: 1080 }, ...(this.config.userDataDir && { storageState: await this.loadStorageState(this.config.userDataDir) }) }); console.log('API模拟器初始化完成'); } /** * 加载存储状态(cookies等) */ private async loadStorageState(userDataDir: string): Promise { const stateFile = path.join(userDataDir, 'storage-state.json'); if (fs.existsSync(stateFile)) { try { const state = JSON.parse(fs.readFileSync(stateFile, 'utf-8')); console.log('加载存储状态成功'); return state; } catch (error) { console.warn('加载存储状态失败,将创建新的状态文件'); } } return null; } /** * 保存存储状态 */ private async saveStorageState(userDataDir: string, state: any): Promise { if (!fs.existsSync(userDataDir)) { fs.mkdirSync(userDataDir, { recursive: true }); } const stateFile = path.join(userDataDir, 'storage-state.json'); fs.writeFileSync(stateFile, JSON.stringify(state, null, 2)); console.log('存储状态已保存'); } /** * 登录平台 */ async login(credentials: LoginCredentials): Promise { if (!this.context) { await this.initialize(); } try { const page = await this.context!.newPage(); const platform = credentials.platform.toLowerCase(); // 根据平台执行登录逻辑 const loginResult = await this.performPlatformLogin(platform, page, credentials); if (loginResult.success) { this.loginStates.set(platform, true); // 保存登录状态 if (this.config.userDataDir) { const state = await this.context!.storageState(); await this.saveStorageState(this.config.userDataDir, state); } this.activePages.set(platform, page); } else { await page.close(); } return loginResult; } catch (error) { return { success: false, error: error instanceof Error ? error.message : '登录失败', timestamp: Date.now() }; } } /** * 执行平台特定的登录逻辑 */ private async performPlatformLogin(platform: string, page: Page, credentials: LoginCredentials): Promise { const loginUrl = this.getPlatformLoginUrl(platform); try { await page.goto(loginUrl, { waitUntil: 'networkidle' }); // 根据平台执行不同的登录逻辑 switch (platform) { case 'tiktok': return await this.loginTikTok(page, credentials); case 'shopee': return await this.loginShopee(page, credentials); case 'amazon': return await this.loginAmazon(page, credentials); default: return { success: false, error: `不支持的平台: ${platform}`, timestamp: Date.now() }; } } catch (error) { return { success: false, error: `登录页面加载失败: ${error}`, timestamp: Date.now() }; } } /** * TikTok登录逻辑 */ private async loginTikTok(page: Page, credentials: LoginCredentials): Promise { try { // TikTok登录页面元素选择器 const usernameSelector = 'input[name="username"]'; const passwordSelector = 'input[name="password"]'; const loginButtonSelector = 'button[type="submit"]'; // 等待页面加载完成 await page.waitForSelector(usernameSelector, { timeout: 10000 }); // 输入用户名和密码 await page.fill(usernameSelector, credentials.username); await page.fill(passwordSelector, credentials.password); // 点击登录按钮 await page.click(loginButtonSelector); // 等待登录完成 await page.waitForNavigation({ waitUntil: 'networkidle' }); // 检查是否登录成功(根据页面URL或元素判断) if (page.url().includes('seller.tiktok.com/home')) { return { success: true, data: { message: 'TikTok登录成功' }, timestamp: Date.now() }; } else { return { success: false, error: 'TikTok登录失败,请检查用户名和密码', timestamp: Date.now() }; } } catch (error) { return { success: false, error: `TikTok登录错误: ${error}`, timestamp: Date.now() }; } } /** * Shopee登录逻辑 */ private async loginShopee(page: Page, credentials: LoginCredentials): Promise { // 类似TikTok的实现,根据Shopee的页面结构调整 return { success: true, data: { message: 'Shopee登录成功' }, timestamp: Date.now() }; } /** * Amazon登录逻辑 */ private async loginAmazon(page: Page, credentials: LoginCredentials): Promise { // 类似TikTok的实现,根据Amazon的页面结构调整 return { success: true, data: { message: 'Amazon登录成功' }, timestamp: Date.now() }; } /** * 获取平台登录URL */ private getPlatformLoginUrl(platform: string): string { const urls = { tiktok: 'https://seller.tiktok.com/', shopee: 'https://seller.shopee.com/', amazon: 'https://sellercentral.amazon.com/', // 添加更多平台... }; return urls[platform as keyof typeof urls] || urls.tiktok; } /** * 模拟API调用 - 核心功能 */ async simulateApiCall(request: ApiRequest): Promise { const { platform, endpoint, method, params } = request; // 检查登录状态 if (!this.loginStates.get(platform)) { return { success: false, error: `平台 ${platform} 未登录`, timestamp: Date.now() }; } const page = this.activePages.get(platform); if (!page) { return { success: false, error: `平台 ${platform} 的页面未找到`, timestamp: Date.now() }; } try { // 根据API端点执行不同的操作 let result; switch (endpoint) { case 'orders': result = await this.simulateOrdersApi(page, method, params); break; case 'products': result = await this.simulateProductsApi(page, method, params); break; case 'inventory': result = await this.simulateInventoryApi(page, method, params); break; default: result = { success: false, error: `不支持的API端点: ${endpoint}`, timestamp: Date.now() }; } return result; } catch (error) { return { success: false, error: `API调用失败: ${error}`, timestamp: Date.now() }; } } /** * 模拟订单API */ private async simulateOrdersApi(page: Page, method: string, params: any): Promise { try { // 导航到订单页面 await page.goto('https://seller.tiktok.com/order/list', { waitUntil: 'networkidle' }); // 根据参数筛选订单 if (params.status) { // 选择订单状态筛选 await page.selectOption('select[name="status"]', params.status); } if (params.startDate && params.endDate) { // 设置日期范围 await page.fill('input[name="startDate"]', params.startDate); await page.fill('input[name="endDate"]', params.endDate); } // 点击搜索按钮 await page.click('button[type="submit"]'); await page.waitForTimeout(2000); // 抓取订单数据 const orders = await page.$$eval('.order-item', (items) => { return items.map(item => { const orderId = item.querySelector('.order-id')?.textContent?.trim(); const status = item.querySelector('.order-status')?.textContent?.trim(); const amount = item.querySelector('.order-amount')?.textContent?.trim(); return { id: orderId, status, amount, createdAt: new Date().toISOString() }; }); }); return { success: true, data: { orders, total: orders.length, page: params.page || 1 }, timestamp: Date.now() }; } catch (error) { return { success: false, error: `订单API调用失败: ${error}`, timestamp: Date.now() }; } } /** * 模拟商品API */ private async simulateProductsApi(page: Page, method: string, params: any): Promise { // 类似订单API的实现 return { success: true, data: { products: [], total: 0 }, timestamp: Date.now() }; } /** * 模拟库存API */ private async simulateInventoryApi(page: Page, method: string, params: any): Promise { // 类似订单API的实现 return { success: true, data: { inventory: [] }, timestamp: Date.now() }; } /** * 检查登录状态 */ isLoggedIn(platform: string): boolean { return this.loginStates.get(platform) || false; } /** * 获取支持的平台列表 */ getSupportedPlatforms(): string[] { return ['tiktok', 'shopee', 'amazon']; } /** * 关闭浏览器 */ async close(): Promise { if (this.browser) { await this.browser.close(); this.browser = null; this.context = null; this.activePages.clear(); this.loginStates.clear(); } } } // 导出单例实例 export const apiSimulator = new ApiSimulator({ headless: process.env.HEADLESS !== 'false', userDataDir: process.env.USER_DATA_DIR || './user-data', timeout: 30000 });