DToo 陕采雷达 · 陕西政采每日监控看板
每日监控陕西全省「办公用品 / 服务器 / 商用电脑 / 耗材 / 信息化 / 运维 / 安全 / 集成 / 软件开发 / 办公设备 / 打印机」11 类采购公告,
数据源为陕西省政府采购网(主力,权威、全省、带预算金额)+ 剑鱼标讯陕西分站(补充),
输出数据内联的自包含 HTML 看板(趋势图 + 品类分布 + 明细表,支持搜索/筛选/排序)。
目录结构(所有路径都以本 skill 目录为根,开箱即用)
scripts/bootstrap.py—— 跨平台引导脚本(自动建 venv、装依赖、采集、渲染、打开看板)scripts/collect.py—— 采集 + 过滤 + 去重 + 落盘(含验证码自动识别)scripts/render_dashboard.py—— 渲染output/dashboard.htmlscripts/config.json—— 关键词表 / 排除词 / 数据源 / 区域代码,全部可改data/history.json—— 累积去重库(跨天保留,首次运行自动生成)data/items_<日期>.json—— 当次快照output/dashboard.html—— 看板产物requirements.txt—— Python 依赖
最快上手:引导脚本(推荐,一个命令三平台通用)
python scripts/bootstrap.py # 采集 + 渲染(近 7 天),完成后自动打开看板
python scripts/bootstrap.py doctor # 环境自检(依赖/网络/数据源),出问题先跑这个
python scripts/bootstrap.py 14 # 采集近 14 天
python scripts/bootstrap.py setup # 仅准备环境(建 .venv + 装依赖)
python scripts/bootstrap.py --no-open # 跑完不自动打开浏览器
> Windows 上若 python 不可用,用 py -3 scripts/bootstrap.py。
> 该脚本只用标准库,无需预装第三方包;首次运行自动建 .venv 并装依赖(约 1~3 分钟),
> 之后每次约 2~3 分钟(采集本身耗时)。
>
> 为什么不用 run.bat / run.sh:一是 skill 市场(SkillHub 等)通常不允许上传
> 可执行脚本类文件(.bat/.sh/.exe),二是两套脚本要分别维护。
> 用 .py 引导脚本,一个文件覆盖三平台,且天然被平台接受。
环境自检 doctor(强烈建议首次运行先跑)
python scripts/bootstrap.py doctor # 或 python scripts/collect.py --doctor
它会逐项检查并给出可操作结论:
- Python 版本、系统架构、解释器路径、skill 目录
- 5 个必需依赖是否可导入
- 两个数据源域名是否可达(HTTP 状态码)
- 数据源实测:剑鱼栏目页能否解析出条目 + 陕采验证码 OCR 能否识别出 4 位
全部通过会打印「环境就绪,可以正常采集 ✅」,否则逐条列出问题与修复命令。
跨平台兼容性说明(Windows 为主)
| 风险点 | 处理方式 |
|---|---|
Windows 控制台默认 GBK,打印中文报 UnicodeEncodeError |
三个脚本(bootstrap/collect/render)启动时都把 stdout/stderr 切到 UTF-8(reconfigure) |
python3 命令在 Windows 不存在 |
引导脚本用 sys.executable 自举,用户用 python 或 py -3 启动均可;文档中已注明 |
venv 路径不同(Windows Scripts\,Unix bin/) |
bootstrap.py 按 platform.system() 自动选择 Scripts/python.exe 或 bin/python3 |
市场不允许上传 run.bat/run.sh |
已改为纯 .py 引导脚本 scripts/bootstrap.py,一个文件覆盖三平台 |
ddddocr 依赖 numpy/onnxruntime/opencv-python/Pillow,Windows 上可能装不上 |
① CaptchaSolver 做防御性加载,失败时给出中文修复提示而非崩溃;② 陕采源整体降级(跳过陕采、继续跑剑鱼),不会让采集中断;③ 建议用 64 位 Python 3.10+;④ 提供国内镜像命令 |
| 路径分隔符 | 全程 os.path.join,无硬编码 / 或 \ |
| 文件编码 | 所有 open() 显式 encoding="utf-8" |
| 打开看板的方式不同 | bootstrap.py 按平台用 os.startfile / open / xdg-open,失败也不影响主流程 |
移植到其他智能体 / 其他机器(已验证)
本 skill 是自包含的,整套目录拷走即可用,无需改动代码:
- 拷目录:把整个
shaanxi-procurement-monitor/复制到目标机器的 skills 目录
(WorkBuddy 用户级~/.workbuddy/skills/,或项目级{workspace}/.workbuddy/skills/)。 - 跑引导脚本:
python scripts/bootstrap.py。首次会自动建.venv并装依赖。 - 若失败:先跑
python scripts/bootstrap.py doctor看具体哪项不通过,按提示修复。
已验证的兼容性事实:
- 脚本内无任何硬编码绝对路径,全部基于
os.path.dirname(os.path.abspath(__file__))解析,
换目录、换用户名、换机器都不受影响。 - 必需依赖仅 5 个:
requests、beautifulsoup4、lxml、pycryptodome、ddddocr。 bootstrap.py已实测从零自举:用系统 Python(3.14.6)自动创建.venv并装齐 5 个依赖,
随后完整跑通「采集 109 条 → 渲染 92 条明细 → 看板生成」。- 已用全新 venv + 空 data/output 目录做过端到端实测:采集 → 渲染 → 看板内联数据校验通过。
- 首次运行会自动生成
data/history.json,无需预置数据。 - 需要联网(
ccgp-shaanxi.gov.cn+shaanxi.jianyu360.cn)。 - 定时任务不绑定平台:在其他智能体上同样用「
python scripts/bootstrap.py+ present_files
打开 output/dashboard.html」即可复刻整套工作流。
> 迁移注意:data/history.json 是跨天累积库,建议一起带走(保留历史与 first_seen,
> 看板趋势图才有历史数据);若想要干净起点,删掉 data/*.json 即可,脚本会自动重建。
> .venv/ 不要打包(体积 300MB+,且与平台绑定),到目标机器由 bootstrap 自动重建。
手动执行(不使用引导脚本时)
python -m venv .venv
# Windows: .venv\Scripts\pip install -r requirements.txt
# Unix: ./.venv/bin/pip install -r requirements.txt
# 自检 → 采集 → 渲染
python scripts/collect.py --doctor
python scripts/collect.py --days 7
python scripts/render_dashboard.py --days 7
每日执行(定时任务实际就这两条命令)
PY=./.venv/bin/python3 # 换成你的 venv 解释器
$PY scripts/collect.py --days 7
$PY scripts/render_dashboard.py --days 7
跑完用 present_files 打开 output/dashboard.html。
注册"每天早上 8 点"自动任务
用 automation_update 建 recurring 任务,rrule=FREQ=DAILY;BYHOUR=8;BYMINUTE=0,
prompt 里写死本 skill 目录的绝对路径(替换 <SKILL_DIR> 和 <PY>):
采集陕西省政府采购网近 7 天公告(办公用品/服务器/商用电脑/耗材),生成 HTML 看板。
1) <PY> <SKILL_DIR>/scripts/collect.py --days 7
2) <PY> <SKILL_DIR>/scripts/render_dashboard.py --days 7
3) present_files 打开 <SKILL_DIR>/output/dashboard.html
4) 中文汇报:新增条数、分类分布、预算合计、金额 TOP3 项目名称与链接。
容错:偶发验证码/SSL 失败导致某关键词命中 0 属正常;若全部失败则说明官网改版或 IP 被限,如实说明。
两个数据源的逆向结论(改动前必读)
1. 陕西省政府采购网 —— 主力源,全省覆盖,权威
- 列表接口:
GET https://www.ccgp-shaanxi.gov.cn/freecms/rest/v1/notice/selectInfoMoreChannel.do - 关键参数:
siteId=a7a15d60-de5b-42f2-b35a-7e3efc34e54f、channel=1eb454a2-7ff7-4a3b-b12c-12acc2685bd1、
noticeType=00101,001011、regionCode=(空字符串 = 陕西全省,填610001只查省本级)、
title=关键词、operationStartTime/EndTime(YYYY-MM-DD HH:MM:SS)、selectTimeName=noticeTime - 必须带三个签名头,否则一律被拒:
sign = md5(sha1("${毫秒时间戳}_${接口路径}_bosssoft_platform_095285"))nsssjss = RSA-PKCS1v15 加密("${接口路径}$$${毫秒时间戳}")(注意$$与时间之间没有空格),公钥见config.jsontime= 毫秒时间戳;url= 接口路径(不含 query)- 验证码必填:
GET /freecms/verify/verifyCode.do?createTypeFlag=n&name=notice&d=<毫秒>返回 73×27 JPEG,
用 ddddocr 识别后作为verifyCode传入。必须复用同一 Session(JSESSIONID),验证码一次性,
失败返回{"code":"-1","msg":"验证码错误或已失效..."},脚本内置重试。 - 接口直接返回结构化字段,别再从标题正则里抠:
budget预算(单位:元,÷10000 转万元)、successfulMoney中标金额purchaser采购单位、purchaserAddr/LinkMan/LinkPhone地址与联系人电话agency代理机构、openTenderTime开标时间、catalogueNameList采购品目noticeTypeName/transactionType实测为null,公告类型要从标题推断
(collect.guess_notice_type:中标/成交、废标/终止、更正/变更、合同、竞争性磋商/谈判、询价、单一来源、采购意向、公开招标)- 详情页拼接:
{pageurl}?noticeType={noticeType}&noticeId={id} - 区域代码表:
https://www.ccgp-shaanxi.gov.cn/cms-sx/site/shanxi/resources/json/sxTree.json
(regionCode: ""= 全部,610001= 省本级,各地市如610100西安、610200铜川…)
2. 剑鱼标讯 —— 已启用,走陕西分站栏目页(2026-09 站点改版后重写)
- 站点已改版:
www.jianyu360.cn新版搜索页是 Vue SPA,列表接口POST /jyapi/jybx/core/fType/searchList
返回antiEncrypt:1的 AES 加密体;页面带 fid 指纹 SDK + 登录插件。UI 点选筛选在 headless 下不生效,
Playwright route 改写 post_data 会导致请求不发(疑似指纹校验)。不要再走这条路。 - 可靠路径 = 陕西分站行业栏目页:
https://shaanxi.jianyu360.cn/{section}/,分页/{section}_{page}/。 - 纯服务端渲染(SEO 页),requests 直连即可,无 JS 挑战、无加密、无风控拦截。
- 每页 20 条,按日期倒序;列表项
li.card-bid-item > a.item-title,行尾文本含YYYY-MM-DD。 - 天然只含陕西公告(省份已隔离),无需再按标签过滤。
- 已启用栏目(
config.json → jianyu360.sections):xxjs信息技术 /xzbg行政办公 /
rdaf弱电安防 /fwcg服务采购。其余栏目(jzgc/slsd/nyhg/jxsb/jtgc/ylws/szss/nlmy)与本监控品类相关性低。 - 分站没有全量聚合列表页(
/list/、/all/、/index_2/均 404),也没有/list/keywords/{slug}.html
(404),所以只能按行业栏目抓取 + 本地标题关键词过滤。 - 实现:
JianyuSource一次性把各栏目近 N 天条目抓成内存"栏目池"(_load_pool),
再让每个关键词在池里做标题匹配(fetch)。因此 32 个关键词只触发约 4×9=36 次 HTTP,不会重复请求。 - 风控:连续快速请求会
SSLEOFError/ 连接被断。_fetch_page已内置 3 次重试 + 指数退避
(1.2~2.4s×attempt),翻页之间sleep(0.35~0.75s)。偶发单页失败只影响该页,不中断整体。 - 金额:分站列表页不披露金额(
_money_tag为空),剑鱼条目的amount恒为None,
看板显示—。要金额只能进详情页或改用官方付费 API。 - 官方付费 API 仍是终极方案:
https://api.jianyu360.com/data/getdata(需 appid + key,支持 area 过滤)。
旧版结论(已失效,仅存档)
- 旧版
www.jianyu360.cn/list/keywords/{slug}.html关键词页:全国结果 + 首标签省份过滤,实测陕西命中率约 1%
(300 条里 3 条),且需 Playwright 完整渲染(wait_until=networkidle常超时,改用domcontentloaded+长等待)。
该页现在仍可访问但命中率极低,已被分站栏目页方案取代。
常用调整
| 需求 | 做法 |
|---|---|
| 加减关键词 | 改 config.json 的 categories 即可(剑鱼已改为本地标题过滤,不再需要 keyword_slugs) |
| 调整剑鱼栏目/翻页 | jianyu360.sections(栏目代码)、section_pages(每个栏目翻几页,默认 9 ≈ 近 7 天) |
| 排除误命中词 | 改 exclude_keywords(标题含这些词直接丢弃) |
| 只看某个地市 | sources.shaanxi_gov.region_code 改成对应代码(查 sxTree.json);留空 = 全省 |
| 拉长观察窗口 | collect.py --days N 与 render_dashboard.py --days N 保持一致 |
| 清洗历史库 | collect.py --purge-history(按当前规则重筛 history.json,不采集) |
| 跳过/只跑单源 | collect.py --skip-jianyu 或 --only gov / --only jianyu |
已知边界
- 陕采接口每次请求都要刷新验证码,25 个关键词全量约 1.5–2 分钟。
- 金额约 70%~85% 的公告会披露(
budget),其余显示—属正常。 - 中文关键词歧义要主动排除:「工作站」既是设备名也是机构名,实测 8 条命中 7 条是机构名,
现已换成「图形工作站 / 移动工作站」并配exclude_keywords。新增关键词务必先跑一遍验证。 - 医疗/试剂类会命中「耗材」(如血站试剂耗材 540 万);若只做办公耗材,
往exclude_keywords加「试剂」「医疗器械」即可——按业务口径自行决定。 - 看板是自包含单文件(数据内联进 HTML),可直接双击打开或分享,无需起服务。