# 南京公共工程建设中心 - 公告采集工具

一个用于采集南京公共工程建设中心公告信息的 Web 可视化工具，支持定时任务和邮件推送。

## 功能特性

- ✅ 采集公告列表(支持分页)
- ✅ 按时间范围智能采集
- ✅ 采集公告详情内容
- ✅ 智能提取预算金额
- ✅ 生成统计报告
- ✅ Web 可视化界面
- ✅ 导出 Word/Markdown 报告
- ✅ RESTful API 支持
- ✅ **定时任务自动采集**
- ✅ **邮件推送 HTML 报告**
- ✅ **Web 配置界面**
- ✅ **无需数据库，轻量部署**

## 快速开始

### 1. 安装依赖

```bash
npm install
```

### 2. 配置文件

首次使用需要创建配置文件：

```bash
# 复制示例配置文件
cp config.example.json config.json

# 编辑配置文件（或通过 Web 界面配置）
# 填写邮件服务器信息和定时任务设置
```

**配置文件说明：**

- `config.example.json` - 配置模板（不含敏感信息，可提交到 Git）
- `config.json` - 实际配置（包含密码等敏感信息，已在 .gitignore 中忽略）

## 使用方法

### 1. 启动服务器

```bash
npm start
```

### 2. 访问界面

打开浏览器访问: **http://localhost:5000** （或您配置的端口）

### 3. 功能介绍

**公告列表标签**

- 快速查看所有公告
- 支持分页浏览
- 一键获取最新公告列表

**详情采集标签**

- 批量采集公告详情
- 支持按时间范围采集
- 自动提取预算金额
- 可自定义采集数量

**生成报告标签**

- 支持按时间范围生成报告
- 设置金额阈值筛选项目
- 实时统计项目信息
- 一键导出 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
```

### 方法 2：使用 systemd

创建服务文件 `/etc/systemd/system/gjzx-scraper.service`：

```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` 提交到公开仓库

## 技术栈

- **后端**: Node.js + Express
- **爬虫**: Axios + Cheerio
- **定时任务**: node-cron
- **邮件服务**: nodemailer
- **前端**: 原生 HTML/CSS/JavaScript
- **编码处理**: iconv-lite (支持 GBK/UTF-8)
- **文档导出**: docx.js
- **架构**: 无数据库设计

## 项目结构

```
.
├── 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
```

## 架构特点

### 无数据库设计

本项目采用**无数据库架构**，具有以下特点：

- ✅ **轻量部署**：无需安装和配置数据库
- ✅ **实时数据**：每次从源站实时抓取最新数据
- ✅ **配置简单**：只需配置 config.json 文件
- ✅ **邮件归档**：报告通过邮件发送，邮箱即为历史记录
- ✅ **低资源消耗**：内存占用小，适合小型服务器

### 数据流程

```
定时触发 → 抓取网站数据 → 解析提取 → 筛选过滤 → 生成报告 → 发送邮件
   ↑                                                        ↓
   └──────────────────── 配置文件 ──────────────────────────┘
```

## 注意事项

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，某些邮箱可能需要 465（SSL）
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
