news 2026/9/8 1:12:07

新闻推荐系统全栈实战:从Selenium爬虫到Hadoop与大模型混合推荐

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
新闻推荐系统全栈实战:从Selenium爬虫到Hadoop与大模型混合推荐

如果你最近在做大数据方向的课程设计或者毕设,大概率刷到过“新闻推荐系统”这个题目。热点新闻平台、爬虫、可视化、Hadoop、推荐算法,这几个词叠在一起确实很唬人,尤其是再加上“大模型”之后,几乎是答辩现场的“王炸”配置。但说句实话,我见过太多号称“新闻推荐系统”的Demo,打开之后其实是同一个模子:后台管理员手动填新闻,前台按发布时间排一排,点进去显示一个浏览量数字,然后管这个叫“推荐算法”。这顶多算内容管理系统。

这篇文章要聊的,是我实际做过的一套完整项目:用Selenium爬虫从新闻网站采集热点内容,数据清洗后落入Hadoop HDFS,通过Hive做数仓建模和离线特征计算;推荐侧用“热度召回 + 协同过滤/内容相似度召回 + 大模型精排”的混合推荐算法;后端用Django提供推荐接口,前端用Vue搭建新闻平台和可视化大屏。整条链路从数据源到用户点击行为回流,是一个能真正跑起来、能验收、也敢在答辩时演示的闭环。

适合谁来参考?两类人:一类是正在做大数据课设、毕设或者找项目练手的同学;另一类是第一次把Hadoop、爬虫、推荐算法这几个东西拼在一起,想知道“它们到底怎么协作”的开发者。我会把技术选型理由、数据流链路、关键代码逻辑、踩过的坑都写清楚,尽量让你能照着搭出属于自己的版本。

1. 先搞清楚:你做的到底是“热度榜”还是“推荐系统”

1.1 常见的“伪推荐系统”长什么样

我拆过不少所谓的新闻推荐项目,表面上有登录、有新闻列表、有收藏、有点击量,但仔细一看,推荐逻辑无非三种:

  • 全站用户看到同一个列表,按浏览量倒序排;
  • 按栏目分类,把最近几天的新闻按时间倒序排;
  • 号称用了协同过滤,但用户行为数据是写死的假数据,模型根本没跑起来。

这类系统的问题不是“算法不够高级”,而是整个推荐闭环是断的。用户打开首页看到的是编辑置顶的内容,系统不知道他喜欢科技还是体育;用户点完一条新闻,也没有任何机制让这个行为影响下一次刷新。说白了,推荐系统最重要的“个性化”“动态更新”“反馈闭环”一个都没做到,那就是一个带壳的热度榜。

1.2 真正的新闻推荐系统要有三个硬指标

我这里说的“硬指标”,不是指的准确率数值,而是在项目设计层面必须成立的条件:

  • 个性化:不同用户打开首页,推荐列表要不一样。哪怕只是个“兴趣标签”维度的差异,也不能所有人一模一样。
  • 动态更新:新新闻进入系统后,应该能进入候选池;用户点击、收藏、停留时长等行为,应该能影响下一轮推荐结果。
  • 反馈闭环:用户行为必须被采集、落库、回流到算法训练里。没有这一环,你的系统就只是一次性推荐,不是会成长的推荐系统。

新闻场景还有一个特殊性:时新性极强。三天前的新闻即使曾经爆火,今天也不该再出现在首页。所以新闻推荐不只是“用户喜欢什么”,还要掂量“这条新闻现在还值不值得推”。这就是为什么最终项目采用混合算法而不是单一模型——热度负责时效和冷启动,兴趣匹配负责个性化,大模型负责内容理解。

1.3 本项目全链路定位与数据流向

先给你整体的数据流,这段链路建议直接画在答辩PPT的第一页:

  1. Selenium爬虫定时抓取新闻网站列表页和详情页;
  2. 清洗后的结构化数据写入本地JSON Lines文件,再上传到Hadoop HDFS;
  3. Hive按日期分区建表,通过Hive SQL完成基础统计和特征提取;
  4. 推荐算法读取Hive统计结果,算出热度分、相似度分、大模型精评分,把每个用户/匿名用户的推荐列表写入MySQL和Redis;
  5. Django后端从缓存或数据库取推荐结果,对外提供API;
  6. Vue前端调用API,渲染新闻流和可视化大屏;
  7. 用户点击、收藏行为上报到Django,存入行为表,定时导出参与下一轮模型更新。

这个链路的好处是每层都职责清晰:爬虫只负责采集,Hadoop只负责存储和批量计算,算法层只算分,Django只做接口和服务,Vue只做展示。任何一层出问题都能独立排查,不会出现“改个推荐算法导致页面打不开”的尴尬情况。

2. 技术栈选型复盘:Hadoop、Django、Vue、Selenium怎么分工

2.1 存储与计算选型:为什么是Hadoop,不是MySQL

很多人的疑问是:新闻数据就这么点,几万条而已,有必要上Hadoop吗?

实话讲,如果只是演示,MySQL完全够用。但如果你做的是“大数据项目”,Hadoop不是可选项,而是核心展示点。新闻爬虫跑一个月,原始HTML加结构化数据能到几千万条,文件数量非常大;HDFS在处理海量小文件时可以把它们合并成更大的数据块,Hive能直接在分布式存储上做批量统计。更重要的是,Hadoop生态的“存储计算分离”思路和MySQL完全不一样:你把数据扔到HDFS上,然后用Hive/MR/Spark去算,算完结果再导回业务库,这样既不会让业务数据库被批量统计拖垮,也能体现大数据处理能力。

当然,纯单机MySQL也能做新闻推荐,但那就不叫大数据项目了。我的建议是:数据量级不一定真要到PB级别,但处理链条一定要“像大数据那么回事”。

2.2 爬虫框架选型:静态请求和Selenium之间怎么选

这个选择其实很现实。你随便打开一个新闻网站,按F12看网络请求,会发现很多新闻列表的数据不是直接写在HTML源码里的,而是页面加载后用JavaScript异步请求接口渲染出来的。这时候用requests直接请求页面URL,拿到的HTML里只有空壳,根本解析不到新闻条目。处理办法有两个:

  • 抓接口:找到页面背后的Ajax接口,模拟请求,返回JSON直接解析。优点是速度快,缺点是接口参数可能带签名、加密字段,逆向成本高。
  • 用Selenium:直接驱动真实浏览器打开页面,等JS执行完再取渲染后的完整HTML。优点是省去接口逆向,缺点是速度慢、更吃资源。

本项目用Selenium,核心原因是“稳定优先”。爬虫需要长时间无人值守运行,如果一个接口签名变了就断,排查成本很高;而Selenium只要目标站不强制登录、不弹验证码,基本不会因为前端重构而崩溃。虽然慢一点,但爬虫频率本身就不用太高,每半小时跑一批完全够用。

2.3 后端和前端选型:Django负责接口,Vue负责呈现

Django的优势在Python项目里非常明显:自带ORM、Admin后台、用户认证,加上Django REST Framework,三四天就能把API骨架搭完。这个项目里Django的核心职责不是做推荐计算——推荐是离线算好的,它更像是“推荐结果的前端服务层”:从Redis读缓存、从MySQL读行为数据、给Vue提供标准的JSON接口。

Vue这边,我选它主要是为了可视化表达。新闻推荐系统的页面无非三大块:新闻信息流、新闻详情页、数据可视化大屏。Vue的组件化适合把这三块拆开维护;ECharts是Vue生态里最顺手的可视化库,热点趋势图、栏目分布饼图、用户画像词云都靠它。如果你愿意折腾,还能加一个Vue Router管理的多页面结构,让“推荐流”和“可视化大屏”作为两个独立路由存在。

2.4 系统整体数据从哪来、到哪去

我画一下最终跑通的架构分工(文字版):

  • 采集层:Selenium + Chrome WebDriver,抓列表页和详情页;
  • 存储层:原始HTML和结构化JSON存入HDFS,Hive负责离线数仓;
  • 计算层:离线跑热度统计、协同过滤、TF-IDF相似度、大模型批量打分;
  • 业务层:Django + MySQL + Redis,对外提供推荐流、热度榜、行为上报接口;
  • 展示层:Vue + ECharts,新闻平台 + 可视化大屏;
  • 调度层:Crontab/APScheduler,串联以上所有定时任务。

这里有一点要提醒:不要上来就写业务代码,先把这条数据流在文档里画清楚。我当初因为没画清楚就动手,结果Django后端写了快一半才发现不知道推荐结果放在哪、行为数据往哪存,返工成本非常高。

3. 爬虫模块实战:用Selenium把热点新闻变成可用数据

3.1 爬虫整体结构:列表页抓链接,详情页抓正文

新闻爬虫最忌讳一页一页直接抓全量内容,效率低而且容易触发反爬。推荐用“列表页 + 详情页”双层结构:

  1. 打开新闻列表页(比如科技频道、财经频道);
  2. 等待页面渲染完成,滚动到底触发懒加载,让更多新闻链接出现;
  3. 提取当前页所有新闻的URL,存入待抓取队列;
  4. 遍历URL,逐个打开详情页,抓取标题、正文、来源、发布时间、栏目、阅读数等字段;
  5. 抓完的URL写入已完成表,避免下次重复。

这样做的好处是列表页抓得勤、详情页抓得少,能有效控制请求量。比如列表页每30分钟跑一次,详情页只在出现新链接时才去抓,大部分时间系统是空闲的。

3.2 Selenium关键配置:无头、等待、滚动加载

Selenium的核心代码其实不多,但配置细节决定成败。我直接在项目里用的配置如下:

from selenium import webdriver from selenium.webdriver.chrome.options import Options options = Options() options.add_argument("--headless") options.add_argument("--no-sandbox") options.add_argument("--disable-gpu") options.add_argument("--disable-blink-features=AutomationControlled") options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...") driver = webdriver.Chrome(options=options) driver.get("https://news.example.com/tech")

这里面最容易被忽略的是--disable-blink-features=AutomationControlled。不加它,很多网站可以通过navigator.webdriver属性识别出这是自动化浏览器,直接拒绝后续请求。加上之后能降低一部分被检测概率。

懒加载处理靠滚动:

import time from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By wait = WebDriverWait(driver, 10) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "div.news-list"))) for _ in range(5): driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") time.sleep(1.5)

每滚动一次,页面会继续加载新内容。等你拿到足够多的新闻链接后再停止滚动,而不是一口气滚到底,减少无意义请求。

3.3 反爬不是玄学:降低存在感比绕验证码更重要

很多同学一遇到反爬就想着怎么破解验证码、怎么伪造指纹,这些当然有用,但对新闻爬虫来说,第一要务是“别让目标站感觉到你是个异常程序”。我总结下来最重要的几条:

  • 随机请求间隔:每次请求之间随机等2到5秒,而不是固定3秒。固定间隔在日志里看起来非常机器化。
  • User-Agent轮换:维护一个UA池,每次请求随机取一个,至少覆盖Chrome、Edge、Safari。
  • 控制整体量:新闻站不是电商,不需要每秒抓几十条。列表页半小时一次、详情页每分钟不超过10条,基本不会被封。
  • 遇到验证码不硬刚:如果出现滑块验证码或图片验证码,程序直接跳到下一个URL,把当前URL记入失败队列,下次再试。宁可漏掉几条,不要卡死整个任务。

我实际运行过程中,遇到过滑块验证码,也遇到过IP被临时限制。滑块验证的通用处理思路是通过OpenCV识别缺口位置、用actions拖拽,但成功率不稳定;还不如放过它,过段时间再补抓。别在一个验证码上耗一下午。

3.4 清洗与入库:从HTML到干净的JSON Lines

HTML拿到手之后,用BeautifulSoup或者lxml解析。重点解析字段包括:

  • news_id:用URL的MD5生成,作为主键去重;
  • title:新闻标题;
  • content:正文文本,去掉script、style、广告节点;
  • source:来源名,比如“XX网”“YY时报”;
  • publish_time:发布时间,统一转成标准时间格式;
  • category:栏目/分类;
  • views:阅读数、评论数等热度字段,有的站有,没有就填0。

清洗完成后,每行一条JSON输出,方便后续入HDFS和Hive。文件名带上批次时间,比如news_20250120_1830.jsonl。这里有个经验:原始HTML也尽量留一份,压缩后存起来,虽然前期用不到,但如果你想重跑清洗逻辑,不需要重新爬一遍。

4. 大数据流转:Hadoop存储和Hive数仓建模

4.1 伪分布式环境与格式化那个著名的坑

Hadoop的第一道坎就是环境搭建。单机训练/毕设用伪分布式模式足够,真正上集群可以用Ambari之类工具部署,但成本和复杂度高不少。伪分布式需要注意的点:

  • core-site.xml配置fs.defaultFShdfs://localhost:9000
  • hdfs-site.xml配置副本数为1,并指定NameNode和DataNode的目录路径;
  • 改好配置后第一次启动之前,要先执行hdfs namenode -format

格式化失败是最常见的坑之一。原因是之前运行过程中NameNode目录已经存在,或者目录里有残留数据。解决方案很简单:把dfs.namenode.name.dirdfs.datanode.data.dir指向的目录清空,再重新格式化。另外,如果出现Incompatible clusterIDs之类的报错,说明DataNode和NameNode的clusterID不一致,删除DataNode目录里的current文件夹,重新启动即可。

Hadoop启动后,用jps确认进程:应该有NameNodeDataNodeSecondaryNameNodeResourceManagerNodeManager这几个关键进程。少一个都说明启动有问题。

4.2 新闻原始数据如何进入HDFS

数据进入HDFS最直接的方式就是命令行上传:

hdfs dfs -mkdir -p /warehouse/news/raw hdfs dfs -put ./news_*.jsonl /warehouse/news/raw/

如果数据量大,可以先合并文件再上传,避免大量小文件挤占NameNode内存。比如每天抓完数据后,用shell脚本把当天所有jsonl合并成一个news_20250120.jsonl,再上传,这样Hive查询效率也会高很多。

也可以写一个Python脚本,直接用hdfs库或调用subprocess执行hdfs dfs -put,把这个步骤纳入整体调度。不需要为了“看起来高级”引入Flume或者Kafka——在这个项目里,定时批量上传已经足够,加消息队列反而徒增复杂度。

4.3 Hive建表:按日期分区的新闻明细表

Hive里建一个外部表,按日期分区。外部表的好处是数据文件删了,表结构还在,不会误删原始数据。

CREATE EXTERNAL TABLE IF NOT EXISTS default.news_dim ( news_id STRING, title STRING, content STRING, source STRING, publish_time STRING, category STRING, views BIGINT, comments INT, url STRING ) PARTITIONED BY (dt STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE LOCATION '/warehouse/news/warehouse';

上传到HDFS后,手动增加分区:

hive -e "ALTER TABLE news_dim ADD PARTITION(dt='2025-01-20') LOCATION '/warehouse/news/warehouse/dt=2025-01-20';"

分区的好处是后续按天统计时,只需要扫描对应分区的数据,不需要全表扫描。这个特性在新闻这种按天增量明显的场景里非常实用。

4.4 从Hive到算法:离线特征怎么返给推荐层

Hive在项目里的产出主要有三类:

  • 新闻热度统计表:每天每篇文章的浏览量、评论量、发布时间等;
  • 新闻栏目分布表:各栏目内容数量、平均阅读数,用于可视化大屏;
  • 用户行为聚合表:从行为日志里统计每个用户的点击偏好、阅读时长。

这些离线统计结果不适合直接让前端查,因为Hive查询延迟高。标准做法是把统计结果导出到MySQL或Redis:用hive -e "INSERT OVERWRITE ..."或者写一个Python脚本读取Hive结果,然后写回业务库。推荐流接口直接读MySQL/Redis,秒开;可视化大屏的汇总数据则每小时刷新一次,完全够用。

调度上,我直接用Crontab跑一个总脚本:先跑爬虫,再跑清洗,上传HDFS,执行Hive ETL,最后触发推荐算法任务。整个过程串行执行,日志写到固定目录,方便第二天排查哪里断了。

5. 混合推荐算法拆解:热度、协同过滤、内容相似、大模型精排

5.1 第一层召回:带时间衰减的热度公式

新闻推荐里,热度是第一生产力。新用户没有行为记录时,你没法做个性化,只能靠“大家都在看什么”来兜底。但单纯按浏览量排会有一个问题:老新闻霸榜。所以热度公式一定要带时间衰减。

我这里用的公式是:

hot_score = (a * views + b * comments + c * collects) / power((now - publish_time).hours + 2, 1.5)

分子是“质量分”,浏览量、评论数、收藏数按权重累加;分母是“时间衰减”,新闻发布越久,热度越低。常数2是为了避免刚发布时除数为0,指数1.5控制衰减速度。这个公式不复杂,但它在冷启动阶段的表现直接决定了整个推荐系统的下限。权重a、b、c可以按平台调,内容站评论权重大一些,资讯站浏览量权重大一些。

5.2 第二层召回:协同过滤 + TF-IDF内容相似度

热度只解决“大家都在看”,解决不了“你喜欢什么”。第二步要做的是个性化召回。

基于用户的协同过滤(UserCF):核心逻辑是找到与当前用户兴趣相似的一群人,把他们看过的新闻推荐给当前用户。用户之间的相似度,可以用共同看过的新闻数量除以并集新闻数量,也可以根据行为加权。新闻场景有个明显问题:多数用户读过的东西很少,交互矩阵极其稀疏,纯UserCF容易抓瞎。

基于内容的召回:对每篇新闻做分词、TF-IDF向量化,计算新闻之间的余弦相似度。用户读完一篇“Hadoop入门”的新闻,系统就可以找向量最接近的其他技术文章推荐过去。这个方案不依赖用户间行为,冷启动优势明显,但缺点是会给用户推同质化内容,容易形成“信息茧房”。

所以项目里不是选二者之一,而是把两个召回结果合并:UserCF给Top N,内容相似给Top N,再加上热度Top N,三个来源并集形成候选集,送到下一层精排。

5.3 第三层精排:大模型做语义匹配和推荐理由

候选集可能有几百条,用户只能看到二三十条,怎么排序?这层我引入了大模型。

大模型在这里不是做在线实时推理,那延迟太高了。我在项目里用本地部署的开源对话模型(7B/13B级别均可),离线批量给候选新闻打分。具体流程是:

  1. 从用户画像中提取兴趣标签和最近读过的5条新闻标题;
  2. 把候选新闻的标题、摘要、分类拼接成提示词;
  3. 让模型输出0到10的匹配分;
  4. 批量跑完后,将结果写入Redis,在线推荐时直接读取分数。

提示词大致是这样:

用户近期关注:机器学习、房价走势、新能源汽车 候选新闻标题:某品牌发布新款电动车,续航超过700公里 请根据用户兴趣,输出这篇新闻对该用户的匹配程度,0到10分,只输出数字。

模型输出可能是“8”,解析后归一化作为精排分。除了打分,也可以让模型生成一句“推荐理由”,像“因为你对新能源车持续关注,这条消息值得一看”,这个细节在演示时非常加分。

大模型还有两个很实用的点:一是给新闻打语义标签,比如“科技/财经/体育”这种粗分类很容易分,但“ChatGPT”“AIGC”“大模型”这种语义标签需要模型理解能力;二是用文本相似度判断两条标题不同、内容相同的新闻是否属于同一事件,做去重。

5.4 混合权重、冷启动和实时反馈修正

最终分数用加权混合:

final_score = 0.20 * hot_score + 0.30 * user_cf_score + 0.25 * content_score + 0.25 * llm_match_score

这个权重不一定通用。你可以先跑一个月数据,用离线测试集做网格搜索,选CTR预估最准的一组权重。冷启动阶段,用户没有任何行为时,user_cf和content_score都没法算,权重直接切到热度和当日大事件上;等用户产生行为后,再逐步切换到个性化权重。

还要留一个“实时反馈修正”通道:用户点击一条科技新闻,那么他候选列表里同类内容的权重立即上调5%,不喜欢/点踩的内容权重下调。这个可以在Django接口层临时塞一个bias参数实现,不用重新跑整个离线流程。

6. Django后端接口与Vue可视化联动

6.1 推荐API怎么设计:feed、hot、behavior三条主线

后端接口不需要设计得非常复杂,三条主线就够用:

  • 推荐流GET /api/recommend/feed?user_id=xxx&page=2,返回当前用户当前页的新闻列表,每项包含标题、摘要、来源、发布时间、推荐理由;
  • 热度榜GET /api/news/hot?category=tech,返回某个栏目下按热度分排序的新闻,可供“热点新闻平台”页使用;
  • 行为上报POST /api/user/behavior,接收user_idnews_idbehavior_type(view/collect/comment)、durationtimestamp,写入行为表。

用户体系这里可以做得轻一些:注册登录用Django自带User模型;匿名用户生成一个session_id作为临时用户,行为照样上报。匿名用户第一次打开首页时,接口返回热度榜内容,并提示“登录后获得个性化推荐”。

6.2 推荐结果是怎么从Hadoop流向Django的

流程是这样的:离线算法任务跑完后,把每个活跃用户的推荐列表写进MySQL的一张recommend_result表,字段包括user_idnews_idscorereasonexpire_at;同时把热度榜和当日推荐理由写入Redis。

Django接口收到请求后,优先查Redis缓存;缓存过期或没有该用户数据时,再查MySQL。Redis的key可以设计成recommend:user:{user_id}:{page},过期时间设为30分钟。这样避免每次刷新都打MySQL,也给了推荐结果“定时更新”的窗口——最多每30分钟刷新一次推荐,用户体感是“推荐居然在跟着我看的东西变”。

6.3 Vue页面结构:新闻流、详情页、可视化大屏

Vue这边我分了三个主要模块:

  • 新闻流页面:进入首页自动请求推荐接口,下拉触底加载下一页。每条新闻卡片可以展示标题、摘要、来源、推荐理由。点“不感兴趣”按钮,前端把这个行为上报后端,下次刷新该条新闻会被过滤掉。
  • 新闻详情页:展示正文,同时给出“相关推荐”栏目,调用基于内容相似度计算的接口,推荐3-5篇相关新闻。
  • 可视化大屏:如果项目需要演示,建议单独路由做一个/dashboard页面,用ECharts展示五块内容——当日新闻数量趋势、栏目热度分布、新闻来源占比、用户阅读偏好词云、推荐点击率折线。数据来源是后台统计接口,每小时更新一次。

6.4 联调阶段最常踩的跨域和字段坑

前后端分离项目最常见的坑是跨域。Django里直接装django-cors-headers,在settings.py里配置:

INSTALLED_APPS = [ ... "corsheaders", ] MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", ... ] CORS_ALLOWED_ORIGINS = [ "http://localhost:5173", ]

Vue开发服务器默认端口5173,Django默认8000,两个端口不一致,不配跨域请求必挂。这个坑几乎每个第一次做前后端分离的人都会踩。

字段命名也要统一。数据库里用news_id,接口里就不要一会儿newsId一会儿id;推荐理由字段统一叫reason,前端组件写死。建议接口返回前先打印一份JSON检查结构,别等到页面渲染报错再回来翻后端代码。

7. 实测表现、效果评估和几个真实翻车场景

7.1 离线指标和在线指标怎么定

推荐系统不能靠“看起来推荐得挺准”来验收。我实际操作时用了两类指标:

  • 离线指标:用历史行为数据切训练集和测试集,看召回率、准确率、覆盖率。覆盖率特别重要,如果推荐结果永远来自那几百篇热度高的新闻,说明个性化没生效。我会统计“推荐列表里非Top200热门新闻的占比”,目标是超过30%。
  • 在线指标:记录用户曝光量、点击量、收藏量、平均停留时长。核心就是CTR(点击率),公式是点击次数 / 曝光次数。跑混合推荐之后,CTR应该明显高于纯热度榜。我当时对比了两周数据,混合推荐CTR提升了大概15%-20%。

如果只是课程设计,不需要做这么细,但答辩时能说出“离线覆盖率从20%提到35%,在线CTR比热度榜提升17%”这种数据,说服力比“用了协同过滤算法”强太多。

7.2 三个让我半夜改代码的翻车场景

翻车场景一:爬虫跑了一小时,IP被限制。症状是页面开始弹验证码,所有请求进入死循环。解决办法是加代理池 + 降低抓取频率。代理池可以用免费代理列表,但质量不稳定;更稳的方案是拉长抓取间隔,让单IP的整体请求量控制在每天几千次以内,新闻站基本不会有意见。

翻车场景二:冷启动用户打开首页是空的。我最初把推荐接口设计成“先取UserCF结果,取不到就返回空列表”,结果新用户注册进来首页一片空白。后来加了两条保底逻辑:第一,任何用户都能拿到热度榜Top50;第二,如果用户有过一次点击,立即用内容相似度补30条候选。诡异的是这个bug在开发环境一直没暴露,因为开发环境我账号里已经攒了很多行为数据。所以测试新用户流程一定要从零开始。

翻车场景三:大模型在线打分太慢,接口超时。一开始我天真地在推荐接口里直接调大模型推理,一条候选就要几百毫秒,几十条候选算下来接口奔着10秒去了。后来改成离线批量打分,把所有用户候选集一次性拼批喂给模型,结果写入Redis,接口从10秒优化到200毫秒。这个优化也解释了为什么项目架构里“大模型”一定要放在离线任务里,不能放在请求链路上。

7.3 这套系统还能往哪些方向扩展

如果你做完之后还有余力,有几个方向性价比很高:

  • 实时热度:加一个WebSocket推送,把用户正在浏览事件的实时热度变化推到大屏上,视觉冲击力很强。
  • 更细的用户画像:除了栏目偏好,还可以用大模型抽取用户阅读内容的语义关键词,做成词云展示。
  • 混合推荐权重自动调优:写一个简单脚本,每天根据前一天的CTR表现自动微调几个混合权重,让系统看起来“会自我进化”。
  • 新闻内容去重:同一事件不同网站的报道很多,用大模型判断“是否为同一事件”,把相似新闻聚成一簇,推荐时只推最优质的一篇。

整套系统跑通之后,我最大的感受是:推荐系统真正难的不是算法,而是数据闭环。新闻推荐尤其见真章——用户点了一下,你下一次刷新必须给出反应;如果做不到这条,再花哨的算法都只是演示动画。所以不管你是为了答辩还是为了入门大数据,动手做之前一定先把数据流画清楚,这比急着写代码重要得多。后面扩展的时候,优先考虑实时流处理和更完整的用户画像,那才是这套系统“从能跑变成好用”的下一级台阶。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 1:11:07

基于SpringBoot的在线考研辅导平台 设计与实现

1.选题背景及研究的目的和意义 1.1选题背景 随着考研人数逐年攀升,2025 年全国考研报名人数突破 500 万,传统线下辅导存在地域限制、资源分配不均、学习时间灵活度低等问题。现有线上平台多侧重课程播放,缺乏考研专属的个性化辅导、实时互动答…

作者头像 李华
网站建设 2026/9/8 1:08:16

无 GPU 跑 CUDA:BarraCUDA 功能级模拟器详解

第一次看到 BarraCUDA 这个名字,我下意识以为是某个显卡烤机工具或者咖啡机的营销项目。后来翻到帝国理工开源的这个项目,才意识到它干的事情相当反直觉:在没有 NVIDIA 显卡的机器上,用 CPU 把 CUDA 程序跑起来,并且尽…

作者头像 李华
网站建设 2026/9/8 1:08:07

Python爬虫实战:requests+BeautifulSoup采集基金会公开项目数据全流程

做数据采集这行,最怕的不是目标网站结构有多复杂,而是你根本不知道自己到底要采什么、采回来能干什么。最近我完成了一轮基金会公开项目数据的深度采集,整个过程没有上重型框架,就是Python爬虫里最常用的requests加BeautifulSoup&…

作者头像 李华
网站建设 2026/9/8 1:07:20

前端直接渲染后端超大高精度SVG:放弃Echarts后的完整实践方案

接手一个前后端分离项目时,后端同事直接把一批超大高精度SVG矢量图丢了过来,问我前端能不能直接渲染,还强调“别再用Echarts硬转,精度扛不住”。一开始我还觉得奇怪,Echarts不是有SVG渲染器吗,后来真上手才…

作者头像 李华
网站建设 2026/9/8 1:02:55

n8n实现混合数据RPA:GUI与API自动化整合方案

1. 项目概述:n8n中的混合数据RPA挑战在自动化流程设计领域,n8n作为开源工作流自动化工具正获得越来越多企业的青睐。最近我在为一个跨境电商客户设计库存管理系统时,遇到了一个典型场景:需要同时操作本地ERP软件的图形界面(GUI)和…

作者头像 李华
网站建设 2026/9/8 1:01:47

三段式爬虫管道设计:列表-详情-附件解耦采集架构

做采集项目这些年,我踩过最深的坑,不是反爬严,也不是解析难,而是把“抓列表”“抓详情”“下附件”全塞在一个脚本里,几百行代码串成一坨,跑到一半报错,从头再来。后来我把这套流程重构成“列表…

作者头像 李华