Files
makemd/docs/04_Plugin/Plugin_Design.md
wurenzhi 72cd7f6f45 chore: 清理归档文件和文档模板
删除不再需要的归档文件和过时的文档模板,包括多个README、安全策略、前端集成蓝图等文件,同时移除了未使用的业务文档和项目结构文件。

优化项目结构,移除冗余文件,保持代码库整洁。主要删除archive/handover目录下的多个文件及doc目录下的部分文档模板。
2026-03-18 01:21:15 +08:00

17 KiB
Raw Blame History

Plugin Design (Crawlful Hub)

定位Crawlful Hub 浏览器插件架构设计文档 - 包含技术栈、目录结构、核心功能及开发规范。 更新日期: 2026-03-18 最高优先级参考: Business_ClosedLoops.md


1. 技术栈 (Tech Stack)

层级 技术 版本 用途
Framework WebExtensions API MV3 浏览器扩展标准
Language TypeScript 5.x 开发语言
Build Tool Vite 5.x 构建工具
Bundler Rollup 4.x 代码打包
UI React + Tailwind 18.x + 3.x 弹窗/选项页 UI
Testing Vitest 1.x 单元测试

2. 目录结构 (Directory Structure)

extension/
│
├─ manifest.json                 # 扩展清单 (MV3)
│
├─ src/
│   │
│   ├─ background/              # Service Worker (后台脚本)
│   │   ├─ index.ts             # 入口
│   │   ├─ handlers/
│   │   │   ├─ messageHandler.ts    # 消息处理
│   │   │   ├─ alarmHandler.ts      # 定时任务
│   │   │   └─ commandHandler.ts    # 快捷键处理
│   │   └─ services/
│   │       ├─ crawlerService.ts    # 网页采集服务无API平台
│   │       ├─ syncService.ts       # 同步服务
│   │       └─ authService.ts       # 认证服务
│   │
│   ├─ content/                 # 内容脚本 (注入页面)
│   │   ├─ index.ts             # 入口
│   │   ├─ crawlers/            # 采集器
│   │   │   ├─ amazonCrawler.ts
│   │   │   ├─ ebayCrawler.ts
│   │   │   ├─ shopifyCrawler.ts
│   │   │   └─ aliexpressCrawler.ts
│   │   ├─ automation/          # 自动化操作
│   │   │   ├─ listingAutomation.ts
│   │   │   ├─ orderAutomation.ts
│   │   │   └─ adAutomation.ts
│   │   └─ utils/
│   │       ├─ domUtils.ts
│   │       ├─ selectorUtils.ts
│   │       └─ eventUtils.ts
│   │
│   ├─ popup/                   # 弹窗页面
│   │   ├─ index.tsx
│   │   ├─ components/
│   │   │   ├─ QuickActions.tsx
│   │   │   ├─ StatusPanel.tsx
│   │   │   └─ RecentTasks.tsx
│   │   └─ hooks/
│   │       └─ useBackground.ts
│   │
│   ├─ options/                 # 选项页面
│   │   ├─ index.tsx
│   │   ├─ components/
│   │   │   ├─ GeneralSettings.tsx
│   │   │   ├─ PlatformSettings.tsx
│   │   │   ├─ AccountSettings.tsx
│   │   │   └─ AdvancedSettings.tsx
│   │   └─ stores/
│   │       └─ settingsStore.ts
│   │
│   ├─ shared/                  # 共享资源
│   │   ├─ types/
│   │   │   ├─ messaging.ts     # 消息类型定义
│   │   │   ├─ crawler.ts       # 采集类型
│   │   │   └─ platform.ts      # 平台类型
│   │   ├─ constants/
│   │   │   ├─ platforms.ts     # 平台常量
│   │   │   └─ selectors.ts     # 选择器常量
│   │   └─ utils/
│   │       ├─ logger.ts
│   │       ├─ storage.ts
│   │       └─ crypto.ts
│   │
│   └─ injected/                # 注入脚本 (隔离环境)
│       ├─ index.ts
│       └─ services/
│           └─ bridgeService.ts
│
├─ assets/                      # 静态资源
│   ├─ icons/
│   │   ├─ icon-16.png
│   │   ├─ icon-32.png
│   │   ├─ icon-48.png
│   │   └─ icon-128.png
│   └─ styles/
│       └─ global.css
│
├─ _locales/                    # 国际化
│   ├─ en/
│   │   └─ messages.json
│   └─ zh_CN/
│       └─ messages.json
│
└─ dist/                        # 构建输出

3. 架构设计 (Architecture)

3.1 核心组件关系

┌─────────────────────────────────────────────────────────────┐
│                      Browser Extension                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐ │
│  │   Popup      │     │   Options    │     │  Content     │ │
│  │   (UI)       │◄───►│   (Settings) │◄───►│  (Page)      │ │
│  └──────┬───────┘     └──────┬───────┘     └──────┬───────┘ │
│         │                    │                    │         │
│         └────────────────────┼────────────────────┘         │
│                              │                              │
│                              ▼                              │
│                    ┌──────────────────┐                     │
│                    │  Service Worker  │                     │
│                    │   (Background)   │                     │
│                    └────────┬─────────┘                     │
│                             │                               │
│         ┌───────────────────┼───────────────────┐          │
│         ▼                   ▼                   ▼          │
│  ┌──────────────┐   ┌──────────────┐   ┌──────────────┐   │
│  │   Crawler    │   │     Sync     │   │    Auth      │   │
│  │   Engine     │   │   Engine     │   │   Engine     │   │
│  └──────────────┘   └──────────────┘   └──────────────┘   │
│                                                              │
└─────────────────────────────────────────────────────────────┘

3.2 通信机制

消息类型 (Messaging Types)

// src/shared/types/messaging.ts

export enum MessageType {
  // 采集相关
  CRAWL_PRODUCT = 'CRAWL_PRODUCT',
  CRAWL_ORDER = 'CRAWL_ORDER',
  CRAWL_COMPLETE = 'CRAWL_COMPLETE',
  
  // 自动化相关
  AUTO_LISTING = 'AUTO_LISTING',
  AUTO_ORDER = 'AUTO_ORDER',
  AUTO_AD = 'AUTO_AD',
  
  // 同步相关
  SYNC_DATA = 'SYNC_DATA',
  SYNC_STATUS = 'SYNC_STATUS',
  
  // 认证相关
  AUTH_LOGIN = 'AUTH_LOGIN',
  AUTH_LOGOUT = 'AUTH_LOGOUT',
  AUTH_REFRESH = 'AUTH_REFRESH',
  
  // 设置相关
  GET_SETTINGS = 'GET_SETTINGS',
  SET_SETTINGS = 'SET_SETTINGS',
  
  // 任务相关
  TASK_STATUS = 'TASK_STATUS',
  TASK_RESULT = 'TASK_RESULT',
}

export interface MessagePayload {
  type: MessageType;
  data?: any;
  error?: string;
  traceId?: string;
}

通信流程

Content Script ──► Background Service Worker ──► Backend API
      │                      │
      │◄─────────────────────┘
      │
Popup/Options ◄─── Chrome Storage

4. 核心功能模块

4.1 数据采集模块 (Crawler)

功能定位

  • 从各电商平台采集商品、订单数据
  • 仅处理无API平台TikTok Shop, Temu, 部分1688页面等
  • 有API平台由后端处理Amazon MWS, eBay API, Shopee Open API
  • 支持沙箱模式(测试环境)

采集策略矩阵

平台 类型 采集方式 登录要求 反爬策略
Amazon 有API 后端处理 OAuth API限流
eBay 有API 后端处理 OAuth API限流
Shopee 有API 后端处理 OAuth API限流
TikTok Shop 无API 插件采集 需登录 指纹隔离+代理IP
Temu 无API 插件采集 需登录 指纹隔离+代理IP
1688(部分) 无API 插件采集 可选 频率控制

⚠️ 重要约束

  • 后端严禁直接爬取IP封禁风险、法律合规问题
  • 所有网页级采集必须通过插件在用户浏览器端执行
  • 插件必须实现店铺隔离一店一IP一指纹

采集器实现

// src/content/crawlers/amazonCrawler.ts

export class AmazonCrawler {
  private selectors = {
    title: '#productTitle',
    price: '.a-price-whole, .a-offscreen',
    images: '#landingImage, .a-dynamic-image',
    description: '#feature-bullets, #productDescription',
    reviews: '#acrCustomerReviewText',
  };

  async crawlProduct(): Promise<ProductData> {
    const title = this.extractText(this.selectors.title);
    const price = this.extractPrice(this.selectors.price);
    const images = this.extractImages(this.selectors.images);
    const description = this.extractText(this.selectors.description);
    
    return {
      platform: 'AMAZON',
      title,
      price,
      images,
      description,
      url: window.location.href,
      crawledAt: new Date().toISOString(),
    };
  }

  private extractText(selector: string): string {
    const element = document.querySelector(selector);
    return element?.textContent?.trim() || '';
  }

  private extractPrice(selector: string): number {
    const element = document.querySelector(selector);
    const text = element?.textContent?.replace(/[^\d.]/g, '') || '0';
    return parseFloat(text);
  }

  private extractImages(selector: string): string[] {
    const elements = document.querySelectorAll(selector);
    return Array.from(elements)
      .map(el => el.getAttribute('src') || el.getAttribute('data-src'))
      .filter(Boolean) as string[];
  }
}

采集流程

1. 用户点击采集按钮 / 定时任务触发
2. Content Script 注入采集器
3. 采集器解析 DOM 提取数据
4. 数据发送至 Background
5. Background 发送至后端 API
6. 返回采集结果

4.2 自动化操作模块 (Automation)

功能定位

  • 自动刊登商品
  • 自动处理订单
  • 自动投放广告

自动化实现

// src/content/automation/listingAutomation.ts

export class ListingAutomation {
  async autoListing(productData: ProductData, platform: string): Promise<boolean> {
    switch (platform) {
      case 'AMAZON':
        return this.listOnAmazon(productData);
      case 'EBAY':
        return this.listOnEbay(productData);
      case 'SHOPIFY':
        return this.listOnShopify(productData);
      default:
        throw new Error(`Unsupported platform: ${platform}`);
    }
  }

  private async listOnAmazon(product: ProductData): Promise<boolean> {
    // 1. 导航到刊登页面
    await this.navigateTo('/inventory/add');
    
    // 2. 填写商品信息
    await this.fillInput('#title', product.title);
    await this.fillInput('#price', product.price.toString());
    await this.fillTextarea('#description', product.description);
    
    // 3. 上传图片
    for (const imageUrl of product.images) {
      await this.uploadImage(imageUrl);
    }
    
    // 4. 提交刊登
    await this.click('#submit-button');
    
    // 5. 等待结果
    return this.waitForSuccess();
  }

  private async navigateTo(path: string): Promise<void> {
    window.location.href = `https://sellercentral.amazon.com${path}`;
    await this.waitForElement('#title', 10000);
  }

  private async fillInput(selector: string, value: string): Promise<void> {
    const input = document.querySelector(selector) as HTMLInputElement;
    if (input) {
      input.value = value;
      input.dispatchEvent(new Event('input', { bubbles: true }));
    }
  }

  private async waitForElement(selector: string, timeout: number): Promise<void> {
    return new Promise((resolve, reject) => {
      const startTime = Date.now();
      const check = () => {
        if (document.querySelector(selector)) {
          resolve();
        } else if (Date.now() - startTime > timeout) {
          reject(new Error('Timeout waiting for element'));
        } else {
          setTimeout(check, 100);
        }
      };
      check();
    });
  }
}

4.3 数据同步模块 (Sync)

功能定位

  • 定时同步订单数据
  • 同步库存状态
  • 同步广告数据

同步配置

// src/background/services/syncService.ts

export class SyncService {
  private syncIntervals: Record<string, number> = {
    orders: 5 * 60 * 1000,    // 5分钟
    inventory: 10 * 60 * 1000, // 10分钟
    ads: 30 * 60 * 1000,       // 30分钟
  };

  async startSync(): Promise<void> {
    // 创建定时任务
    chrome.alarms.create('syncOrders', { periodInMinutes: 5 });
    chrome.alarms.create('syncInventory', { periodInMinutes: 10 });
    chrome.alarms.create('syncAds', { periodInMinutes: 30 });
  }

  async handleAlarm(alarmName: string): Promise<void> {
    switch (alarmName) {
      case 'syncOrders':
        await this.syncOrders();
        break;
      case 'syncInventory':
        await this.syncInventory();
        break;
      case 'syncAds':
        await this.syncAds();
        break;
    }
  }

  private async syncOrders(): Promise<void> {
    const platforms = await this.getEnabledPlatforms();
    for (const platform of platforms) {
      try {
        const orders = await this.crawlOrders(platform);
        await this.sendToBackend('/api/v1/orders/sync', orders);
      } catch (error) {
        console.error(`Failed to sync orders for ${platform}:`, error);
      }
    }
  }
}

5. 安全与隐私

5.1 数据存储

// src/shared/utils/storage.ts

export class SecureStorage {
  // 存储敏感数据(加密)
  static async setSecure(key: string, value: string): Promise<void> {
    const encrypted = await this.encrypt(value);
    await chrome.storage.local.set({ [key]: encrypted });
  }

  // 读取敏感数据(解密)
  static async getSecure(key: string): Promise<string | null> {
    const result = await chrome.storage.local.get(key);
    if (result[key]) {
      return this.decrypt(result[key]);
    }
    return null;
  }

  // 存储普通数据
  static async set(key: string, value: any): Promise<void> {
    await chrome.storage.local.set({ [key]: value });
  }

  // 读取普通数据
  static async get(key: string): Promise<any> {
    const result = await chrome.storage.local.get(key);
    return result[key];
  }

  private static async encrypt(text: string): Promise<string> {
    // 使用 Chrome 的加密 API
    // 实际实现需要更复杂的加密逻辑
    return btoa(text);
  }

  private static async decrypt(encrypted: string): Promise<string> {
    return atob(encrypted);
  }
}

5.2 权限控制

// manifest.json
{
  "manifest_version": 3,
  "name": "Crawlful Hub",
  "version": "1.0.0",
  "permissions": [
    "storage",
    "alarms",
    "activeTab",
    "scripting"
  ],
  "host_permissions": [
    "https://sellercentral.amazon.com/*",
    "https://www.ebay.com/*",
    "https://*.myshopify.com/*",
    "https://*.tiktok.com/*"
  ],
  "background": {
    "service_worker": "src/background/index.ts"
  },
  "content_scripts": [
    {
      "matches": [
        "https://sellercentral.amazon.com/*",
        "https://www.ebay.com/*"
      ],
      "js": ["src/content/index.ts"]
    }
  ],
  "action": {
    "default_popup": "src/popup/index.html"
  },
  "options_page": "src/options/index.html"
}

6. 开发规范

6.1 代码规范

  • 使用 TypeScript 严格模式
  • 使用函数式组件 + Hooks
  • 避免使用 any 类型
  • 所有消息类型必须在 messaging.ts 中定义

6.2 测试规范

// __tests__/crawler.test.ts
import { AmazonCrawler } from '../src/content/crawlers/amazonCrawler';

describe('AmazonCrawler', () => {
  let crawler: AmazonCrawler;

  beforeEach(() => {
    crawler = new AmazonCrawler();
  });

  test('should extract product title', async () => {
    // Mock DOM
    document.body.innerHTML = `
      <span id="productTitle">Test Product</span>
    `;
    
    const product = await crawler.crawlProduct();
    expect(product.title).toBe('Test Product');
  });
});

6.3 构建与发布

# 开发模式
npm run dev

# 生产构建
npm run build

# 打包扩展
npm run package

# 运行测试
npm run test

7. 相关文档


本文档基于业务闭环设计,最后更新: 2026-03-18