开发步骤大纲
阶段1:项目骨架搭建(1-2天)
-
初始化 FastAPI 项目,连接 PostgreSQL
-
初始化 Vue 3 项目,配置路由和 UI 框架
-
编写 Docker Compose 文件(PostgreSQL, Redis, 后端, 前端, Worker)
-
实现最基础的"Hello World"验证前后端联通
阶段2:用户认证系统(1天)
-
创建 User 模型,实现注册/登录
-
使用 JWT 生成令牌,前端存储并携带请求头
-
添加依赖注入
get_current_user,所有 API 继承该依赖
阶段3:模板上传与解析(2天)
-
设计 Excel/CSV 模板规范
-
固定列名:
url(必填)、keyword(如果有搜索)、其余为输出占位列 -
或者完全自由定义,让用户在界面做"输入列"和"输出列"映射
-
-
前端实现上传组件,发送文件到后端
-
后端解析文件,存储
templates表,返回列名供前端映射配置 -
用户保存映射关系(如:A列是"商品标题",B列是"价格")
阶段4:采集引擎核心(3-5天)
-
在 Celery Worker 中编写一个通用的 Playwright 采集函数
- 接收参数:平台代码、登录状态ID、目标URL、输入数据、映射规则
-
实现登录态管理:
-
方式A:让用户在前端输入账号密码(加密存储),Worker 每次自动登录
-
方式B:提供"手动登录接口"
-
前端点击"开始登录",Worker 返回一个 VNC 连接地址
-
用户通过 noVNC 在浏览器里操作,完成登录后 Worker 保存
storage_state
-
-
-
实现数据提取逻辑:
-
针对每个平台编写一个"提取器"函数(或配置化 XPath/CSS 选择器)
-
函数加载登录态,打开页面,根据映射规则抓取数据
-
结果写入
scraped_data
-
-
加入随机延迟、异常重试机制
阶段5:任务流程串联(2天)
-
后端接口:创建任务(读取模板,为每行生成
task_item,推入队列) -
Worker 消费队列:逐个处理
task_item,更新进度 -
前端展示任务列表、进度条,实时刷新(轮询或 WebSocket)
阶段6:结果导出与下载(1天)
-
任务全部完成后,后端组装原始模板 + 抓取数据,生成新 Excel/CSV
-
存储到文件服务,返回下载链接
-
清理过期文件(定时任务)
阶段7:多平台扩展(持续)
-
每新增一个平台,只需:
-
在配置中注册平台代码和名称
-
编写对应的
extract_platform_xxx()函数 -
定义该平台的模板格式要求
-
-
前端自动展示所有支持的平台列表
阶段8:多用户隔离与资源控制(1天)
-
所有数据库操作过滤
user_id -
Worker 中为每个任务创建独立的 Browser Context
-
限制单个用户最大并发任务数(Celery 路由 + 应用层判断)
-
资源不足时可增加 Worker 实例
阶段9:部署与运维(1天)
-
完善
docker-compose.yml,包含所有服务 -
编写环境变量配置文件
-
内网机器
docker compose up -d一键启动 -
数据备份策略(定时 pg_dump + 文件备份)
阶段1:项目骨架搭建的实际操作步骤
一、初始化VUE项目
第 1 步:安装 Node.js
Vue3 项目依赖 Node.js 环境,先检查你的电脑上有没有装。
打开终端(Windows 用 PowerShell 或 CMD,Mac/Linux 用终端),输入:
bash
node -v
如果显示版本号(如 v18.16.0),说明已安装,跳到第 2 步。
如果显示 'node' 不是内部或外部命令,则需要安装。
安装方法:
-
打开 Node.js 官网,下载 LTS 版本(长期支持版,当前为 20.x 或 18.x)。
-
双击安装包,一路
Next安装,全部保持默认选项(npm 和 PATH 都会自动配好)。 -
安装完成后,重新打开终端再次输入
node -v和npm -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 数据库
-
安装 Python 并创建项目虚拟环境
-
初始化 FastAPI 项目骨架
-
用 Docker 快速启动一个 PostgreSQL(无需在本地繁琐配置)
-
安装数据库驱动,编写数据库连接代码
-
写一个简单的用户模型,跑通读写流程
-
用 API 测试工具验证连接成功
第 1 步:Python 与虚拟环境
实际操作:使用之前用conda建立的python313_conda虚拟环境,下面所有包的安装都是用conda,且使用前需要激活环境。
conda activate python313_conda
以下是创建项目环境(未使用):
-
检查 Python 版本
打开终端(Windows 用 PowerShell),输入:
bash
python --version确保版本 ≥ 3.8(推荐 3.10+)。如果没有安装,去 python.org 下载并安装,安装时勾选「Add Python to PATH」。
-
创建项目文件夹
在你喜欢的目录下(例如
D:\projects)新建文件夹scraper-backend:bash
mkdir scraper-backend cd scraper-backend -
创建虚拟环境
虚拟环境可以隔离项目依赖,避免污染系统 Python。
bash
python -m venv venv -
激活虚拟环境
-
Windows (PowerShell):
bash
.\venv\Scripts\activate -
Mac/Linux:
bash
source venv/bin/activate
激活后,终端前面会出现
(venv)提示符。 -
第 2 步:初始化 FastAPI 项目骨架
-
安装核心依赖(激活虚拟环境并安装包)
bash
pip install fastapi uvicorn[standard] -
创建项目结构
我们先手动建几个文件夹和文件,后期再逐步扩展。最终结构如下:
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": "后端服务运行中"}
-
-
测试基础运行
使用Anaconda powershell prompt,激活虚拟环境后,转到项目根目录(
scraper-backend)下执行:
- 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,一行命令就搞定。
-
安装 Docker Desktop
-
从 Docker 官网 下载并安装。
-
安装后启动 Docker Desktop,等待右下角图标变绿。
-
-
拉取并运行 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
-
-
验证数据库是否启动
bash
docker ps会看到
scraper-postgres状态为Up。
以后每次需要启动数据库时,只需:
bash
docker start scraper-postgres
第 4 步:安装数据库驱动并编写连接代码
我们需要一个异步的 PostgreSQL 驱动,这里选择 databases + asyncpg,或者 SQLAlchemy(异步模式)。为了新手友好且后续扩展方便,我们采用 SQLAlchemy 2.0 异步模式 + asyncpg。
-
安装依赖
确保虚拟环境已激活,然后执行:
bash
pip install sqlalchemy[asyncio] asyncpg psycopg2-binary(psycopg2 暂时用不上,但未来同步工具可能会用,可安可不安)
-
编写数据库配置文件
app/database.pypython
pythonfrom 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 -
编写一个简单的用户模型
app/models.pypython
pythonimport 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()) -
在
app/main.py中集成数据库,并在启动时自动建表修改
app/main.py:python
pythonfrom 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 步:重新启动后端并测试数据库连接
-
停止之前的 uvicorn(按 Ctrl+C)。
-
重新启动(使用Anaconda powershell prompt激活环境后运行):
bash
uvicorn app.main:app --reload -
访问测试接口 :浏览器打开
http://127.0.0.1:8000/db-test,会返回{"user_count": 0},说明数据库连接成功,并且表已创建,只是还没数据。 -
用数据库管理工具验证 (可选)
你可以用 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-backend 和 scraper-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 创建编排并启动
-
1Panel → 容器 → 编排 → 创建编排
-
路径选择:
/opt/1panel/apps/scraper-platform/docker-compose.yml -
粘贴上面的 yml → 确认
-
点击启动(首次会自动构建镜像)
验证结果
-
访问
http://192.168.30.186:5173 -
点击「假装登录」→ 进入 Home 页
-
点击「测试后端连接」→ 页面显示 "后端返回:Hello from backend! 前后端联通成功 ✅"
当前状态
-
✅ 后端 FastAPI 运行正常,数据库连接成功
-
✅ 前端 Vue3 运行正常,代理转发
/api到后端 -
✅ 代码修改可通过挂载卷实时热更新
-
✅ 数据库表
users已自动创建,等待写入数据