爬虫管理系统实现方案

开发步骤大纲

阶段1:项目骨架搭建(1-2天)

  1. 初始化 FastAPI 项目,连接 PostgreSQL

  2. 初始化 Vue 3 项目,配置路由和 UI 框架

  3. 编写 Docker Compose 文件(PostgreSQL, Redis, 后端, 前端, Worker)

  4. 实现最基础的"Hello World"验证前后端联通

阶段2:用户认证系统(1天)

  1. 创建 User 模型,实现注册/登录

  2. 使用 JWT 生成令牌,前端存储并携带请求头

  3. 添加依赖注入 get_current_user,所有 API 继承该依赖

阶段3:模板上传与解析(2天)

  1. 设计 Excel/CSV 模板规范

    • 固定列名:url(必填)、keyword(如果有搜索)、其余为输出占位列

    • 或者完全自由定义,让用户在界面做"输入列"和"输出列"映射

  2. 前端实现上传组件,发送文件到后端

  3. 后端解析文件,存储 templates 表,返回列名供前端映射配置

  4. 用户保存映射关系(如:A列是"商品标题",B列是"价格")

阶段4:采集引擎核心(3-5天)

  1. 在 Celery Worker 中编写一个通用的 Playwright 采集函数

    • 接收参数:平台代码、登录状态ID、目标URL、输入数据、映射规则
  2. 实现登录态管理:

    • 方式A:让用户在前端输入账号密码(加密存储),Worker 每次自动登录

    • 方式B:提供"手动登录接口"

      • 前端点击"开始登录",Worker 返回一个 VNC 连接地址

      • 用户通过 noVNC 在浏览器里操作,完成登录后 Worker 保存 storage_state

  3. 实现数据提取逻辑:

    • 针对每个平台编写一个"提取器"函数(或配置化 XPath/CSS 选择器)

    • 函数加载登录态,打开页面,根据映射规则抓取数据

    • 结果写入 scraped_data

  4. 加入随机延迟、异常重试机制

阶段5:任务流程串联(2天)

  1. 后端接口:创建任务(读取模板,为每行生成 task_item,推入队列)

  2. Worker 消费队列:逐个处理 task_item,更新进度

  3. 前端展示任务列表、进度条,实时刷新(轮询或 WebSocket)

阶段6:结果导出与下载(1天)

  1. 任务全部完成后,后端组装原始模板 + 抓取数据,生成新 Excel/CSV

  2. 存储到文件服务,返回下载链接

  3. 清理过期文件(定时任务)

阶段7:多平台扩展(持续)

  1. 每新增一个平台,只需:

    • 在配置中注册平台代码和名称

    • 编写对应的 extract_platform_xxx() 函数

    • 定义该平台的模板格式要求

  2. 前端自动展示所有支持的平台列表

阶段8:多用户隔离与资源控制(1天)

  1. 所有数据库操作过滤 user_id

  2. Worker 中为每个任务创建独立的 Browser Context

  3. 限制单个用户最大并发任务数(Celery 路由 + 应用层判断)

  4. 资源不足时可增加 Worker 实例

阶段9:部署与运维(1天)

  1. 完善 docker-compose.yml,包含所有服务

  2. 编写环境变量配置文件

  3. 内网机器 docker compose up -d 一键启动

  4. 数据备份策略(定时 pg_dump + 文件备份)

阶段1:项目骨架搭建的实际操作步骤

一、初始化VUE项目

第 1 步:安装 Node.js

Vue3 项目依赖 Node.js 环境,先检查你的电脑上有没有装。

打开终端(Windows 用 PowerShell 或 CMD,Mac/Linux 用终端),输入:

bash

复制代码
node -v

如果显示版本号(如 v18.16.0),说明已安装,跳到第 2 步。

如果显示 'node' 不是内部或外部命令,则需要安装。

安装方法:

  1. 打开 Node.js 官网,下载 LTS 版本(长期支持版,当前为 20.x 或 18.x)。

  2. 双击安装包,一路 Next 安装,全部保持默认选项(npm 和 PATH 都会自动配好)。

  3. 安装完成后,重新打开终端再次输入 node -vnpm -v,出现版本号即成功。

内网/离线环境:如果开发机不能连外网,需要从能上网的机器下载安装包,拷贝到开发机安装。npm 包的离线安装我们后续再说,现在先用在线方式走通。


第 2 步:使用 Vite 创建 Vue3 项目

Vite 是 Vue 官方推荐的现代构建工具,速度快、配置少。

在终端中,进入你希望存放项目的目录(例如桌面或 D:/projects),执行以下命令:

bash

复制代码
npm create vite@latest scraper-frontend -- --template vue

会询问你是否安装 create-vite,输入 y 回车即可。

等待几秒,一个名为 scraper-frontend 的项目就创建好了。

命令解释:

  • scraper-frontend 是项目文件夹名,可以自定义

  • --template vue 表示使用 Vue 模板(默认是 JavaScript,如果你想用 TypeScript 可换成 vue-ts,这里我们先从 JS 开始)

进入项目目录,安装依赖:

bash

复制代码
cd scraper-frontend
npm install

等待依赖安装完成。此时,一个纯净的 Vue3 项目已经就绪。


第 3 步:运行项目看效果

scraper-frontend 目录下执行:

bash

复制代码
npm run dev

终端会显示:

text

复制代码
  VITE v4.x.x  ready in xxx ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

打开浏览器访问 http://localhost:5173/,你应该能看到 Vite + Vue 的欢迎页面。

Ctrl + C 可以停止开发服务器。


第 4 步:安装 Element Plus 并配置

Element Plus 是一套成熟的 Vue3 组件库,提供按钮、表格、弹窗等 UI 控件,非常适合后台管理系统。

在项目根目录下执行:

bash

复制代码
npm install element-plus

然后修改入口文件,让 Element Plus 全局可用。用代码编辑器(VsCode 或任意)打开项目。

编辑 src/main.js

js

javascript 复制代码
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'

const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')

现在 Element Plus 的组件就可以在任意文件中直接使用了,不用每次手动引入。


第 5 步:安装 Vue Router(路由)

爬虫管理平台至少有登录页、任务管理页、模板上传页等,需要页面跳转。

安装路由:

bash

复制代码
npm install vue-router

src 下创建一个文件夹 router,并在其中创建 index.js

js

javascript 复制代码
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'

// 先准备两个占位页面(Login 和 Home),稍后会创建
const routes = [
  {
    path: '/',
    redirect: '/login'
  },
  {
    path: '/login',
    name: 'Login',
    component: () => import('../views/Login.vue')
  },
  {
    path: '/home',
    name: 'Home',
    component: () => import('../views/Home.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

main.js 中引入并使用路由:

js

javascript 复制代码
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
import router from './router'   // 新增

const app = createApp(App)
app.use(ElementPlus)
app.use(router)    // 新增
app.mount('#app')

第 6 步:创建基础页面和布局

创建 src/views 文件夹,新建两个页面文件。

Login.vue

vue

复制代码
<template>
  <div style="padding: 40px;">
    <h1>登录页(占位)</h1>
    <el-button type="primary" @click="$router.push('/home')">假装登录</el-button>
  </div>
</template>

<script setup>
// 后续在这里接入实际的登录逻辑
</script>

Home.vue

vue

复制代码
<template>
  <div style="padding: 40px;">
    <h1>任务管理页(占位)</h1>
    <el-button @click="$router.push('/login')">退出登录</el-button>
  </div>
</template>

修改 App.vue,只保留一个路由视图:

vue

复制代码
<template>
  <router-view />
</template>

访问 http://localhost:5173,应该自动跳转到 /login,点击按钮能跳到 /home,说明路由和 Element Plus 都已正常运行。


第 7 步:配置开发环境代理(对接后端做准备)

后面后端服务(FastAPI)会运行在 http://localhost:8000,前端开发时需要把 API 请求代理过去,避免跨域问题。

打开项目根目录的 vite.config.js,添加 server 配置:

js

javascript 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  server: {
    port: 5173,          // 保持默认
    proxy: {
      '/api': {
        target: 'http://localhost:8000',  // 后端地址
        changeOrigin: true,
        // rewrite: (path) => path.replace(/^\/api/, '')  // 如果后端不带 /api 前缀,可以去掉注释
      }
    }
  }
})

之后前端用 fetch('/api/users') 都会被代理到 http://localhost:8000/api/users,完美对接。


当前项目结构预览

text

复制代码
scraper-frontend/
├── public/
├── src/
│   ├── router/
│   │   └── index.js
│   ├── views/
│   │   ├── Login.vue
│   │   └── Home.vue
│   ├── App.vue
│   └── main.js
├── index.html
├── vite.config.js
└── package.json

二、搭建 FastAPI 后端项目+ PostgreSQL 数据库

  1. 安装 Python 并创建项目虚拟环境

  2. 初始化 FastAPI 项目骨架

  3. 用 Docker 快速启动一个 PostgreSQL(无需在本地繁琐配置)

  4. 安装数据库驱动,编写数据库连接代码

  5. 写一个简单的用户模型,跑通读写流程

  6. 用 API 测试工具验证连接成功

第 1 步:Python 与虚拟环境

实际操作:使用之前用conda建立的python313_conda虚拟环境,下面所有包的安装都是用conda,且使用前需要激活环境。

conda activate python313_conda

以下是创建项目环境(未使用):

  1. 检查 Python 版本

    打开终端(Windows 用 PowerShell),输入:

    bash

    复制代码
    python --version

    确保版本 ≥ 3.8(推荐 3.10+)。如果没有安装,去 python.org 下载并安装,安装时勾选「Add Python to PATH」

  2. 创建项目文件夹

    在你喜欢的目录下(例如 D:\projects)新建文件夹 scraper-backend

    bash

    复制代码
    mkdir scraper-backend
    cd scraper-backend
  3. 创建虚拟环境

    虚拟环境可以隔离项目依赖,避免污染系统 Python。

    bash

    复制代码
    python -m venv venv
  4. 激活虚拟环境

    • Windows (PowerShell)

      bash

      复制代码
      .\venv\Scripts\activate
    • Mac/Linux

      bash

      复制代码
      source venv/bin/activate

    激活后,终端前面会出现 (venv) 提示符。


第 2 步:初始化 FastAPI 项目骨架

  1. 安装核心依赖(激活虚拟环境并安装包)

    bash

    复制代码
    pip install fastapi uvicorn[standard]
  2. 创建项目结构

    我们先手动建几个文件夹和文件,后期再逐步扩展。最终结构如下:

    text

    复制代码
    scraper-backend/
    ├── app/
    │   ├── __init__.py
    │   ├── main.py          # FastAPI 应用入口
    │   ├── database.py       # 数据库连接配置
    │   ├── models.py         # 数据表模型
    │   └── ... (未来会有 api/、schemas/ 等)
    ├── requirements.txt

    现在一步步创建:

    • 新建 app 文件夹

    • app 中新建 __init__.py(空文件,标记为 Python 包)

    • 新建 app/main.py,写入以下基础代码:

      python

      复制代码
      from fastapi import FastAPI
      
      app = FastAPI(
          title="爬虫管理平台",
          version="0.1.0"
      )
      
      @app.get("/")
      def root():
          return {"message": "后端服务运行中"}
  3. 测试基础运行

    使用Anaconda powershell prompt,激活虚拟环境后,转到项目根目录(scraper-backend)下执行:

  1. bash

conda activate python313_conda

复制代码
2. bash
uvicorn app.main:app --reload

打开浏览器访问 http://127.0.0.1:8000,看到 {"message":"..."} 即成功。按 Ctrl+C 可以停止。


第 3 步:用 Docker 启动 PostgreSQL

实际操作:已经使用1panel构建PostgreSQL。在PostgreSQL下不使用postgres默认数据库,建立新的数据库,并设置用户名和密码。

以下是创建项目环境(未使用):

如果你本地没有安装和配置过 PostgreSQL,强烈推荐用 Docker,一行命令就搞定。

  1. 安装 Docker Desktop

    • Docker 官网 下载并安装。

    • 安装后启动 Docker Desktop,等待右下角图标变绿。

  2. 拉取并运行 PostgreSQL 容器

    终端中执行(注意 Windows 要用 PowerShell,且确保终端在任意目录即可):

    bash

    复制代码
    docker run -d --name scraper-postgres -p 5432:5432 -e POSTGRES_USER=scraper -e POSTGRES_PASSWORD=secret123 -e POSTGRES_DB=scraper_db postgres:16-alpine

    参数说明:

    • --name scraper-postgres:容器名称

    • -p 5432:5432:本机 5432 端口映射到容器 5432

    • POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB:创建初始用户、密码和数据库

    • 镜像使用体积小的 postgres:16-alpine

  3. 验证数据库是否启动

    bash

    复制代码
    docker ps

    会看到 scraper-postgres 状态为 Up

以后每次需要启动数据库时,只需:

bash

复制代码
docker start scraper-postgres

第 4 步:安装数据库驱动并编写连接代码

我们需要一个异步的 PostgreSQL 驱动,这里选择 databases + asyncpg,或者 SQLAlchemy(异步模式)。为了新手友好且后续扩展方便,我们采用 SQLAlchemy 2.0 异步模式 + asyncpg

  1. 安装依赖

    确保虚拟环境已激活,然后执行:

    bash

    复制代码
    pip install sqlalchemy[asyncio] asyncpg psycopg2-binary

    (psycopg2 暂时用不上,但未来同步工具可能会用,可安可不安)

  2. 编写数据库配置文件 app/database.py

    python

    python 复制代码
    from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
    from sqlalchemy.orm import sessionmaker, declarative_base
    
    DATABASE_URL = "postgresql+asyncpg://user:password@localhost:5432/database"
    
    engine = create_async_engine(DATABASE_URL, echo=True)
    async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
    
    Base = declarative_base()
    
    async def get_db():
        async with async_session() as session:
            yield session
  3. 编写一个简单的用户模型 app/models.py

    python

    python 复制代码
    import app.models  # 确保 User 模型被注册到 Base.metadata
    from sqlalchemy import Column, Integer, String, Boolean, DateTime
    from sqlalchemy.sql import func
    from app.database import Base
    
    
    class User(Base):
        __tablename__ = "users"
    
        id = Column(Integer, primary_key=True, index=True)
        username = Column(String(50), unique=True, nullable=False)
        password_hash = Column(String(255), nullable=False)
        is_active = Column(Boolean, default=True)
        created_at = Column(DateTime(timezone=True), server_default=func.now())
  4. app/main.py 中集成数据库,并在启动时自动建表

    修改 app/main.py

    python

    python 复制代码
    from fastapi import FastAPI, Depends
    from sqlalchemy.ext.asyncio import AsyncSession
    from sqlalchemy import text
    from contextlib import asynccontextmanager
    import app.models
    from app.database import engine, Base, get_db
    
    # ---------- 数据库初始化(独立提取,方便调试) ----------
    async def init_db():
        """创建所有表(如果尚未存在)"""
        try:
            async with engine.begin() as conn:
                await conn.run_sync(Base.metadata.create_all)
            print("✅ 数据库表初始化完成")
        except Exception as e:
            print(f"❌ 数据库初始化失败: {e}")
            raise
    
    # ---------- lifespan 替代 on_event ----------
    @asynccontextmanager
    async def lifespan(app: FastAPI):
        # 启动时执行
        await init_db()
        yield
        # 关闭时执行(可留空)
        print("👋 应用关闭")
    
    # ---------- 创建 FastAPI 实例 ----------
    app = FastAPI(
        title="爬虫管理平台",
        version="0.1.0",
        lifespan=lifespan  # 使用 lifespan 替代 on_event
    )
    
    # ---------- 路由 ----------
    @app.get("/")
    async def root():
        return {"message": "后端服务运行中"}
    
    @app.get("/db-test")
    async def db_test(db: AsyncSession = Depends(get_db)):
        result = await db.execute(text("SELECT COUNT(*) FROM users"))
        count = result.scalar()
        return {"user_count": count}

第 5 步:重新启动后端并测试数据库连接

  1. 停止之前的 uvicorn(按 Ctrl+C)。

  2. 重新启动(使用Anaconda powershell prompt激活环境后运行)

    bash

    复制代码
    uvicorn app.main:app --reload
  3. 访问测试接口 :浏览器打开 http://127.0.0.1:8000/db-test,会返回 {"user_count": 0},说明数据库连接成功,并且表已创建,只是还没数据。

  4. 用数据库管理工具验证 (可选)

    你可以用 DBeaver、Navicat 或命令行连接 PostgreSQL 查看 users 表确实存在:

    bash

    复制代码
    docker exec -it scraper-postgres psql -U scraper -d scraper_db
    \dt          # 列出表
    SELECT * FROM users;   # 查数据

当前项目结构总览

这是你目前后端的样子:

text

复制代码
scraper-backend/
├── app/
│   ├── __init__.py
│   ├── main.py
│   ├── database.py
│   └── models.py
├── requirements.txt        (可稍后生成:pip freeze > requirements.txt)
└── ...

三、编写 Docker Compose 文件(PostgreSQL, Redis, 后端, 前端, Worker),验证前后端连接


步骤 1:上传项目代码到服务器

将本地 scraper-backendscraper-frontend 整个目录上传至 /opt/1panel/apps/scraper-platform/,确保结构如下:

text

复制代码
/opt/1panel/apps/scraper-platform/
├── scraper-backend/
│   ├── Dockerfile
│   ├── requirements.txt
│   └── app/
└── scraper-frontend/
    ├── Dockerfile
    ├── package.json
    └── src/

步骤 2:准备 Dockerfile和requirements.txt

/opt/1panel/apps/scraper-platform/scraper-backend/requirements.txt

fastapi

uvicorn[standard]

sqlalchemy[asyncio]

asyncpg

python-jose[cryptography]

passlib[bcrypt]

python-multipart

bcrypt==4.0.1

后端 scraper-backend/Dockerfile(最终版):

Dockerfile

复制代码
FROM python:3.11-slim
WORKDIR /app
RUN apt-get update && apt-get install -y --no-install-recommends gcc libpq-dev && rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

前端 scraper-frontend/Dockerfile(最终版):

Dockerfile

复制代码
FROM node:22-alpine       # 必须 22+,否则 Vite 报错
WORKDIR /app
COPY package*.json ./
RUN npm config set registry https://registry.npmmirror.com
RUN npm install
COPY . .
EXPOSE 5173
ENV CHOKIDAR_USEPOLLING=true
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]

步骤 3:编写 docker-compose.yml(1Panel 编排)

yaml

复制代码
services:
  backend:
    build: ./scraper-backend
    container_name: scraper-backend
    restart: unless-stopped
    ports:
      - "8000:8000"
    volumes:
      - ./scraper-backend:/app
    environment:
      DATABASE_URL: postgresql+asyncpg://user_ysXKNY:password_8Z3dk8@host.docker.internal:5432/scraper_db

  frontend:
    build: ./scraper-frontend
    container_name: scraper-frontend
    restart: unless-stopped
    ports:
      - "5173:5173"
    volumes:
      - ./scraper-frontend/src:/app/src
      - ./scraper-frontend/public:/app/public
      - ./scraper-frontend/index.html:/app/index.html
      - ./scraper-frontend/vite.config.js:/app/vite.config.js
    environment:
      - CHOKIDAR_USEPOLLING=true
    depends_on:
      - backend

关键说明 :前端 volumes 只挂载了需要热更新的文件,避免覆盖 node_modules 导致权限问题。


步骤 4:在 1Panel 创建编排并启动

  1. 1Panel → 容器 → 编排 → 创建编排

  2. 路径选择: /opt/1panel/apps/scraper-platform/docker-compose.yml

  3. 粘贴上面的 yml → 确认

  4. 点击启动(首次会自动构建镜像)


验证结果

  • 访问 http://192.168.30.186:5173

  • 点击「假装登录」→ 进入 Home 页

  • 点击「测试后端连接」→ 页面显示 "后端返回:Hello from backend! 前后端联通成功 ✅"


当前状态

  • ✅ 后端 FastAPI 运行正常,数据库连接成功

  • ✅ 前端 Vue3 运行正常,代理转发 /api 到后端

  • ✅ 代码修改可通过挂载卷实时热更新

  • ✅ 数据库表 users 已自动创建,等待写入数据

相关推荐
跨境数据猎手3 小时前
1688 商品铺货到独立站实操(附工具 + 代码)
大数据·爬虫·软件构建
_.Switch19 小时前
东方财富股票数据JS逆向:secids字段和AES加密实战
开发语言·前端·javascript·网络·爬虫·python·ecmascript
码界奇点1 天前
基于Python的新浪微博数据爬虫系统设计与实现
数据库·爬虫·python·毕业设计·新浪微博·源代码管理
tang777891 天前
代理IP质量检测实战:Python实现IP可用性、延迟、匿名度自动测试脚本
大数据·爬虫·python·网络协议·tcp/ip
datascome2 天前
文章自动采集发布到Discuz网站技巧
经验分享·爬虫·数据采集·discuz·网站内容批量发布
亿牛云爬虫专家2 天前
Go爬虫进阶:如何优雅地在Colly框架中实现无缝代理切换?
爬虫·中间件·golang·爬虫代理·colly框架·代理切换·api提取
小白学大数据2 天前
Python 3.7 高并发爬虫:接口请求与页面解析并发处理
开发语言·爬虫·python
深蓝电商API3 天前
淘宝商品主图视频下载:从 API 返回值中提取视频 URL 并转码
爬虫·接口·api·淘宝api
独隅3 天前
爬虫对抗:ZLibrary反爬机制实战分析
爬虫