# 南京公共工程建设中心 - 公告采集工具 一个用于采集南京公共工程建设中心公告信息的 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:3000** ### 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:3000` 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 确保进程持续运行 - ⚠️ **防火墙**:确保 3000 端口可访问 - ⚠️ **配置安全**:不要将 `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 服务器默认端口 3000,可在 server.js 中修改 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