newsnow 财经快讯双源聚合教程:5 分钟跑通华尔街见闻 × 财联社实时流
【免费下载链接】newsnowElegant reading of real-time and hottest news项目地址: https://gitcode.com/GitHub_Trending/ne/newsnow
开盘时段来回切换多个财经应用查行情,效率很低。newsnow 是一个开源实时热点聚合项目,默认同时抓取华尔街见闻「快讯」与财联社「电报」,把两路数据汇进同一个财经栏目。它按 5 分钟粒度取数、30 分钟缓存兜底,本文先带你把服务跑起来,再拆数据链路。
快速上手:双源快讯 5 分钟跑通 🚀
克隆仓库后用 Docker 直接启动:
git clone https://gitcode.com/GitHub_Trending/ne/newsnow cd newsnow docker compose up浏览器访问http://localhost:4444,切到财经栏目。你会看到华尔街见闻「快讯」和财联社「电报」两张卡片并排,各列约 30 条最新条目,时间戳精确到分钟,点击任意条目跳转原文。
本地开发(便于二次开发)只需两条命令:
pnpm install pnpm dev原理拆解:快讯为什么能保持实时
抓取层:两个 API,一套规则
server/sources/wallstreetcn.ts 请求 lives 接口,返回结构经 TypeScript 约束:
// 华尔街见闻快讯条目,display_time 为秒级时间戳,需乘 1000 interface Item { uri: string id: number title?: string content_text: string display_time: number }server/sources/cls/index.ts 请求财联社电报接口,用当前时间作为 last_time 拉取最新 30 条,并剔除广告:
// 财联社电报条目,ctime 为秒级时间戳,需乘 1000 interface Item { id: number brief: string shareurl: string ctime: number is_ad: number // 1 表示广告位,直接过滤 }两路请求共用 server/utils/fetch.ts 里的封装:10 秒超时、自动重试 3 次,并把 UA 伪装成浏览器,降低被源站拦的概率。
缓存层:interval 与 TTL 两个阈值
缓存表在 server/database/cache.ts,底层是 D1 数据库(Cloudflare 提供的云端 SQLite),只存三列:键、JSON 数据、写入时间:
// 写入缓存:同键覆盖写,updated 记录写入时刻 async set(key: string, value: NewsItem[]) { await this.db.prepare( `INSERT OR REPLACE INTO cache (id, data, updated) VALUES (?, ?, ?)`, ).run(key, JSON.stringify(value), Date.now()) }调度逻辑在 server/api/s/index.ts,靠两个数字判断:
- interval(300000 毫秒 = 5 分钟):未到间隔时直接返回缓存,不请求源站;
- TTL(30 分钟,定义在 shared/consts.ts):超过 interval 但未超 TTL 时,仍返回缓存;只有带 latest=true 且已登录的请求能突破这层限制。
也就是说,普通访客看到的是 5 分钟粒度的缓存,登录用户用 latest=true 可强制回源。
渲染层:栏目只是数据映射
前端请求/s?id=xxx,拿到{id, updatedTime, items}后按column: "finance"归入财经菜单,用 React Query + Jotai 渲染卡片,每条附相对时间(如「18 分钟前」)。
配置详解
sources.json 字段对照
全部数据源开关在 shared/sources.json,本主题涉及的两条:
"wallstreetcn-quick": { "name": "华尔街见闻", "type": "realtime", "column": "finance", "home": "https://wallstreetcn.com/", "color": "blue", "interval": 300000, "title": "快讯" }, "cls-telegraph": { "name": "财联社", "type": "realtime", "column": "finance", "home": "https://www.cls.cn", "color": "red", "interval": 300000, "title": "电报" }| 字段 | 作用 | 示例 / 默认 |
|---|---|---|
| name | 卡片展示名 | 华尔街见闻 |
| type | 数据性质:realtime 实时流 / hottest 热榜 | realtime |
| column | 归属栏目,决定顶部菜单 | finance |
| interval | 刷新间隔,毫秒 | 300000(5 分钟) |
| title | 卡片内副标题 | 快讯 / 电报 |
| color | 卡片主题色 | blue / red |
| redirect | 旧键重定向,如 wallstreetcn → wallstreetcn-quick | 无 |
| disable | 停用标记,cf 表示被 Cloudflare 反爬拦截 | 无 |
sources.json 在构建时由 scripts/source.ts 打包进产物,改完需重新构建并重启才生效。
环境变量
参照 example.env.server 复制为.env.server:
| 变量 | 默认值 | 作用 |
|---|---|---|
| ENABLE_CACHE | true | 缓存总开关,false 则每次请求回源 |
| INIT_TABLE | true | 首次运行初始化缓存表与用户表 |
| G_CLIENT_ID / G_CLIENT_SECRET | 空 | GitHub OAuth(第三方身份联合协议)应用凭据,登录必需 |
| JWT_SECRET | 空 | 登录 token 签名密钥 |
| PRODUCTHUNT_API_TOKEN | 空 | Product Hunt 数据源接口密钥 |
进阶玩法
登录实现跨设备同步
GitHub OAuth 登录后,栏目顺序、收藏、显示偏好会通过/me/sync自动上传,换设备启动时拉回。上传带 10 秒防抖(src/hooks/useSync.ts),避免拖拽时高频写库;服务端在 server/api/me/sync.ts 把整份配置以 JSON 存入用户表。
个性化与检索
- 栏目、卡片均支持拖拽排序,布局存本地;
- 顶部搜索栏(cmdk)支持拼音首字母匹配,输入「cls」即可定位财联社卡片;
- 卡片右上角的刷新、星标图标可单独触发回源或收藏。
接入自定义财经数据源
三步接入:
- 在 server/sources/ 下新建文件,用 defineSource 导出,返回
{id, title, url, pubDate?}数组; - 在 shared/sources.json 注册键名与 interval;
- 重启。抓取函数通过 glob 自动发现(server/getters.ts),无需手动登记。
源站有 RSS 的话直接用 defineRSSSource(见 server/utils/source.ts),传个地址即可。
把接口接进 MCP 客户端
/s?id=wallstreetcn-quick返回纯 JSON、结构稳定,可包装成 MCP(Model Context Protocol,让大模型调用外部工具的标准协议)工具,AI 助手就能直接读取本实例最新快讯、生成行情速报。
常见问题
问:页面开着但快讯不更新?先访问/s?id=cls-telegraph看updatedTime。它长时间不变且 ENABLE_CACHE=true,说明缓存工作正常,你拿到的是最近一次缓存;要看实时数据,登录后请求加latest=true。若关闭缓存仍不更新,查服务端日志里的回源报错,通常是限流或反爬。
问:ENABLE_CACHE 改成 false,回源请求却没变多?关闭缓存后/s每次请求都会回源,但浏览器端还有 React Query 的前端缓存,短时间重复点击不会真正打到服务器。验证请用接口直连,不要看页面。
问:为什么 36氪 的卡片不可用?配置里带"disable": "cf"的条目因 Cloudflare 质询拦截被停用,36氪属于此类;财经栏目可用金十数据、格隆汇等源替代。
写在最后
newsnow 把「多个财经 App」压缩成「一列卡片」:5 分钟粒度的双源抓取加 30 分钟缓存层,是实时与开销的平衡点。想提交新数据源,先读 CONTRIBUTING.md。下期预告:基于/s接口搭建你自己的财经监控看板。
【免费下载链接】newsnowElegant reading of real-time and hottest news项目地址: https://gitcode.com/GitHub_Trending/ne/newsnow
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考