资讯详情

资讯详情

新闻流聚合项目Beta冲刺实录:正文抽取、事件聚合与性能优化

1. 开篇Pulse news stream 的 Beta 冲刺我们到底在冲什么先说结论Pulse news stream 是一个以“实时新闻流聚合”为核心的个人项目简单点讲它把多个信息源RSS、网页正文、社交媒体热帖等抓下来经过解析、去重、排序统一渲染成一条可无限滑动的时间线主打“一屏看完今天值得看的东西”。做这个项目的初衷很朴素——我自己受够了在五六个 App 之间来回切换看新闻想让信息主动流向我而不是我去各个平台“逛”。这篇博客主要记录我们团队在 Beta 冲刺阶段的完整过程从功能冻结到性能优化从崩溃排查到发布候选版本以及我在这个过程中踩过的坑、验证过的方案、和最后沉淀下来的经验。适合两类人读一类是正在做信息流类产品或 RSS 阅读器的开发者另一类是准备把个人项目推向“可对外发布”状态、但还没想清楚 Beta 冲刺阶段该干什么的独立开发者。Beta 冲刺不是一个玄幻的阶段它的本质就一句话功能已经定了剩下的时间全部用来让这个版本变得“能见人”。我们这次冲刺周期是两周目标不是加新功能而是把 Pulse news stream 从一个“自己跑着没问题”的 demo变成一个“别人用起来也不尴尬”的 Beta 版本。2. 整体设计与冲刺思路2.1 为什么叫“Pulse”——信息流的脉搏感从哪来项目取名 Pulse是因为我们希望新闻流给人的感觉不是死板的列表而是一种“有脉搏”的节奏。传统 RSS 阅读器按时间倒序排列表项Pulse 想做的不太一样同一事件的后续报道会自动聚合到同一条“事件流”里再结合热度权重排序让重要的事浮上来琐碎的信息沉下去。这个设计决定了 Beta 冲刺阶段的大部分技术工作。因为一旦做事件聚合和热度排序后端就不能只做一个简单的“抓取-存储-输出”三层而是需要负责任务调度、正文抽取、相似度计算、热度衰减这几个核心环节。Beta 冲刺阶段我们首先把“功能边界”锁死否则两周时间根本不够用。冲刺前我们开会定了三条边界这三条在后面帮了大忙只支持 RSS 源 静态页面正文抓取不碰登录后才能看的内容。热度排序先用“时间衰减 来源权重”的简化公式不上机器学习模型。客户端只做 Web 端移动端适配不做原生 App。锁边界不是为了偷懒是因为 Beta 冲刺的所有精力应该花在“稳定性、性能、体验一致性”上而不是继续往外扩。见过太多个人项目死在“什么都要做”上最后 Beta 版本连基本功能都跑不稳。2.2 技术栈选型与分工逻辑在技术选型上我们坚持“用顺手的不用最新潮的”。这句话听起来保守但在冲刺阶段极其重要——因为你没有时间去踩别人踩过的坑更没时间为一个刚出的框架付学费。后端采用 Python FastAPI负责抓取调度、正文解析、聚合排序、API 输出。数据存储用 PostgreSQLJSON 字段存原始抓取内容关系表存源信息和聚合关系。前端采用 Vue 3 Vite移动端优先桌面端保证可用。抓取任务用 APScheduler 做定时调度没有上 Celery因为目前的源数量还没到必须引入消息队列的程度。分工逻辑是这样的我个人主攻后端抓取和聚合算法另一位同学负责前端时间线渲染和交互还有一位兼职测试和部署。小团队冲刺阶段最忌讳“各写各的然后最后联调”我们每天固定一次半小时站会强制同步当天改动和阻塞点。2.3 Beta 冲刺的里程碑规划两周冲刺我们拆成三段每段有明确的出口标准第 1~4 天功能冻结与数据链路稳定性加固。所有接口按“Beta 契约”锁定不允许随意加参数。第 5~9 天性能优化与核心指标调优。首屏加载时间、接口 P95 延迟、抓取成功率、去重准确率四件事并行推进。第 10~14 天真机环境、内容合规排查、发布候选与文档补齐。这个规划看起来平平无奇但真正跑起来之后每一天都会有计划外的问题冒出来。冲刺不是“按计划执行”而是“按计划发现问题然后解决”。3. 核心细节解析与实操要点3.1 正文抽取摘要时代里最容易被低估的关键点新闻流的体验八成交给正文抽取的质量。如果用户点开一条内容发现正文是乱的、缺段落的、全是广告噪声的整个产品就会失去信任。Beta 冲刺阶段我们把正文抽取模块完全重构了一遍。最早版本用的是 Readability 的 Python 移植版可实测下来对国内部分新闻站点的适配很不好。后来换成了“规则优先 兜底算法”的双层策略第一层针对高频源配置 CSS 选择器规则直接定位正文节点。配置存放在数据库表里运营后台可随时调整不改代码。第二层对无规则覆盖的站点走文本密度分析算法。核心思路是统计每个块级元素的文本密度和链接密度密度高且链接占比低的节点认定为正文候选再取整页最连续的候选区域。实操上有个细节特别值得注意新闻页往往有“相关推荐”“热门阅读”这类区块在正文后面它们也是高密度文本。我们用了两个信号来过滤一是在 DOM 树中的相对位置正文节点通常在主内容容器内推荐区块多在 aside 或底部二是节点内部链接的锚文本长度若链接文字包含“点击查看”“阅读全文”高频词则降权处理。这两招组合起来把正文抽取准确率从最初的 68% 提到 91% 左右。# 伪代码正文候选节点评分 def score_node(node): text_len len(node.extract_text()) link_text_len sum(len(a.text) for a in node.find_all(a)) if text_len 200: return 0 link_ratio link_text_len / text_len density text_len / max(1, node.text_blocks_count()) score density * 0.6 (1 - link_ratio) * 0.4 return score这个评分函数不算复杂但它解决了一个真实痛点把“文本多”和“值得读”两个概念解耦单纯字数多不代表是正文有可能是垃圾导航。3.2 事件聚合相似度的度量和阈值调优Pulse 的特色功能是“同一事件的不同报道聚合到一条流里”。Beta 冲刺阶段最花时间的不是写代码而是调相似度阈值。我们采用的方案是 SimHash 文本去重逻辑的变体先对正文做分词提取 TF-IDF 特征词生成 64 位 SimHash 指纹再计算两个指纹的海明距离。距离小于等于 3 视为同一事件的候选候选再通过发布时间窗口做二次筛选。但 SimHash 有个问题——它擅长处理“近似重复”的文本对“同一事件但不同角度”的报道鉴别力一般。比如某手机厂商发布新机A 媒体报道聚焦参数B 媒体报道聚焦价格两者文字重合度可能只有 30%但读者看来就是同一件事。为了补这个短板我们在 SimHash 之后加了一层“核心实体重叠检查”用 jieba 分词后按词性提取专有名词NR、机构名NT、品牌词如果核心实体集合重叠超过 60%即使文本距离较大也会被归为同一事件聚合。这一层逻辑上线以后聚合的 Precision 保持了 90% 以上Recall 提升了约 15%。代价是增加了一次额外的计算开销但新闻源单日采集量在万级以内完全可接受。3.3 热度排序不用机器学习也能做到“有感知”Pulse 的时间线不是严格按时间排序而是按“热度分”排序。Beta 冲刺阶段我们确定了一个可解释、可调整的公式确保任何一条内容的排序变化都能说清楚原因。热度分由四个因子组成基础分来源站点权重 × 内容类型系数。权威媒体权重高个人博客系数略低。时间衰减采用指数衰减半衰期设为 6 小时。简单说一条内容发布 6 小时后热度衰减一半12 小时后只剩四分之一。互动反馈Beta 期间用户对内容的“阅后标记”无关、不感兴趣会反馈到系统降低该类内容后续排序权重。突发惩罚同一事件聚合条数过多时整体略微降权避免热点刷屏。公式如下score base_weight * content_type * pow(0.5, age_hours / 6) engagement_bonus这个公式背后有一个理念新闻流产品不应该是“编辑的主观推荐”也不应该是“完全随波逐流的时间线”而应该是一个透明的、可解释的系统。Beta 用户给我们的反馈里排在最前面的两条——一条是关于某个大型开源项目的发布另一条是关于某地天气的突发报道——用户没有觉得“推荐得很奇怪”因为热度的逻辑和直觉是吻合的。4. 实操过程与核心环节实现4.1 抓取调度与更新策略的稳定化Beta 冲刺阶段的第 3 天数据抓取链路出了一个大问题某个源连续请求失败后我们的重试机制会以指数退避方式退避一小时但用户的客户端还会频频触发拉取导致部分内容一直不更新。我们把抓取策略调整为“两级时钟”模式第一级全局调度器每 5 分钟检查一次待抓取队列。第二级每个源独立维护上次成功抓取时间和抓取失败次数。如果失败次数超过 3 次该源自动降级为“观察模式”——只记录不重试直到下一次全局检查发现该源已恢复。同时我们为高频源设置了差异化抓取频率头部媒体源默认 10 分钟一轮普通博客 30 分钟一轮低频网站 2 小时一轮。调整后整体抓取成功率维持在 96% 以上API 的平均响应延迟从 900ms 降到 400ms 左右。4.2 前端时间线渲染虚拟滚动和图片懒加载的权衡Pulse 的时间线是无限滚动如果一次渲染几千条 DOM 节点任何一个浏览器都会卡死。Beta 阶段我们采用了虚拟滚动方案只渲染视口内可见的节点滚动时动态回收和创建 DOM。虚拟滚动实现不难难在图片懒加载和虚拟滚动的配合。新闻流卡片大量包含缩略图如果直接在卡片创建时加载图片虚拟滚动快速滑动时会疯狂发出图片请求造成带宽浪费和图片闪烁。我们最终的方案是卡片进入视口前 200px 时才开始请求图片同时给图片容器设置固定宽高比防止滚动跳动。每个卡片的图片区域用 CSSaspect-ratio占位加载完成后再填充实际图片。这组优化让首屏加载时间从 2.8 秒降到了 1.4 秒实际体感提升非常明显。4.3 合规与内容安全自查Beta 发布前必做的一步Beta 冲刺阶段很容易忽略内容安全但这恰恰是一个新闻流产品不能省的环节。我们的做法是在发布候选版本之前全量扫描数据库中的存量内容自动过滤包含高风险关键词的条目同时对新增内容走实时检查接口命中疑似内容一律不放行。这部分的实现不算困难但需要认真对待的是“误杀”问题。如果过滤规则太激进正常内容会被大量误伤如果太宽松又失去了防护意义。我们采取的策略是“分级处理”明确违规的内容直接删除疑似内容不进时间线、只进入后台待审列表由人工定期复核。Beta 阶段两周跑下来自动过滤的准确率在可以接受的范围内误杀率控制在 1% 以下同时没有出现漏放的情况。4.4 发布候选版本的构建与验证冲刺最后两天我们冻结代码进入发布候选阶段。这一步的流程是从主干拉出release/beta分支冻结所有功能开发。跑一遍自动化测试回归接口测试 核心聚合算法单测 前端构建检查。部署到预发布环境用真实数据跑 24 小时代稳定性验证。检查所有外部依赖的许可证合规性避免分发时埋雷。生成版本说明文档和部署说明文档。这里面经常被新手忽略的是许可证合规检查但个人项目如果未来有商业化打算这一步最好一开始就做。我们在 Beta 冲刺中就发现一个前端工具库的许可证对商用不友好换掉的时间成本在可控范围内——这要是等到正式发版再发现麻烦就大了。5. 常见问题与排查技巧实录5.1 正文解析结果时好时坏怎么排查我们遇到过非常典型的场景同一个新闻源昨天解析正常今天抓下来的正文就变成了“页面标题 一堆导航链接”。排查思路如下先看抓取时的 HTTP 状态码如果返回 200再看 HTML 结构是否变化。很多站点会隔几天改一次 CSS class 名称导致我们配置的选择器规则失效。进一步打开抓取日志里的 HTML 快照对比失效前后站点的 DOM 结构差异。最终我们发现那个源改版后把正文区块的 class 从article-content改成了post-content。解决方案是给每个源增加多个备选选择器当一个选择器命中不到节点时自动尝试下一个。这种小技巧只有踩过坑才会想到。5.2 相似度聚合错得离谱怎么降低误判测试阶段有用户反馈两条完全不相关的内容聚合到了一条事件流里。排查后发现问题出在 SimHash 的指纹比较逻辑上——SimHash 对长文的指纹计算不稳定当文本长度差异悬殊时容易产生意外的相近指纹。修复方案有两个一是对参与计算的文本做长度归一化只取正文前 2000 个字符参与指纹计算二是增加“核心实体重叠检查”的权重当两条内容的专有名词完全不重合时即使指纹距离很近也不聚合。两个改动配合上线后误判率降低了 60% 以上。5.3 Beta 用户反馈“内容太旧”怎么定位问题Beta 期间有用户反馈“Pulse 里的内容总是比原网站慢半小时”。这个反馈很关键因为对于一个新闻产品时效性就是生命线。排查结果是两级原因叠加一是目标源网站更新时没有更新 RSS 的 Last-Modified 头我们的调度器判断“没有变化”就跳过抓取二是某些源的反爬机制会把我们的抓取请求引导到缓存节点拿到的是几小时前的旧页面。针对第一个原因我们增加了“按正文最新发布时间判断是否更新”的逻辑不再完全依赖 HTTP 层的 Last-Modified针对第二个原因我们设置了缓存绕过参数关键请求强制回源。处理完以后平均延迟从 35 分钟降到了 6 分钟。6. 写在冲刺结束后6.1 我个人的三个实操体会Beta 冲刺结束我回头看这十四天有三个体会想分享第一个体会是“Beta 冲刺不是功能冲刺而是稳定性和体验的冲刺”。很多人到了 Beta 阶段还在加功能结果就是每个功能都有 bug体感甚至不如原型阶段。功能冻结不是妥协而是对自己项目的一次认真负责。第二个体会是“日志和可观测性做得好排查问题的速度能快十倍”。我们这次冲刺救命的不是某个“高级工具”而是一开始就挂在后台的访问日志和抓取日志。每次用户反馈问题我们先查日志再猜原因大大缩短了定位时间。如果你还在用 print 调试自己的项目Beta 冲刺前一定要把日志结构梳理好。第三个体会是“小团队冲刺沟通密度比代码量重要”。我们每天半小时站会听起来时间不长但把各自正在做的、阻塞的、明天打算做的全过了一遍。很多看似棘手的问题其实在站会上三句话就能互相点醒。6.2 最后再分享一个小技巧Beta 版本发布后建议在应用内明显位置放一个反馈入口让用户能直接提交“内容错误、加载失败、排序异常”这三类反馈。Pulse 的 Beta 冲刺后期就是通过这类结构化反馈快速发现了几个聚合误判的高频场景针对性调参之后准确率提升非常明显。Beta 冲刺这十四天谈不上轻松但很值得。把一个项目从“能用”推到“别人愿意用”的状态这个过程中沉淀下来的判断力和经验比代码本身更有价值。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →