ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从零搭建跨平台信号监控系统:PLFM_RADAR 实战复盘

从零搭建跨平台信号监控系统:PLFM_RADAR 实战复盘

做独立开发和产品运营这几年,我手机里装过的监控类工具一只手数不过来:盯竞品变动要刷应用商店评论区,盯行业风向要逛技术社区,盯用户反馈要翻论坛和群消息。麻烦的地方在于每个平台都要单独登录、单独刷,信息散得跟撒了一地似的,真正有价值的变化常常淹没在每天几百条更新里。后来我断断续续花了几周空余时间,从零写了一个叫 PLFM_RADAR 的小系统,把“每个平台都去看”这件事收敛成一套统一逻辑:采集、清洗、分析、告警,全部自动化。

PLFM_RADAR 这个名字是按我的习惯拆的:PLFM 是 Platform 的缩写,RADAR 就是雷达。合起来的含义很直白——平台雷达,专门用来扫描多个线上平台的关键信号,识别值得关注的异常变化,然后第一时间推送提示。它能处理的具体场景包括:某个开源项目热度是不是开始降温,技术社区里有没有人集中讨论你所在的方向,竞品产品页是不是悄悄改了描述,目标关键词在近几个小时的讨论量是不是突然抬头。如果你在做独立开发、内容运营、产品增长或者任何偏情报分析的工作,这篇文章就是 PLFM_RADAR 从命名到落地的完整复盘。我会把架构设计、数据采集、信号打分、告警通道以及踩过的坑都摆出来,方便你在自己的场景里直接改造复用。

1. PLFM_RADAR 到底在解决什么问题

1.1 先想清楚:你缺的其实不是信息,而是“信号”

项目启动之前,我给自己列过一张“每天要刷的清单”:GitHub Trending、几个技术社区的讨论区、行业产品的更新日志、应用商店的用户评论、若干个关键词的搜索结果。真正执行起来才发现,每天两小时都未必刷得完,而且大部分时间是在重复翻看没有变化的内容。信息从来都不缺,缺的是把“发生了某件事”从信息流里及时捞出来的能力。

系统要做的事,本质上是把“信息”转化成“信号”。信息是持续流动的原始数据,信号则是其中值得你停下手里的事去关注的变化点。PLFM_RADAR 的思路就是模仿雷达的工作原理:持续发射扫描请求,接收各平台返回的“回波”,过滤掉大量不变的背景噪声,只把“新出现的、符合关注条件的对象”标记出来。这也是我决定不靠人工盯屏,而是写一套自动化系统的最核心理由。

另一个出发点是成本。市面上做情报监控的 SaaS 不是没有,但要么按关键词数量收费、要么数据只存在于对方平台、要么定制一个字段就要等排期。对于个人开发者或者三五人的小团队来说,自己搭一套轻量系统,虽然前期要花一些时间,但后续的每一处改动都掌握在自己手里,数据模型、告警规则、展示维度都能按自己的需求生长。

1.2 三种常见玩法:信息雷达、信号雷达、运营雷达

同一个 PLFM_RADAR 的框架,放在不同人手里可以玩出不一样的效果。我把它总结成三种典型用法,你可以对照自己的角色来选。

玩法关注的核心信号适合人群典型输出
信息雷达指定平台的新增内容、更新动态独立开发者、内容从业者每日新增列表、更新提醒
信号雷达关键词异动、讨论热度突变、竞品变化产品经理、市场运营、研究员实时告警、趋势报告
运营雷达用户反馈关键词、口碑变化、需求线索运营人员、客服负责人问题聚类、需求热度排行

我做这套系统时优先覆盖的是“信号雷达”场景,因为它的收益最直观:不用再每天手动刷几十个页面,系统会在我睡觉的时候盯着,早上起来只推送那些真正有变化的条目。后来给一位做电商选品的朋友改了一套配置,他把采集源换成了几个行业论坛和商品评论页,关注词换成了品类词加痛点词,就变成了一套完全不同的选品情报雷达。这说明核心代码其实高度通用,差异主要在采集源的配置和打分规则上。

2. 整体架构与方案选型解析

2.1 分层架构:采集层、清洗层、分析层、消费层

PLFM_RADAR 的整体结构我一开始就定了四层,没有多犹豫,因为这种分层对应的是数据生命周期里最自然的四个阶段。

  • 采集层负责从各平台拉取原始数据,统一封装成“源记录”,不管来源是 API、RSS 还是页面解析,对外暴露的接口是一样的。
  • 清洗层负责去重、补全、规范化,把不同平台的字段统一成同一个 schema,比如统一时间格式、统一作者字段、统一内容摘要。
  • 分析层是雷达的核心,它把清洗后的数据放到规则引擎和打分模型里跑一遍,判断哪些条目应该升级为“信号”,哪些只是噪声。
  • 消费层负责信号的出口,包括告警推送、可视化面板、每日摘要邮件和数据归档。

用雷达来类比就很容易理解:采集层是天线和收发机,清洗层是回波信号的前端处理,分析层是目标识别算法,消费层是操作员面前那块显示屏。每一层之间只通过规定的数据格式通信,所以替换任何一层都不会影响其他层。比如我后期把告警通道从邮件换成了 Webhook,只动了消费层,其他三层完全没改。

2.2 技术选型:Python + SQLite + Flask 这套组合的取舍

技术栈的选择上,我走的是一条“够用且好维护”的路线,没有追逐复杂组件。核心组合是 Python、SQLite、Flask 加几个轻量库,整套系统跑在一台 2 核 4G 的云主机上,资源占用非常低。

选 Python 基本不需要解释,requests 做 HTTP 拉取、BeautifulSoup 做页面解析、schedule 做定时任务、pandas 做分析计算、Flask 做展示层,一条链路都是成熟生态,写起来快,出问题也好查。SQLite 是很多人会纠结的点:为什么不用 MySQL 或者 PostgreSQL?我的判断是,这个系统的数据量在单机场景下完全在 SQLite 的能力范围内。我跑了三个月,累计几十万条原始记录、几万条信号,SQLite 一个文件就能装下,查询速度依然毫秒级,而且备份就是拷贝一个文件,省去了数据库运维的负担。如果你后续要上多节点采集或者要做复杂的并发分析和报表,再迁到 PostgreSQL 也不迟,因为数据模型已经设计好了,迁移成本很低。

Flask 承担的是可视化面板和 Webhook 接收端的角色。它足够轻,一个进程就够,不需要引入前后端分离的工程结构。展示层我只做了少数几个页面:今日信号、趋势折线、雷达图、历史回看。后期有些朋友建议我用 Django,但对我来说 Flask 的简洁性本身就是生产力,多出的功能用不上反而是负担。

2.3 为什么不用现成的监控工具

在动手写代码之前,我认认真真评估过一轮现成工具,结论是不能满足我需要的那种“信号研判”。

舆情监控类 SaaS 的功能通常很全,但定价是按关键词数量和采集平台数量走的,个人承担起来偏贵,关键点是数据模型是黑盒,它不会告诉你“这条信号为什么触发了”,而 PLFM_RADAR 的分析层必须能解释每个信号的得分来源。另一个现实限制是数据主权,采集结果放在第三方平台上,想导出做自己的历史分析比较困难。

开源的采集框架和自动化工具我也试过两三个,它们擅长的是“触发-执行”型的流程编排,比如检测到某个页面变了就执行一个爬虫任务、发一条通知。这类工具在规则简单时很好用,但一旦涉及“多个维度加权打分”“滚动窗口均值对比”“信噪比调优”这些分析逻辑,就明显力不从心了。它们缺的是一个以“信号”为中心的数据模型,所以我最终决定自己搭这套系统,把数据模型和分析权利都握在自己手里。

3. 数据采集层实操:从零接入多平台信号

3.1 采集源分类:先把数据来源梳理清楚

采集层是所有后续环节的原料入口,这一层如果设计得乱,后面清洗和分析都会很痛苦。我采用的分类方式是按数据获取方式区分,因为不同获取方式决定了采集代码的写法、更新频率以及出错处理策略。

  • 直接 API 型:源平台提供公开 API,返回结构化 JSON。典型包括 GitHub API、Hacker News API、Product Hunt API。这类源最容易处理,解析稳定、字段完整,是首选的采集方式。
  • 结构化订阅型:源平台提供 RSS/Atom 订阅,虽然不是官方 API,但同样是标准格式,用 feedparser 解析非常方便。很多技术博客、社区公告、更新日志都保留了 RSS 输出,可以直接利用。
  • 页面解析型:源平台没有 API 也没有 RSS,只能请求页面后用解析器提取关键信息,比如产品介绍页的修改时间、商店评论区的最新评论。这类源需要额外小心,后续我会专门说限制问题。

分类完以后,我维护了一张源配置表,每条源记录包含源名称、类型、请求 URL、解析规则、更新频率、是否启用。解析规则用 JSON 存,字段有 selector、attribute、regex 等几种类型。这样新增一个采集源时不需要改代码,只要往配置表里加一行,再写一个对应解析函数,或者写一个通用的解析模板就可以。

3.2 采集频率和增量策略怎么定

采集频率是个看起来很随便、实际上很有讲究的参数。频率太高会被源站限流,频率太低又会错过信号的时效性。我的经验不是一刀切,而是按源的重要性和数据更新速度分别设置。

  • GitHub 相关源:每 6 小时一次快照,因为仓库热度和趋势本来就是日级别的波动,没必要每小时刷。
  • Hacker News 这类活跃社区:每 1 小时采集一次,标题和分数变化是小时级别的。
  • 产品页、落地页:每 4 小时拉一次,同时记录响应体哈希值,如果哈希没变就不入库,这样能显著减少无效数据。
  • 应用商店评论、论坛新帖:每天拉一次新增条目,因为这类内容不追求分钟级告警,更看重完整性。

增量策略的核心是“增量游标”。API 型源通常返回 id 或 updated_at 字段,我记录了每个源当前处理到的最大游标,下次采集只取大于游标的数据。RSS 型源用条目的发布时间做过滤窗口,只处理最近 24 小时内的新条目。页面解析型源用内容哈希做判断,页面没变就不存,页面变量再解析差异。这套策略跑下来,重复数据量能压掉八成以上,入库压力小了很多。

3.3 限流、反爬与合规边界:这几个坑绕不开

采集层最容易翻车的地方不是代码,而是对源平台的规则缺乏敬畏。我自己的原则有三条:只采公开数据,不做任何绕过登录态的采集;严格遵守每个源公开的速率限制;对源站的 robots 约定保持基本的尊重。

以 GitHub 为例,它的 API 对普通请求有每小时 5000 次的限制,这个额度对监控场景来说完全充裕,我实际只用到几百次。但如果不做任何节流直接高并发请求,还是会触发 403。代码里我用了一个简单的限速器,每个源请求之间至少间隔一个固定秒数,并且加随机抖动,避免出现准点齐射式的请求特征。同时也给每个请求设置了合法的 User-Agent,标注到项目地址,这样如果源站管理员看到日志,也知道我是正常的监控用途。

这个部分一定不能省。我见过有人在一个小型论坛上每分钟抓一次页面,结果 IP 被封,连正常访问都受影响。PLFM_RADAR 的价值是让它“持续、安静、不出格”地运行,而不是给自己惹麻烦。

3.4 数据表结构设计:一个可以扛三个月演进的设计

采集层的数据模型我用了四张核心表,实际运行下来改动很少,说明这个设计站得住。

  • sources 表:源配置,字段包括 id、name、type、url、parse_rule、interval_minutes、enabled。
  • raw_items 表:原始数据,统一 schema,字段包括 id、source_id、external_id、title、content、author、url、published_at、created_at。
  • seen 表:去重表,记录已经处理过的外部条目标识,字段就两个,external_key 和 first_seen_at,配合唯一索引使用。
  • signals 表:分析层输出的信号,字段包括 id、raw_item_id、keyword、rule_id、score、signal_type、created_at。

schema 设计的关键点是 raw_items 表尽量用“宽表加 JSON 扩展”的方式,核心字段全部显式建列,方便检索和统计;各平台特有字段统一塞进一个 extra 字段存 JSON,避免频繁加列。seen 表是去重的关键,external_key 用“源名 + : + 外部ID”拼接,保证不同平台之间不会误判为同一条内容。

4. 信号分析层:把采集回来的噪音变成可执行的情报

4.1 关键词规则与信号分类

采集层解决的是“有没有新东西”,分析层解决的是“新东西值不值得你看”。PLFM_RADAR 的分析层围绕规则引擎和打分模型展开,这是整个系统里最值得花时间调优的部分。

规则引擎我用的是“关键词规则表”加“评分算子”的组合。关键词规则表长这样:每条规则包含关键词、作用域(title、content、author 任意组合)、运算方式(包含、正则匹配、组合匹配)、权重分。比如我配置过这样几条规则——关键词“PLFM_RADAR”作用域是 title 和 content,权重 2.0;关键词“竞品名 + 改版”是组合匹配,要求两者同时出现在同一篇文章里,权重 3.0;关键词“用户反馈 + 闪退”是正则匹配,权重 4.0,用于抓质量问题信号。

信号分类我分了三档:情报型信号,比如新项目发布、产品改版,用来了解行业动向;预警型信号,比如关键词讨论量暴涨、质量反馈集中出现,需要立刻关注;常规型信号,比如指定的博客更新了,属于低优先级信息。分类决定了告警通道的差异,预警型走即时推送,情报型走日报汇总,常规型基本只在面板里展示。

4.2 热度打分模型:用一套可解释的公式计算

为了让信号优先级可量化,我设计了一个热度打分模型,核心思路是“不要只看单条内容,还要看它在窗口期内的整体表现”。综合分由三个子分加权而成。

  • 权重分:由规则引擎计算,反映单条内容与你的关注方向的匹配程度,取值范围 0 到 5。
  • 热度分:统计同一个关键词在时间窗口内出现的次数,经过归一化处理,反映了这个话题最近的整体活跃度。
  • 来源可信度:每个采集源有一个可信度系数,比如官方 API 源 1.0,普通论坛解析源 0.6,避免低质量来源的噪声被过度放大。

综合分 = 0.6 乘权重分 + 0.3 乘热度分 + 0.1 乘来源可信度。举个例子,某技术社区一小时内有三个帖子包含关键词“自动化监控”,每个帖子的权重分都是 1.5,热度分归一化以后是 0.8,来源可信度 0.8,那么每条内容的综合分就是 0.6 乘 1.5 加 0.3 乘 0.8 加 0.1 乘 0.8,等于 1.22。如果只出现一条孤立帖子,权重分相同但热度分只有 0.2,综合分就只有 1.04,优先级明显降低。用这套公式,可以把“偶尔有人提”和“突然很多人提”明确区分开。

4.3 异常检测:别被绝对值骗了,要看相对变化

打分模型解决的是存量信号的优先排序,但还有一个更重要的场景是“这件事相较于平常是不是异常地多”。我最初的版本只设置了绝对阈值,比如某个关键词一天出现 5 次就告警,结果很快被噪声淹没。后来改成基于滚动窗口的异常检测,效果好了很多。

方法是维护每个关键词近 3 天的日出现次数序列,计算均值和标准差,然后用 Z-score 算法判断当天的情况是否显著偏离正常区间。比如某个关键词平时日均出现 2 次,标准差 1.2,今天突然出现 8 次,Z-score 就是(8 减 2)除以 1.2 等于 5,远大于告警线,立刻触发预警。这个方法的优势是阈值自动适应不同关键词的流量特征,热门大词和冷门精准词不需要分别拍脑袋定参数。

给这个模块设置了一个保底机制:如果关键词的历史数据太少,日均不到 3 次,就直接用绝对阈值兜底,比如超过 5 次就告警,避免小样本下 Z-score 波动过于剧烈导致频繁误报。自上线以来,这套动态阈值比固定阈值的准确率高出一大截,告警里真正值得看的比例明显上升。

5. 告警与可视化落地:让信号真正触达你

5.1 告警通道配置:选择 Webhook 作为标准出口

信号只有触达人才有价值,所以我给消费层设计了一个统一的告警出口:Webhook。为什么选 Webhook 而不是邮件或短信?因为它的适配性最强,公司群、自建协作工具、甚至个人手机的推送服务都能通过 Webhook 接入,而且配置起来就是发一个 HTTP POST 请求的事。

推送模板我用的是 JSON,核心字段包括信号类型、标题、内容摘要、URL、综合分、触发规则。实际推送时再根据通道不同做轻微调整,比如群机器人类通道会附带 @ 所有人的选项,个人通道则不会。为了避免告警轰炸,我实现了一个 15 分钟的聚合窗口,同一关键词在同一窗口内只推一次,重复信号只更新摘要里的次数字段。这个改动非常关键,否则一个话题集中爆发时,手机能在一小时里收到几十条几乎一样的内容。

5.2 轻量雷达面板:Flask 加 ECharts 做可视化

可视化面板我选择了 Flask 提供后端接口、ECharts 负责前端图表渲染的组合。面板一共有三个页面:今日信号列表、趋势总览、信号详情。

今日信号列表是最常看的页面,展示最近 24 小时产生的所有信号,按综合分降序排列,每条信号直接给出触发原因和来源链接。趋势总览里放了两张图,一张是各采集源的数据量折线图,用来观察不同平台活跃度变化;另一张是信号数量的柱状图,按天聚合,方便看有没有异常峰值。信号详情页则针对单条信号展示原始内容、命中的关键词、各项子分。

雷达图我放在趋势总览的角落,用五个维度来评估系统的运行状态:及时性、覆盖面、信噪比、可解释性、可行动性。每个维度的得分是最近 7 天相关指标的汇总归一化结果。这张图的用意是让我自己快速看出系统在哪方面偏科,比如信噪比偏低就说明规则太宽,需要提高关键词权重或者收紧分类阈值。

5.3 数据归档与周报回看

打分量和信号数据如果只用于实时查看,就浪费了积累的价值。我在消费层里加了一个归档任务,每天凌晨把前一天的所有原始数据和信号写进一张按日分区的快照表。每周一早上,系统会生成一份周报,包含本周信号总数、触发最多的话题关键词 Top 10、综合分最高的信号 Top 5,以 HTML 邮件发送到指定邮箱。

这份周报的价值在复盘时体现得非常明显。比如我通过周报发现某类信号连续三周占比上升,但实时看的时候完全没有体感。归档数据也为我后续做更复杂的数据分析留出了空间,比如训练一个简单的分类模型来替代部分人工规则,这在最早期设计时就已经考虑进去了。

6. 常见问题与排查技巧实录

6.1 高频问题速查表

运行这套系统半年多,遇到的不少问题其实有很高的重复性,整理成速查表方便自己排查,也方便你直接套用。

问题现象可能原因解决办法
采集数据大量重复增量游标没记录或去重键设计错误检查 seen 表 external_key 是否带源前缀,重新初始化游标
告警半夜持续轰炸阈值过低 / 热度分计算方法不合理提高 Z-score 告警线,给夜间时段加静默开关
某个源返回 403请求频率过高或 User-Agent 被识别降低频率,更换合法 UA,检查是否需要使用官方 API
SQLite 写入冲突采集任务和分析任务同时写库使用单线程写队列,或用 WAL 模式减少锁等待
信号打分普遍虚高权重分配不合理,来源可信度没起作用调小权重分系数,拉大不同来源的可信度差异
面板一直无数据采集任务没启动或源配置被禁用检查 schedule 任务列表和 sources 表 enabled 字段

6.2 几个我反复踩的深坑

第一个坑是时区问题。最初我把采集时间统一存成本地时区,结果每次部署到不同机器,历史数据的时序都乱掉一段。后来统一改成 UTC 存储,展示层再转换成本地时间,这个问题彻底消失。所有时间字段一律存 UTC,这是我在这个项目里学会的最重要的一条约定。

第二个坑是采集重放机制。系统运行久了以后,我偶尔需要重新跑某一天的采集来修复历史数据缺口。一开始以为直接把采集函数再跑一遍就行,结果发现源站点会拒绝同样的高频请求,而且数据重复率极高。后来我给每个采集批次都写成一条日志,记录开始时间、结束时间、获取条数、新增条数、耗时,并且把采集函数做成“可重放但幂等”,重放时自动跳过 seen 表里已有的条目标识,只补充缺失的部分。

第三个坑是阈值漂移。动态阈值不是一次设置就能长期躺平的。某类关键词的讨论量会随行业热度变化,三个月前还算正常的波动区间,三个月后可能变成异常低点。我的解决办法是每个月给动态阈值模块重新计算一次历史基线,并且把基线计算的输出也记录到数据库里,方便追溯每次阈值调整的原因。系统不是石器时代刻好的石碑,它应该跟行业一起生长。

按照这套思路把 PLFM_RADAR 搭起来之后,我自己最大的变化是盯屏时间大幅减少,真正花在判断上的时间反而多了。以前每天刷几十个页面,大部分是在确认“没变化”;现在系统只推送“有变化”,而我只需要做决策。如果你也想搭一套类似的平台雷达,我的建议是别一上来就追求功能齐全,先跑通一个采集源加一条告警规则的最小闭环,等真正用起来以后,再根据你遇到的痛点逐步加模块。这套东西最难的部分从来不是代码,而是清楚自己到底要盯哪些信号、信号从哪里来、以及看到信号之后要做什么。把这些想明白了,PLFM_RADAR 对你来说就是一层窗户纸。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进