陕西采购情报监控(陕西省政府采购网)
每日监控陕西全省「办公用品 / 服务器 / 商用电脑 / 耗材」四类采购公告, 输出数据内联的自包含 HTML 看板(趋势图 + 品类分布 + 明细表,支持搜索/筛选/排序)。
目录结构(所有路径都以本 skill 目录为根,开箱即用)
scripts/collect.py—— 采集 + 过滤 + 去重 + 落盘(含验证码自动识别)scripts/render_dashboard.py—— 渲染output/dashboard.htmlscripts/config.json—— 关键词表 / 排除词 / 数据源 / 区域代码,全部可改data/history.json—— 累积去重库(跨天保留,首次运行自动生成)data/items_<日期>.json—— 当次快照output/dashboard.html—— 看板产物requirements.txt—— Python 依赖
首次安装
python3 -m venv .venv
./.venv/bin/pip install -r requirements.txt
./.venv/bin/playwright install chromium # 仅剑鱼源需要;不开剑鱼可跳过
每日执行(定时任务实际就这两条命令)
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}¬iceId={id} - 区域代码表:
https://www.ccgp-shaanxi.gov.cn/cms-sx/site/shanxi/resources/json/sxTree.json(regionCode: ""= 全部,610001= 省本级,各地市如610100西安、610200铜川…)
2. 剑鱼标讯 —— 默认关闭,保留代码备用
- 有 JS 反爬(指纹 + RSA token 挑战页),纯 requests 拿不到数据,必须 Playwright 渲染。
- 没有 URL 级地区过滤(
?area=/?province=无效,分站/list/...404), 只能抓全国结果再按列表项第一个标签(省份)过滤,命中率 1%~3%。 - 关键词是全文模糊匹配,不是标题匹配:实测噪声约 88%("黄砂采购"会命中"笔记本电脑")。
因此默认
require_title_match = true,只保留标题含关键词者。 - Playwright 连续请求会被风控:关键词页退化成挑战页(
.liLuceneList数量为 0)。 故config.json里jianyu360.enabled默认 false。 - 想要真正的「按地区 + 按品类」精准检索,只能走官方付费 API
https://api.jianyu360.com/data/getdata(需 appid + key,支持area过滤); 拿到凭据后在JianyuSource里换成 API 直连即可。
常用调整
| 需求 | 做法 |
|---|---|
| 加减关键词 | 改 config.json 的 categories;剑鱼源要同步补 keyword_slugs 拼音映射 |
| 排除误命中词 | 改 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),可直接双击打开或分享,无需起服务。
Scan to join WeChat group