帮助首页 > 网站操作说明 · 9. 功能说明(不分前后端) > 招标采集与智能匹配操作说明

招标采集与智能匹配操作说明

招标信息采集与商家智能匹配系统 — 方案报告

一、目标与范围

1.1 业务目标

  • 招标源:以滁州市公共资源交易中心(Zz_ggzy.chuzhou.gov.cn)为典型,支持从类似政府招投标网站自动采集每日发布的招标信息。
  • 商家匹配:将采集到的招标信息根据本站商家(shop)的资质、业绩、人员等综合信息,自动匹配并推送给合适商家。
  • 扩展性:采集侧提供万能接口(可配置变量网址 + 条件1~条件10),数据驱动、可配置多站点多栏目,无需改代码即可接入新站点。

1.2 三大版块划分(建议实施顺序)

版块名称说明接口预留
版块一采集入库版块采集源配置、定时/手动采集、招标信息入库、采集日志。先做此版块。采集完成后调用「匹配触发接口」:传入本批新增的 tender_id 列表,供版块三拉取并执行匹配。
版块二商家信息版块商家资质、业绩、人员等扩展信息维护,形成「商家画像」。提供接口:按 shop_id 获取商家画像(文本或结构化),供版块三匹配时使用。
版块三AI 对接自动匹配版块调用 AI/规则引擎,将招标与商家画像匹配,写入匹配结果;商家端展示与操作。输入:tender_id 或招标摘要+类别;输出:匹配到的 shop_id 列表 + score + reason。依赖版块一的数据、版块二的画像接口。

版块一预留接口(供版块三调用)

  • 采集任务结束时,将本次新增的 tender_id 列表写入队列或调用 TenderMatchService::onNewTenders($tender_ids)(预留空实现,后续版块三实现具体匹配逻辑)。

版块二预留接口

  • getShopProfileForMatch($shop_id):返回该商家的资质、类型、业绩、人员摘要,用于匹配。

版块三预留接口

  • 由版块一在入库后调用:triggerMatchForTenders($tender_ids);内部可调用版块二的 getShopProfileForMatch 与 AI 服务,结果写入 by_tender_shop_match

1.3 系统范围(总览)

模块所属版块说明
采集配置版块一管理采集源(变量网址、条件1~10、列表/详情规则、采集时间等)
定时采集版块一按配置自动执行采集,写入本站数据库
招标信息库版块一存储标题、链接、发布时间、类别、正文等
采集日志版块一每次采集的起止时间、成功/失败条数
商家扩展信息版块二商家资质、业绩、人员等(预留表与接口)
AI 智能匹配版块三根据招标内容与商家画像计算匹配度并推荐(预留接口)
匹配结果表版块三tender_id, shop_id, score, reason, status(预留表)
推送与展示版块三商家端“推荐招标”列表与操作(预留)

后台入口:登录后台后,左侧菜单 「招标采集」→「采集管理」→「采集源设置」(即 Backstage/tendercollect/index)。若未显示菜单,请执行 数据库变更-招标采集-后台菜单.sql 或到 系统-菜单管理 中手动添加。


二、招标网站分析(以滁州公共资源交易中心为例)

2.1 网站结构概览

  • 站点:滁州市公共资源交易中心(ggzy.chuzhou.gov.cn)
  • 栏目:交易信息 → 工程建设(005001)、政府采购(005002)、土地矿权(005003)、国有产权(005004)、农村产权(005005)、其他交易(005006)、自主交易(005007) 等。
  • 工程建设子类(data-value):招标计划(005001014)、招标公告(005001003)、招标文件(005001005)、澄清修改(005001004)、开标记录(005001006)、中标候选人公示(005001007)、中标结果公示(005001008)、中标通知书(005001009)、合同订立(005001011) 等。

2.2 页面与数据特征

类型路径/形式说明
首页index.html入口,含交易信息等导航
列表页bussinessJSGC.html 等工程建设等,列表由 JS 加载(如 bussinessJsgc.js),模板含 visiturlinfoidtitleinfodate
详情页UUID.html / 数字ID.html正文页,meta 含 ArticleTite / ArticleTitle、PubDate、ContentSource,正文在 .ewb-article 或 .ewb-article-info
列表数据可能来自接口若站点提供列表 API,可配置为“接口采集”;否则用 HTML 解析

2.3 采集要点

  • 列表:需支持 HTML 抓取(如解析 iframe/JS 渲染后的 DOM)或接口 JSON(若可拿到列表 API)。
  • 详情:标题、发布时间、来源、正文为必备字段;可选:项目编号、预算、截止时间等(若页面有)。
  • 去重:以源站唯一标识(如 infoid + 来源站点)做唯一约束,避免重复入库。
  • 礼貌爬取:间隔请求、可配置 User-Agent、并发数,避免对目标站造成压力。

三、系统架构

┌─────────────────────────────────────────────────────────────────────────┐
│                           管理后台                                        │
│  采集源配置(万能接口) │ 招标列表/详情 │ 商家资质维护 │ 匹配规则 │ 日志   │
└─────────────────────────────────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  采集调度(Cron/队列)                                                     │
│  按 by_tender_collect_config 逐条执行:请求(变量URL+条件1~10) → 解析 → 入库  │
└─────────────────────────────────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  招标信息库(by_tender_info)                                              │
│  去重、状态(待匹配/已匹配)、原始URL、正文等                                 │
└─────────────────────────────────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  AI 匹配服务(内网 API 或第三方)                                           │
│  输入:招标标题+摘要+类别;商家:资质、类型、人员、业绩  → 匹配度 + 推荐理由  │
└─────────────────────────────────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  匹配结果(by_tender_shop_match)                                          │
│  tender_id, shop_id, score, reason, status(未读/已读/已报名)               │
└─────────────────────────────────────────────────────────────────────────┘
                    │
                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│  商家端(现有 shop 体系)                                                  │
│  “推荐招标”列表、详情、已读/报名操作                                        │
└─────────────────────────────────────────────────────────────────────────┘

四、万能采集接口设计

4.1 设计原则

  • 配置驱动:采集行为由数据库配置决定,不写死 URL 和参数。
  • 变量网址:支持占位符,如 {base_url}{category}{page}{date} 等,由执行时替换。
  • 条件 1~条件 10:对应 10 个可配置键值(如栏目编码、类型、地区),用于拼接到 URL 或请求体,或作为解析时的过滤条件。

4.2 采集源配置表(by_tender_collect_config)

字段名类型说明
idint, PK主键
namevarchar(128)采集源名称(如:滁州公共资源-工程建设招标公告)
site_domainvarchar(128)站点域名(用于去重、展示)
list_url_tplvarchar(512)列表页 URL 模板,支持变量 {base_url},{cond1}~{cond10},{page},{date}
detail_url_tplvarchar(512)详情页 URL 模板,如 {base_url}/{id}.html
list_typetinyint列表类型:1=HTML 列表页,2=API 列表
list_selectorvarchar(256)列表项选择器(CSS 或 JSONPath),如 .detailList a$.data.list[*]
list_link_attrvarchar(64)列表项链接属性,如 href 或 data-url
list_title_attrvarchar(64)列表项标题所在属性或文本节点
list_date_attrvarchar(64)列表项日期所在属性或文本节点
detail_selector_titlevarchar(128)详情页标题选择器,如 meta[name=ArticleTite].ewb-article h3
detail_selector_datevarchar(128)详情页发布时间选择器
detail_selector_contentvarchar(128)详情页正文选择器,如 .ewb-article-info
cond1~cond10varchar(128)条件 1~10 的值,对应替换 {cond1}~{cond10}
base_urlvarchar(256)基础 URL,替换 {base_url}
page_startint起始页码(默认 1)
page_maxint最大抓取页数
request_intervalint请求间隔(秒)
run_cronvarchar(64)Cron 表达式,如 0 8 * * * 表示每日 8 点
statustinyint0=禁用,1=启用
last_run_timeint上次执行时间
create_timeint创建时间
update_timeint更新时间

变量约定

  • {base_url} → base_url
  • {cond1}{cond10} → cond1~cond10
  • {page} → 当前页码
  • {date} → 当前日期 Y-m-d(可选)

示例(滁州工程建设列表若为接口):

  • list_url_tpl: https://ggzy.chuzhou.gov.cn/api/list?category={cond1}&page={page}
  • cond1: 005001003(招标公告)

若为 HTML:

  • list_url_tpl: {base_url}/bussinessJSGC.html
  • base_url: https://ggzy.chuzhou.gov.cn
  • list_selector 需根据实际 DOM 或 JS 返回结构配置(如 iframe 内列表或 data 接口)。

4.3 采集执行流程

  1. 定时任务:按 run_cron 触发,或后台“立即采集”按钮。
  2. 读取配置:只处理 status=1 的 by_tender_collect_config。
  3. 替换变量:用 base_url、cond1~cond10、page、date 生成实际 list_url。
  4. 抓取列表:根据 list_type 请求 HTML 或 API,用 list_selector 等解析出链接、标题、日期。
  5. 去重:用 source_id(站点+原始ID)查 by_tender_info,已存在则跳过。
  6. 抓取详情:对每条新记录用 detail_url_tpl 抓详情,解析标题、日期、正文,写入 by_tender_info。
  7. 写日志:记录 by_tender_collect_log(采集源 id、开始/结束时间、成功/失败条数、错误信息)。
  8. 触发匹配:采集批次结束后,对本次新增的招标执行“AI 匹配到商家”。

五、数据库设计

5.1 招标信息表(by_tender_info)

字段名类型说明
tender_idint, PK主键
collect_idint采集配置 id
source_idvarchar(64)源站唯一标识(如站点+infoid),唯一索引
titlevarchar(512)标题
urlvarchar(512)详情页 URL
publish_timeint发布时间(时间戳)
source_namevarchar(128)来源(如滁州市公共资源交易中心)
categoryvarchar(64)类别(如 招标公告、中标公示)
category_codevarchar(32)类别编码(如 005001003)
contentmediumtext正文(纯文本或 HTML,按需)
content_summaryvarchar(1024)摘要(用于匹配,可 200~500 字)
extra_jsontext扩展字段(JSON),如项目编号、预算、截止时间
match_statustinyint0=待匹配,1=已匹配
create_timeint入库时间
update_timeint更新时间

唯一索引:(source_id)(collect_id, source_id)

5.2 商家-招标匹配结果表(by_tender_shop_match)

字段名类型说明
idint, PK主键
tender_idint招标 id
shop_idint商家 id
scoredecimal(5,2)匹配度 0~100
reasonvarchar(512)推荐理由(AI 生成简短说明)
statustinyint0=未读,1=已读,2=已报名/感兴趣
read_timeint已读时间
create_timeint匹配时间

索引:tender_id, shop_id, (shop_id, status)。

5.3 商家扩展信息(用于匹配)

现有商家体系上扩展,便于 AI 使用:

  • by_shop:已有 shop_id, shop_name, cate_id, lixing(服务/工业/农业/建设/行政)等。
  • by_shop_details:已有简介、地址等,可增加“主营业务/资质简述”字段(或用现有 intro 等)。
  • by_shop_worker:员工列表;by_worker_qualificationby_worker_achievement:员工资质与业绩(已有表)。

建议新增(若暂无):

  • by_shop_qualification:商家级资质(如建筑业企业资质、行业许可),字段:shop_id, title, level, cert_no, valid_until, intro。
  • by_shop_achievement:商家业绩(项目名称、类型、金额、时间),字段:shop_id, title, category, amount, project_date, intro。

匹配时汇总:商家类型(lixing)+ 类目(cate)+ 商家资质 + 员工资质 + 员工业绩 + 商家业绩,形成“商家画像”文本或向量,与招标标题+摘要+类别做匹配。

5.4 采集日志表(by_tender_collect_log)

字段名类型说明
idint, PK主键
collect_idint采集配置 id
start_timeint开始时间
end_timeint结束时间
total_countint本批发现条数
new_countint新增入库条数
fail_countint失败条数
error_msgtext错误信息(汇总或最后一条)

六、AI 智能匹配设计

6.1 输入

  • 招标侧:title、content_summary(或正文前 N 字)、category/category_code。
  • 商家侧(聚合为“商家画像”文本或向量):

- 商家:shop_name, lixing, cate 名称、简介、主营业务。

- 资质:by_shop_qualification / by_worker_qualification 的 title、level、intro。

- 业绩:by_shop_achievement / by_worker_achievement 的 title、category、intro。

- 人员:可选,如“持证人员数量、专业方向”等摘要。

6.2 匹配方式(两种可选或组合)

  • 规则匹配

- 类别映射:如 工程建设(005001) → 优先推给 lixing=建设类 的商家。

- 关键词:招标标题/摘要含“装修”“消防”等 → 资质或业绩中含对应关键词的商家加分。

- 可配置规则表(by_tender_match_rule):规则类型、关键词/类别、权重、适用商家条件。

  • AI 匹配

- 将招标摘要 + 商家画像文本发给大模型(或本地模型),返回匹配度 0~100 + 一句话推荐理由。

- 或使用向量模型:招标摘要与商家画像分别向量化,计算相似度作为 score,再让 LLM 生成 reason。

6.3 输出与存储

  • 对每条新入库招标,筛选“可参与匹配”的商家(如 audit=1、closed=0、可选:已开通招标推荐服务)。
  • 调用匹配服务,得到 (shop_id, score, reason) 列表;过滤 score ≥ 阈值(如 60)的商家。
  • 写入 by_tender_shop_match,并更新 by_tender_info.match_status=1。
  • 推送:站内消息或微信模板(若已对接),通知商家“有 N 条与您匹配的招标”。

6.4 去重与频控

  • 同一 (tender_id, shop_id) 只保留一条匹配记录(最新一次匹配结果)。
  • 若招标更新后重新匹配,可先删除该 tender_id 的旧 match 再写入新结果,或按业务选择“仅对新招标匹配”。

七、实施步骤建议

阶段内容说明
1. 库表与配置后台建表 by_tender_collect_config、by_tender_info、by_tender_shop_match、by_tender_collect_log;商家扩展表(若需要);后台“采集源管理”CRUD、条件1~10 与变量说明先实现配置与存储,不跑真实采集
2. 采集引擎实现通用采集脚本/服务:读配置 → 变量替换 → 请求列表 → 解析 → 请求详情 → 入库;写日志;支持 HTML 与简单 API可先用滁州站一条配置做联调
3. 滁州站具体配置根据实际列表页(或接口)确定 list_url_tpl、list_selector、detail_url_tpl、detail_selector_*;若列表为 JS 渲染,可考虑内置无头浏览器或对接站点接口(若有)保证至少一个源稳定跑通
4. 定时任务Cron 或队列定时执行“已启用”的采集配置;失败重试与告警每日自动采集
5. 规则匹配实现类别/关键词规则表与规则引擎,输出 (shop_id, score, reason);写入 by_tender_shop_match先不用 AI 也能用
6. AI 对接封装“招标+商家画像→匹配度+理由”的 API;对接大模型或向量服务;将结果写入 by_tender_shop_match可替代或补充规则
7. 商家端展示商家后台/员工端“推荐招标”列表、详情、已读/报名;未读数量角标与现有 shop 权限体系对接
8. 推送与运营站内消息、可选微信模板推送;统计“查看率、报名率”便于优化规则与 AI按需

八、风险与注意点

  • 合规:采集仅用于本站商家服务,遵守目标站 robots.txt 与使用条款;不对外转卖原始数据。
  • 反爬:政府站可能改版或限频,需做请求间隔、错误重试、变更告警;若提供正式接口,优先用接口。
  • 数据质量:列表/详情选择器随站点改版可能失效,需有“采集质量巡检”或人工抽检,配置可快速调整。
  • AI 成本:若用按次计费的大模型,可对高匹配度候选再调 AI 生成理由,或仅对部分招标使用 AI,其余用规则。

九、附录:表结构 SQL 草稿(前缀 by_)

以下为关键表建表草稿,实际表名前缀以项目约定为准(如 by_)。

-- 采集源配置表
CREATE TABLE IF NOT EXISTS `by_tender_collect_config` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) NOT NULL COMMENT '采集源名称',
  `site_domain` varchar(128) DEFAULT NULL COMMENT '站点域名',
  `list_url_tpl` varchar(512) NOT NULL COMMENT '列表URL模板',
  `detail_url_tpl` varchar(512) DEFAULT NULL COMMENT '详情URL模板',
  `list_type` tinyint(4) DEFAULT '1' COMMENT '1=HTML 2=API',
  `list_selector` varchar(256) DEFAULT NULL,
  `list_link_attr` varchar(64) DEFAULT NULL,
  `list_title_attr` varchar(64) DEFAULT NULL,
  `list_date_attr` varchar(64) DEFAULT NULL,
  `detail_selector_title` varchar(128) DEFAULT NULL,
  `detail_selector_date` varchar(128) DEFAULT NULL,
  `detail_selector_content` varchar(256) DEFAULT NULL,
  `cond1` varchar(128) DEFAULT NULL,
  `cond2` varchar(128) DEFAULT NULL,
  `cond3` varchar(128) DEFAULT NULL,
  `cond4` varchar(128) DEFAULT NULL,
  `cond5` varchar(128) DEFAULT NULL,
  `cond6` varchar(128) DEFAULT NULL,
  `cond7` varchar(128) DEFAULT NULL,
  `cond8` varchar(128) DEFAULT NULL,
  `cond9` varchar(128) DEFAULT NULL,
  `cond10` varchar(128) DEFAULT NULL,
  `base_url` varchar(256) DEFAULT NULL,
  `page_start` int(11) DEFAULT '1',
  `page_max` int(11) DEFAULT '5',
  `request_interval` int(11) DEFAULT '2',
  `run_cron` varchar(64) DEFAULT NULL,
  `status` tinyint(4) DEFAULT '1',
  `last_run_time` int(11) DEFAULT NULL,
  `create_time` int(11) NOT NULL,
  `update_time` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='招标采集源配置';

-- 招标信息表
CREATE TABLE IF NOT EXISTS `by_tender_info` (
  `tender_id` int(11) NOT NULL AUTO_INCREMENT,
  `collect_id` int(11) NOT NULL,
  `source_id` varchar(64) NOT NULL COMMENT '源站唯一ID',
  `title` varchar(512) NOT NULL,
  `url` varchar(512) DEFAULT NULL,
  `publish_time` int(11) DEFAULT NULL,
  `source_name` varchar(128) DEFAULT NULL,
  `category` varchar(64) DEFAULT NULL,
  `category_code` varchar(32) DEFAULT NULL,
  `content` mediumtext,
  `content_summary` varchar(1024) DEFAULT NULL,
  `extra_json` text,
  `match_status` tinyint(4) DEFAULT '0',
  `create_time` int(11) NOT NULL,
  `update_time` int(11) NOT NULL,
  PRIMARY KEY (`tender_id`),
  UNIQUE KEY `source_id` (`source_id`),
  KEY `collect_id` (`collect_id`),
  KEY `publish_time` (`publish_time`),
  KEY `match_status` (`match_status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='招标信息';

-- 商家-招标匹配结果表
CREATE TABLE IF NOT EXISTS `by_tender_shop_match` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tender_id` int(11) NOT NULL,
  `shop_id` int(11) NOT NULL,
  `score` decimal(5,2) DEFAULT NULL,
  `reason` varchar(512) DEFAULT NULL,
  `status` tinyint(4) DEFAULT '0' COMMENT '0未读 1已读 2已报名',
  `read_time` int(11) DEFAULT NULL,
  `create_time` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `tender_shop` (`tender_id`,`shop_id`),
  KEY `shop_status` (`shop_id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='招标-商家匹配结果';

-- 采集日志表
CREATE TABLE IF NOT EXISTS `by_tender_collect_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `collect_id` int(11) NOT NULL,
  `start_time` int(11) NOT NULL,
  `end_time` int(11) DEFAULT NULL,
  `total_count` int(11) DEFAULT '0',
  `new_count` int(11) DEFAULT '0',
  `fail_count` int(11) DEFAULT '0',
  `error_msg` text,
  PRIMARY KEY (`id`),
  KEY `collect_id` (`collect_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='招标采集日志';

以上为招标采集与商家智能匹配的完整方案设计,可直接作为评审与开发依据。若需要先落地“采集配置 + 单源采集 + 规则匹配”的最小闭环,可优先做第二、四、五、七阶段;AI 与推送后续迭代。

copyright 2013-2113 www.baoanfuwu.cn All Rights Reserved 保安服务网版权所有
皖ICP备2021016109号-1