This commit is contained in:
2026-03-19 14:21:14 +08:00
parent 7bfba04199
commit 2614af7808
23 changed files with 4447 additions and 489 deletions

619
README.md
View File

@@ -1,536 +1,191 @@
# 南京公共工程建设中心 - 公告采集工具
# 公告抓取与分析工具
一个用于采集南京公共工程建设中心公告信息的 Web 可视化工具,支持定时任务和邮件推送
一个用于管理公告抓取任务、查看抓取结果、查询项目数据并维护系统配置的工具
## 功能特性
当前项目结构已经升级为:
- ✅ 采集公告列表(支持分页)
- ✅ 按时间范围智能采集
- ✅ 采集公告详情内容
- ✅ 智能提取预算金额
- ✅ 生成统计报告
- ✅ Web 可视化界面
- ✅ 导出 Word/Markdown 报告
- ✅ RESTful API 支持
-**定时任务自动采集**
-**邮件推送 HTML 报告**
-**Web 配置界面**
-**无需数据库,轻量部署**
- 前端Vue 3 + JavaScript + Vite + Vue Router + Axios + Element Plus
- 后端Node.js + Express
- 数据存储better-sqlite3
- 调度node-cron
- 邮件nodemailer
## 快速开始
## 功能概览
### 1. 安装依赖
- 任务管理:新增、编辑、启用、禁用、删除任务
- 手动执行:支持单任务运行和批量运行
- 结果查看:按城市、板块、类型筛选抓取结果
- 项目查询:按项目名称、金额、日期范围过滤项目
- 系统设置:维护 Agent、定时任务、邮件配置
- 定时调度:支持 cron 表达式配置
- 数据持久化:任务与结果保存在 SQLite
## 环境要求
- Node.js 20 及以上可运行当前项目
- 建议使用 Node.js 22
说明:
- 当前依赖 `@mendable/firecrawl-js` 会提示要求 Node `>=22`
- 目前在 Node `20.19.4` 下可以安装、构建和启动
- 如果后续采集运行时出现环境兼容问题,优先升级到 Node 22
## 安装依赖
```bash
npm install
```
### 2. 配置文件
## 配置文件
首次使用需要创建配置文件
项目根目录下使用 `config.json` 作为运行配置文件
如果你还没有该文件,可以参考:
```bash
# 复制示例配置文件
cp config.example.json config.json
# 编辑配置文件(或通过 Web 界面配置)
# 填写邮件服务器信息和定时任务设置
```
**配置文件说明:**
需要重点配置的内容包括:
- `config.example.json` - 配置模板(不含敏感信息,可提交到 Git
- `config.json` - 实际配置(包含密码等敏感信息,已在 .gitignore 中忽略)
- `agent.baseUrl`
- `scheduler.enabled`
- `scheduler.cronTime`
- `email.smtpHost`
- `email.smtpUser`
- `email.smtpPass`
- `email.recipients`
## 使用方法
## 启动方式
### 1. 启动服务器
### 开发模式
前后端同时启动:
```bash
npm run dev
```
启动后地址如下:
- 前端开发服务:`http://localhost:5173`
- 后端 API 服务:`http://localhost:5000`
说明:
- Vite 前端会通过代理把 `/api` 请求转发到 `5000`
- 开发时建议直接访问 `http://localhost:5173`
### 生产模式
先构建前端,再启动 Express
```bash
npm run build
npm start
```
### 2. 访问界面
启动后访问:
打开浏览器访问: **http://localhost:5000** (或您配置的端口)
- `http://localhost:5000`
### 3. 功能介绍
说明:
**公告列表标签**
- `npm run build` 会把前端构建到 `dist/`
- `npm start` 会由 Express 托管 `dist/` 静态资源和 `/api`
- 快速查看所有公告
- 支持分页浏览
- 一键获取最新公告列表
**详情采集标签**
- 批量采集公告详情
- 支持按时间范围采集
- 自动提取预算金额
- 可自定义采集数量
**生成报告标签**
- 支持按时间范围生成报告
- 设置金额阈值筛选项目
- 实时统计项目信息
- 一键导出 Word/Markdown 报告
**定时任务标签** ⭐ 新增
- Web 界面配置定时任务
- 支持 Cron 表达式自定义执行时间
- 可选时间范围(今日/本周/本月)
- 设置金额阈值自动筛选
- 实时查看任务运行状态
- 立即测试运行功能
**邮件配置标签** ⭐ 新增
- Web 界面配置 SMTP 邮件服务
- 支持主流邮箱QQ、163、Gmail 等)
- 测试连接功能验证配置
- 支持多个收件人
- 自动发送精美 HTML 报告
## 报告示例
```markdown
# 南京公共工程建设项目报告
**生成时间**: 2025/12/12 11:00:03
## 统计摘要
- 总项目数: 10
- 超过 50 万元的项目: 3
- 总金额: 5395.50 万元
## 项目列表
### 1. 项目名称
- **发布日期**: 2025-12-12
- **发布时间**: 2025-12-12 10:35:00
- **预算金额**: 5000 万元
- **链接**: https://...
```
## API 接口文档
服务器启动后提供以下 RESTful API 接口:
### 1. 获取公告列表
```
GET /api/list?url=<列表页URL>&page=<页码>
```
参数:
- `url` (可选): 列表页 URL,默认为官网首页
- `page` (可选): 页码,默认为 1
### 2. 按时间范围获取列表
```
POST /api/list-daterange
Content-Type: application/json
{
"startDate": "2025-11-01",
"endDate": "2025-12-31",
"maxPages": 23
}
```
### 3. 批量获取详情
```
POST /api/details
Content-Type: application/json
{
"items": [{ "title": "...", "href": "...", "date": "..." }],
"limit": 10
}
```
### 4. 生成报告
```
POST /api/report
Content-Type: application/json
{
"url": "https://gjzx.nanjing.gov.cn/gggs/",
"limit": 15,
"threshold": 50
}
```
### 5. 按时间范围生成报告
```
POST /api/report-daterange
Content-Type: application/json
{
"startDate": "2025-11-01",
"endDate": "2025-12-31",
"threshold": 50,
"maxPages": 23
}
```
### 6. 获取配置
```
GET /api/config
```
返回当前配置信息(密码会被隐藏)
### 7. 更新配置
```
POST /api/config
Content-Type: application/json
{
"scheduler": {
"enabled": true,
"cronTime": "0 9 * * *",
"threshold": 100000,
"timeRange": "today"
},
"email": {
"smtpHost": "smtp.qq.com",
"smtpPort": 587,
"smtpUser": "your-email@qq.com",
"smtpPass": "your-password",
"recipients": "recipient@example.com"
}
}
```
### 8. 获取定时任务状态
```
GET /api/scheduler/status
```
### 9. 手动触发定时任务
```
POST /api/run-scheduled-task
```
## 定时任务配置
### 通过 Web 界面配置(推荐)
1. 访问 `http://localhost:5000` (或您配置的端口)
2. 切换到 **"定时任务"** 标签
3. 配置以下选项:
- **启用定时任务**:勾选启用
- **执行时间**:选择预设时间或自定义 Cron 表达式
- **时间范围**:今日/本周/本月
- **金额阈值**:设置最低金额(单位:万元)
4. 切换到 **"邮件配置"** 标签
5. 配置 SMTP 邮件服务器信息
6. 点击"测试连接"验证配置
7. 点击"保存配置",定时任务自动生效
### 通过配置文件
编辑 `config.json`
```json
{
"scheduler": {
"enabled": true, // 是否启用
"cronTime": "0 9 * * *", // Cron表达式每天9点
"threshold": 100000, // 金额阈值万元10亿
"description": "每天9点采集大于10亿的项目",
"timeRange": "today" // 采集范围: today/thisWeek/thisMonth
},
"email": {
"smtpHost": "smtp.qq.com", // SMTP服务器
"smtpPort": 587, // 端口
"smtpUser": "your@qq.com", // 发件邮箱
"smtpPass": "授权码", // QQ邮箱授权码
"recipients": "to@qq.com" // 收件人(多个用逗号分隔)
}
}
```
### Cron 表达式说明
格式:`分 时 日 月 周`
常用示例:
- `0 9 * * *` - 每天 9:00
- `0 9,18 * * *` - 每天 9:00 和 18:00
- `0 9 * * 1` - 每周一 9:00
- `0 9 1 * *` - 每月1号 9:00
- `0 */6 * * *` - 每 6 小时
### 邮件服务配置参考
**QQ 邮箱:**
- SMTP: `smtp.qq.com`
- 端口: `587`
- 密码: 使用授权码(在 QQ 邮箱设置中生成)
**163 邮箱:**
- SMTP: `smtp.163.com`
- 端口: `465`
- 密码: 使用授权码
**Gmail**
- SMTP: `smtp.gmail.com`
- 端口: `587`
- 需要开启"不够安全的应用访问"
## 服务器部署
### 方法 1使用 PM2推荐
## 常用脚本
```bash
# 安装 PM2
npm install -g pm2
# 启动服务
pm2 start src/server.js --name gjzx-scraper
# 查看状态
pm2 status
# 查看日志
pm2 logs gjzx-scraper
# 设置开机自启
pm2 startup
pm2 save
npm run dev
npm run build
npm run preview
npm start
```
### 方法 2使用 systemd
脚本说明:
创建服务文件 `/etc/systemd/system/gjzx-scraper.service`
- `npm run dev`:开发模式,前后端同时启动
- `npm run build`:构建前端生产包
- `npm run preview`:本地预览前端构建结果
- `npm start`:启动后端服务,并托管前端构建产物
```ini
[Unit]
Description=GJZX Scraper Service
After=network.target
## 页面说明
[Service]
Type=simple
User=your-user
WorkingDirectory=/path/to/tool-node
ExecStart=/usr/bin/node src/server.js
Restart=always
RestartSec=10
### 任务配置
[Install]
WantedBy=multi-user.target
```
- 管理抓取任务
- 支持单独运行和批量运行
- 支持查看运行状态
启动服务:
### 抓取结果
```bash
sudo systemctl enable gjzx-scraper
sudo systemctl start gjzx-scraper
sudo systemctl status gjzx-scraper
```
- 查看每次抓取生成的记录
- 支持按条件筛选
- 支持删除结果
### 注意事
### 项目管理
- **无需数据库**:项目采用无数据库架构,轻量部署
- **配置持久化**:所有配置保存在 `config.json` 文件中
-**进程保活**:使用 PM2 或 systemd 确保进程持续运行
- ⚠️ **防火墙**:确保配置的端口可访问(默认 5000
- ⚠️ **配置安全**:不要将 `config.json` 提交到公开仓库
- 对抓取出的项目做去重查询
- 支持金额和日期范围过滤
### 系统设置
- 配置 Agent 服务地址
- 配置定时任务
- 配置邮件发送参数
## 技术栈
- **后端**: Node.js + Express
- **爬虫**: Axios + Cheerio
- **定时任务**: node-cron
- **邮件服务**: nodemailer
- **前端**: 原生 HTML/CSS/JavaScript
- **编码处理**: iconv-lite (支持 GBK/UTF-8)
- **文档导出**: docx.js
- **架构**: 无数据库设计
- 前端Vue 3、Vite、Vue Router、Axios、Element Plus
- 后端Express
- 数据库better-sqlite3
- 调度node-cron
- 邮件nodemailer
## 项目结构
```
```text
.
├── src/
├── server.js # Web服务器及API
├── scheduler.js # 定时任务调度器
└── emailService.js # 邮件发送服务
├── public/
├── index.html # Web界面
└── app.js # 前端逻辑
├── config.json # 配置文件不提交到Git
├── config.example.json # 配置示例
├── package.json
└── README.md
├─ client/ # Vue 3 前端源码
├─ index.html
└─ src/
├─ api/
│ ├─ components/
├─ pages/
├─ router/
│ ├─ App.vue
│ ├─ main.js
│ └─ styles.css
├─ dist/ # Vite 构建产物
├─ src/ # Express 服务端
│ ├─ server.js
│ ├─ scheduler.js
│ ├─ resultStore.js
│ ├─ agentService.js
│ └─ emailService.js
├─ data/ # SQLite 数据文件目录
├─ config.json # 运行配置
├─ config.example.json # 配置示例
├─ package.json
├─ vite.config.js
└─ README.md
```
## 架构特点
## 数据说明
### 无数据库设计
- 任务数据和抓取结果保存在 SQLite
- 默认数据库路径位于 `data/results.sqlite`
- 配置数据保存在根目录 `config.json`
本项目采用**无数据库架构**,具有以下特点:
## 部署建议
- **轻量部署**:无需安装和配置数据库
- **实时数据**:每次从源站实时抓取最新数据
- **配置简单**:只需配置 config.json 文件
-**邮件归档**:报告通过邮件发送,邮箱即为历史记录
-**低资源消耗**:内存占用小,适合小型服务器
- 使用 PM2 或 systemd 保持进程常驻
- 通过反向代理暴露 `5000` 端口
- 不要把 `config.json``data/``.env` 提交到公开仓库
### 数据流程
## 备注
```
定时触发 → 抓取网站数据 → 解析提取 → 筛选过滤 → 生成报告 → 发送邮件
↑ ↓
└──────────────────── 配置文件 ──────────────────────────┘
```
## 注意事项
1. **采集速度**:已限制为每条延迟 500ms-1s避免请求过快
2. **域名支持**:仅支持 gjzx.nanjing.gov.cn 域名的详情页解析
3. **金额提取**:基于正则匹配,支持多种格式(预算金额、最高限价等)
4. **端口配置**Web 服务器默认端口 5000支持通过环境变量 PORT 修改
5. **智能停止**:按时间范围采集会在检测到所有公告早于起始日期时自动停止
6. **编码处理**:自动识别,支持 GBK 和 UTF-8 网页
7. **配置安全**config.json 包含敏感信息,已加入 .gitignore不要提交到公开仓库
8. **进程保活**:部署时使用 PM2 或 systemd 确保定时任务持续运行
## 核心功能说明
### 时间范围采集逻辑
按时间范围采集时,程序会:
1. 从第一页开始顺序采集
2. 检查每页公告的日期是否在指定范围内
3. 如果某页所有公告都早于起始日期,自动停止采集
4. 支持设置最大页数限制,避免过度采集
### 金额提取规则
支持识别以下格式:
- 预算金额: XX 万元
- 最高限价: XX 万元
- 预算: XX 万元
- 金额: XX 万元
- 直接数字: XX 万元
### 编码处理
自动识别网页编码:
- 优先读取 Content-Type 中的 charset
- 自动处理 GBK、GB2312 编码
- 默认使用 UTF-8
## 常见问题
### Q: 为什么采集速度比较慢?
A: 为了避免对服务器造成过大压力,程序限制了请求频率(每条延迟 500ms-1s。这是一个负责任的爬虫设计。
### Q: 如何采集指定日期范围的公告?
A: 在 Web 界面的"详情采集"和"生成报告"标签中勾选"按时间范围采集",然后输入起始和结束日期即可。
### Q: 导出的报告在哪里?
A: 点击"导出 Word"或"导出 Markdown"按钮后会自动下载到浏览器的默认下载目录。
### Q: 可以采集其他网站吗?
A: 需要修改 server.js 中的 BASE_URL 和相应的解析函数,因为不同网站的 HTML 结构不同。
### Q: 需要安装数据库吗?
A: **不需要!** 本项目采用无数据库架构,只需安装 Node.js 依赖即可运行。所有配置保存在 config.json 文件中,报告通过邮件发送。
### Q: 定时任务配置后不生效怎么办?
A: 请检查以下几点:
1. `config.json``scheduler.enabled` 是否为 `true`
2. 邮件配置是否正确SMTP 服务器、用户名、密码)
3. Node.js 进程是否持续运行(使用 PM2 查看状态)
4. 查看服务器日志是否有错误信息
### Q: 如何修改定时任务的执行时间?
A: 有两种方式:
1. **Web 界面**(推荐):访问网页,切换到"定时任务"标签,选择预设时间或自定义 Cron 表达式,点击保存
2. **配置文件**:编辑 `config.json` 中的 `scheduler.cronTime` 字段
### Q: 邮件发送失败怎么办?
A: 常见原因:
1. **QQ 邮箱**:需要使用授权码,不是登录密码(在 QQ 邮箱设置 → 账户 → POP3/SMTP 服务中生成)
2. **端口问题**QQ 邮箱使用 587某些邮箱可能需要 465SSL
3. **防火墙**:确保服务器可以访问 SMTP 端口
4. **测试连接**:在"邮件配置"标签中使用"测试连接"功能验证配置
### Q: 如何查看定时任务运行日志?
A: 如果使用 PM2 部署:
```bash
pm2 logs gjzx-scraper
```
如果使用 systemd
```bash
sudo journalctl -u gjzx-scraper -f
```
### Q: 服务器重启后定时任务还会运行吗?
A: 需要设置开机自启:
- **PM2 方式**:执行 `pm2 startup``pm2 save`
- **systemd 方式**:执行 `sudo systemctl enable gjzx-scraper`
### Q: 可以设置多个定时任务吗?
A: 当前版本只支持一个定时任务。如需多个任务,可以:
1. 使用 Cron 表达式设置多个时间点(如 `0 9,18 * * *` 表示每天 9:00 和 18:00
2. 部署多个实例,使用不同的配置文件和端口
## 更新日志
### v1.1.0 (2025-12-15)
- ✨ 新增定时任务功能node-cron
- ✨ 新增邮件推送服务nodemailer
- ✨ 新增 Web 配置界面(定时任务 + 邮件配置)
- ✨ 支持多时间范围(今日/本周/本月)
- ✨ 配置 API读取/更新配置)
- ✨ 定时任务状态查询
- ✨ 手动触发任务功能
- 📝 完善文档,新增部署指南
### v1.0.0 (2025-12-12)
- Web 可视化界面
- 支持按时间范围采集
- 支持分页浏览
- 支持导出 Word/Markdown 报告
- RESTful API 接口
- 自动编码识别
- 智能金额提取
## License
MIT
- 旧版 `public/` 页面已不再作为当前主前端入口
- 当前主前端以 `client/` 目录为准