前阵子群里有人吐槽:“现在想盯一个网站的内容更新,怎么这么难?要么天天手动刷,要么开一堆 App 被推送轰炸。”我回了一句:“你缺的是一个 RSS 订阅体系。”然后顺手把 RSSHub 加浏览器插件那套东西丢过去。十分钟后他在群里发了一串感叹号,说“这个太逆天了”。
这事其实一点都不神秘。把“万物皆可 RSS”这句话落到实处,靠的是一个插件化设计的开源项目——RSSHub。它的核心思路非常简单:任何网站,只要能抓到数据,就能通过一条“路由规则”变成标准的 RSS 订阅源。再配合浏览器端的自动发现插件、一个自建的阅读器,你确实可以在几分钟内把几十个网站、账号、关键词全部收进同一个信息流里。这就是标题里“3分钟订阅整个互联网”的真实含义,不是夸张,是操作流程本来就快。
这篇文章我会把这套东西从底层逻辑到落地实操完整讲一遍。适合谁看?信息重度消费者、做行业情报监控的产品经理、自媒体运营、科研人员,以及所有不想被算法喂饭、想重新拿回信息主动权的人。哪怕你完全没接触过 RSS,跟着步骤走也能跑通。
1. 先想明白为什么:RSS 这个老技术为什么值得重新捡起来
1.1 现在获取信息的几个真实痛点
说 RSS 之前,先看看我们现在每天是怎么获取信息的。打开今日头条、抖音、小红书,算法会告诉你“你可能喜欢”,于是你看到的信息越来越窄,越来越像你自己。需要跨平台追踪的 UP 主、公众号、微博博主、开源项目、论文作者,分散在各处,你被迫装了十几个 App。更要命的是,平台的推送逻辑是“它想让你看什么”,不是“你想看什么”。你明明只关心某个作者的新论文,平台却觉得你更该看热门八卦。
这种模式最大的问题是你永远在被动接收。你想主动订阅一个特定的人、一个特定的关键词,恰恰没有入口。搜索结果页是一次性的,过去的就过去了,你不会每天去重搜一遍;期刊网站你也很难天天刷,只能等着邮件提醒。
信息越来越丰富,获取越来越高效,其实是个错觉。效率高的是平台,不是你。
1.2 RSS 的核心价值:订阅粒度与信息主权
RSS 是二十多年前的老协议,但它的设计思想现在看仍然领先。它把“信息获取”拆成了两件事:你决定订阅什么,然后由阅读器统一拉取。没有算法,没有推荐,没有信息流排序。你订阅了某个作者,他发的东西就会一条不落地出现在你的阅读器里;你没订阅的,再热闹也和你无关。
这就是订阅粒度的问题。在 RSS 体系里,你可以做到非常精细的控制:
- 订阅一个具体的 GitHub 仓库的 Release,只关注它是否发布新版本;
- 订阅某个微博关键词的搜索结果,而不是某个博主的所有碎碎念;
- 订阅一个学术作者的论文列表,他发了新文章你第一时间就能看到。
能做到这些,靠的不是某个大平台大发慈悲开放接口,而是一个插件化的中转服务——RSSHub。它的思路是把“抓取某个网站的特定内容”抽象成一条条可插拔的路由规则,社区里已经积累了上千条。你要做的只是找到你要的那条,填上参数,然后把它丢给阅读器。
RSSHub 这个名字起得很贴切:它像一个“路由枢纽”,你在一边输入目标网站,另一边输出标准 RSS。中间发生了什么你不用关心,你只需要知道,几乎任何有内容、有规律更新的网站,都可以通过它变成订阅源。
2. 插件化的核心秘密:路由机制是怎么把任意网页变成订阅源的
2.1 先拆解一下路由到底在干什么
在 RSSHub 里,每接入一个目标网站,就对应一条或多条“路由”。所谓路由,本质就是一段配置代码,它至少包含三样东西:
- 匹配规则:URL 里哪段是动态参数,比如用户名、仓库名、关键词;
- 抓取逻辑:请求目标网站的哪个地址,是否需要登录、是否需要渲染 JS;
- 输出字段:把抓到的网页内容,映射成 RSS 标准里的标题、链接、摘要、发布时间。
如果你用过 Express 这类 Node.js 框架,对这个模式不会陌生。RSSHub 自己就是 Node.js 写的,路由的模式也很像,每条路由就是一个函数。比如 GitHub Release 这条路,用户在浏览器里访问的订阅地址可能是:
/rsshub/github/release/diygod/rsshub翻译成实际行为就是:去 GitHub 抓 diygod 这个用户下 rsshub 仓库的 Releases 页面,把里面的版本号、更新说明、发布时间解析出来,生成一个 RSS XML。同样的规则,把用户名和仓库名换成别的,就变成了另一个项目的订阅源。
这就是“参数化”三个字的含义:规则是固定的,参数是活的。
2.2 为什么要做成插件化架构:一次跨领域的类比
这里我想用一个看起来完全不相关的领域来帮助你理解——SolidWorks 机械设计里的零件参数化插件。
用过 SolidWorks 的朋友都知道,做机械设计的时候,一个法兰盘、一根轴、一个齿轮,建模流程其实是高度重复的:选基准面、画草图、标注尺寸、拉伸切除、倒角……如果每个项目都从零开始建模,效率极低。参数化插件的做法是把这些重复动作抽象成规则,把关键尺寸暴露成参数,你改一个直径、改一个厚度,模型自动重新生成。
RSSHub 的插件化架构和这个如出一辙。RSSHub 的维护者不可能为几千个网站维护一套臃肿的主程序,所以把“针对某类网站的信息抓取”抽象成独立路由。主框架只负责三件事:请求分发、执行路由规则、把结果输出成 RSS。而每接入一个新的网站,只需要新增一个对应的路由插件,不动主框架。
插件化架构带来的三个直接好处,我觉得是这套体系能持续壮大的真正原因:
- 社区协作门槛低:你不需要理解整个项目,只需要会写一条路由,就能为某个网站接入支持。RSSHub 的上千条路由就是这样被一点一点填出来的。
- 单点故障可替换:某条路由挂了,只影响那一个订阅源,其他一切照常。你可以等社区修复,也可以自己临时改。
- 路由即文档:每一条路由的参数说明本身就是使用文档,用户不需要看源码,只需要知道“填什么参数”。
说白了,插件化就是把“重复劳动”变成“规则复用”。SolidWorks 插件复用建模步骤,RSSHub 插件复用抓取逻辑。跨领域一看,设计思想是通用的。
2.3 近距离看一条路由的解析过程
拿一个典型的路由做示例,拆给你看。假设目标是订阅某个视频平台 UP 主的投稿动态,路由 URL 可能是:
https://rsshub.app/bilibili/user/video/22675798这条地址拆开:
| 段落 | 作用 |
|---|---|
bilibili | 目标站点标识,决定使用哪套抓取逻辑 |
user/video | 子路由,表示“用户投稿的视频列表” |
22675798 | 动态参数,即 UP 主的 UID |
当请求到达 RSSHub,实际发生的事是:RSSHub 用这个 UID 拼接出目标站点对应的页面地址,然后发送 HTTP 请求,拿到页面 HTML 后根据路由里预设的解析规则,提取出每个视频的标题、简介、封面、发布时间,最后封装成 RSS 2.0 格式的 XML 返回。
这里有一个很多人会忽略的点:有些页面内容是通过 JavaScript 异步加载的,初始 HTML 里根本没有数据。RSSHub 对这类站点需要在路由层额外启用无头浏览器渲染,等 JS 执行完再去拿真实数据。这也是为什么自建实例时官方建议预留一定内存,因为一旦大量路由需要走实时渲染,资源消耗幕后就拉开了。
从“用户填参数”到“服务端抓页面”,再到“输出标准 RSS”,整套链路实际上就是一个从 URL 到 RSS 的转换器。理解了这条链路,后面我们看到任何“没有 RSS 的网站”都不会慌,因为你知道剩下的事只是找对路由和参数而已。
3. 从零实操:Docker 部署 RSSHub 加阅读器,3 分钟跑通
3.1 先选实例:公共实例还是自建
如果你只是想快速体验 RSSHub 的能力,最简单的办法是直接用官方提供的公共实例。RSSHub 的文档站上列出了大量现成的路由,你随便挑一个,拼好参数地址,直接粘贴到阅读器里就能订阅。我最初就是先这样试了一只“B站 UP 主”订阅源,确认输出正常后,才开始考虑正经搭建。
但公共实例有三个绕不开的问题:
- 稳定性看运气:公共实例所有人共用,流量大,偶尔会出现限流甚至短暂不可用;
- 部分目标网站对公共云 IP 不友好,反爬机制更严格;
- 你无法查看日志,订阅源失效时很难排查到底是路由坏了还是实例被限了。
所以我的建议很直接:想认真用,就花 10 分钟自建一个。Docker 方案是目前最简单、最省心的选择。
3.2 Docker 自建 RSSHub:部署、更新、验证
先确认机器上已经装了 Docker 和 Docker Compose。没有的话先装上,这不是什么高级操作,网上教程一大堆。然后随便找个工作目录,写一个docker-compose.yml,内容大概是这样:
services: rsshub: image: diygod/rsshub:latest container_name: rsshub restart: always ports: - "1200:1200" environment: - NODE_ENV=production - CACHE_TYPE=memory - CACHE_EXPIRE=600 - LISTEN_INADDR_ANY=0 - CORS_ALLOW_ORIGIN=* volumes: - ./data:/app/data保存后执行:
docker compose up -d等服务跑起来,访问http://你的服务器IP:1200。能看到 RSSHub 的路由文档页面,说明服务已经正常。再顺手测试一条已知路由,比如用 GitHub 仓库的 Release 订阅,看能不能正常返回 XML,能返回就说明链路通了。
日常维护几乎为零,建议定期更新镜像:
docker compose pull docker compose up -d这里有两个从实战中得出的提醒。一个是 RSSHub 默认监听 1200 端口,建议在前面套一层 Nginx 反代并且强制 HTTPS,否则订阅地址里带着 IP 和裸端口,在部分网络环境里很容易被拦截。另一个是环境变量里的CACHE_EXPIRE,我习惯设为 300 到 600 秒,这样即使目标网站短暂抽风,你也不会立刻在阅读器里看到一个刷新失败的源。设得太长又会让新内容延迟很久才出现,这个值需要平衡。
3.3 浏览器端神器:RSSHub Radar,让订阅源自己“跳”出来
自建完 RSSHub,先把浏览器插件装上。RSSHub Radar 是官方生态里的一个浏览器扩展,作用非常关键:当你打开任意一个网页时,它会在后台检查这个网站有没有对应的 RSSHub 路由规则,如果有,扩展图标上会亮起提示,点开后直接给出当前订阅地址。
这套体验完全改变了“找订阅源”的流程。以前你要先去 RSSHub 文档站翻路由清单,再对照参数拼接 URL,现在你只要正常浏览网页,它自动告诉你“这个页面可以订阅”。
以订阅某个 UP 主的视频为例:
- 在浏览器里打开他的主页;
- Radar 插件检测到页面匹配 B站的用户路由,图标亮起;
- 弹出面板里直接显示最终的订阅地址,点复制;
- 去阅读器里粘贴添加,完成。
整个过程不到 30 秒。
Radar 插件的本质是一个本地路由索引。它内置了 RSSHub 的文档数据库,负责匹配“URL 模式”和“路由规则”,不涉及任何抓取行为,所以非常轻量。
3.4 阅读器选哪个:FreshRSS 还是 Tiny Tiny RSS
订阅源有了,需要一个地方统一阅读。这张对比表是我自己的使用感受:
| 维度 | FreshRSS | Tiny Tiny RSS |
|---|---|---|
| 部署难度 | 简单,一个容器搞定 | 略复杂,依赖 PostgreSQL 或 MySQL |
| 多用户支持 | 不支持,适合个人 | 原生支持,适合团队共享 |
| 自定义扩展 | 官方插件与主题较多 | 有社区插件体系 |
| 界面风格 | 清爽简洁 | 高可定制,支持主题化 |
| 刷新机制 | 依赖 cron 定时任务 | 自带后台任务 |
我的建议很个人化:一个人用就上 FreshRSS,省心;团队几个人共用,或者你特别想折腾界面和数据关联,再考虑 Tiny Tiny RSS。
FreshRSS 的部署同样走 Docker:
services: freshrss: image: freshrss/freshrss:latest container_name: freshrss restart: always ports: - "8080:80" environment: - TZ=Asia/Shanghai - CRON_MIN=*/5 volumes: - ./data:/var/www/FreshRSS/data启动后,浏览器访问http://你的服务器IP:8080,按安装向导初始化,然后在订阅管理里把雷达插件复制过来的地址粘贴进去,点添加。做完这一步,你的订阅体系已经成立了。
3.5 完整流程实测:3 分钟复现“订阅整个互联网”
下面是完整复现一遍。假设我的目标是订阅五个东西:一个 B 站 UP 主、一个 GitHub 仓库的 Release、一个微博关键词、一个行业科技媒体的全文、一个学术作者的论文列表。按顺序操作:
- 安装 Docker 并部署 RSSHub,约 1 分钟(前提是已经安装了 Docker,否则会多花几分钟);
- 部署 FreshRSS,约 1 分钟;
- 浏览器装好 RSSHub Radar,打开目标网站逐个复制订阅地址,1 分钟内完成五个源的添加。
这就是“3 分钟”说法的来源。当然,如果目标是监控一批特定网站,主要工作其实花在前期调研,而不是操作本身。
这个流程实测下来稳不稳?稳。但有几个细节需要处理,不然会出问题:
- 某些目标网站的路由需要额外的参数或环境变量支持,比如那些需要走无头浏览器的站点,自建实例时要按路由文档要求打开对应的环境变量;
- RSSHub 的公共实例偶尔抽风,如果你要重度使用,一定要优先自建;
- FreshRSS 的定时任务是靠 cron 驱动的,所以我上面特意设置了
CRON_MIN=*/5,让它每五分钟拉取一次。
把这些处理好,你得到的是一套完全自主的信息获取系统。没有推荐算法干预,没有平台推送噪音,只有你真正在乎的内容。
4. 科学场景实战:用 RSS 精准追踪特定作者的文献更新
4.1 科研和行业情报场景下的痛点
前面说的都是折腾各种网站,实际上 RSS 的价值在科研场景里被严重低估了。做科研的人都有这个体会:盯住一个大牛比盯住一本期刊更高效。某个领域出了新论文、新进展,真正值得你关注的就是那么几个团队。但学术信息的获取方式至今仍然很原始:靠期刊订阅邮件、靠 Google Scholar 提醒、靠人脉互相转发。
这些方式要么延迟高,要么噪音大。邮件提醒经常被邮箱过滤规则误伤,期刊订阅只能监控特定刊物,跨库的效果很差。你想实现的目标其实很简单:指定一个作者,他一旦有新文献上线,我第一时间知道,且只让我看到这一条。
RSS 天然适合干这件事。因为任何“搜索结果页”和“作者公开页面”,本质上都是定期更新的内容源。只要有一条路由能把这些页面转换成 XML,追踪就成立了。
4.2 把作者检索变成可订阅源
RSSHub 里有一类路由正是为学术检索服务的。以 Google Scholar 为例,Scholar 的搜索结果页背后是一个支持强大检索语法的接口,你可以把检索词从“某个关键词”换成“某个作者”。核心参数我建议这样组织:
https://你的RSSHub地址/google/scholar/author:作者名字+Surname具体实现的原理是:RSSHub 拿到这个参数后,把author:xxx作为检索式发给 Scholar 的搜索接口,拿回结果页,然后解析出论文标题、作者列表、摘要、引用次数和发布出处,输出成 RSS 条目。
注意:RSSHub 的路由参数在不同版本里可能有调整,具体名字以你部署实例的文档页为准。我在这里不写死路径,因为项目迭代很快,写死了反而容易误导。真正重要的是那套思路:找一个支持构建检索式的学术数据库,把检索式放进路由参数里,出来的 RSS 就是你定制的监控源。
同样的逻辑可以延伸到 PubMed。PubMed 的检索式本身是通过http://www.ncbi.nlm.nih.gov/pubmed/?term=...传递的,RSSHub 的 PubMed 路由支持把完整的检索式作为参数传进去,于是你可以订阅“某个关键词 + 某位作者”这样高度组合化的检索式,比单独订阅期刊的范围精确得多。
4.3 追踪链路搭建实录
我实际搭建过一个追踪三位研究者文献更新的订阅组,步骤可以做一次记录:
- 打开 Google Scholar,按作者名搜索,找到目标作者的学术主页,确认 URL 里包含该作者的唯一 ID;
- 在 RSSHub 文档站里找到 Google Scholar 相关路由,把作者的 ID 或检索式填入参数;
- 先用浏览器直接访问拼好的订阅 URL,看看能否输出 XML,以及摘要里是否包含了你关心的字段;
- 把这个地址挂进 FreshRSS,设置刷新频率为每 30 分钟一次;
- 给这个订阅源打上标签“文献追踪”,和其他资讯源做区分。
实测效果:这个订阅组跑了一个多月,新论文的发现时间基本能和 Google Scholar 官方提醒持平,甚至更快,因为 RSS 抓取是分钟级的。最关键的体验是,我的邮箱里再也不会混入学术提醒了,全部内容都安静地待在自己的信息流里,统一处理。
这里有一个很实际的避坑经验:Google Scholar 的反爬机制比较敏感,如果请求频率太高,容易返回 403 页面或验证码。所以自建 RSSHub 时,请务必把路由对应的缓存时间设大,比如一小时。缓存会让同一个订阅地址在短时间内只抓取一次,既保证更新速度,又不过度打扰目标网站。
5. 实战过程中的坑与排查记录
5.1 订阅源突然不更新?先定位问题在哪一层
订阅体系跑久了,总会遇到某个源“断更”。别急着怀疑是目标网站没更新,按以下顺序排查,问题很快能定位:
- 先用浏览器直接访问订阅地址,看有没有内容输出。有,说明问题在阅读器刷新逻辑或网络链路;没有,问题在 RSSHub 或目标网站。
- 再访问 RSSHub 的日志页面或容器日志。如果在日志里看到 403、429、5xx,基本可以断定目标网站拒绝访问或路由抓取逻辑失效。
- 去看目标网站本身有没有改版。如果页面结构变了,路由里的解析规则就会失配,输出为空或字段丢失,这种情况只能等社区修复,或者自己改路由。
我遇到过最典型的案例是某个新闻类订阅源突然停更,排查后发现目标网站启用了新的反爬策略,RSSHub 发出的请求被当成爬虫拦截。最终解决方式是给 RSSHub 实例配置了代理出口和合理的 User-Agent 头,才恢复正常。
5.2 部署层面的几个高频问题
部署阶段最容易踩的坑:
| 现象 | 原因 | 解决办法 |
|---|---|---|
| 访问实例返回 504 | 内存不足,Node 进程崩溃 | 给容器预留至少 512MB 内存 |
| 镜像拉取失败 | 网络问题 | 配置镜像加速源,或使用代理 |
| 部分路由提示需要 Redis | 缓存类型选的是 memory,而已开启 Redis 依赖 | 按路由文档开启REDIS_URL环境变量 |
| HTTPS 证书反复报错 | 没有配反代 | 加一层 Nginx 或 Caddy 做终止 TLS |
另外,如果你访问某个路由时提示“需要在环境变量中启用某功能”,别硬试,先去看这个路由在文档里的说明,很多时候是作者特意屏蔽了不稳定的源,等真稳定了才放开。
5.3 反爬限制:目标网站不是你想抓就能抓的
真正让 RSSHub 路由失效的头号原因是目标网站的反爬策略。常见的有:限制请求频率、检查 User-Agent、校验 Cookie、对数据中心 IP 段进行整体阻断。
作为使用者,你能做的调整有限,但有三个习惯能减少踩雷:
- 自建实例的出口 IP 质量很重要,别用被滥用的公共 IP 段;
- 对访问频率高的订阅源,把
CACHE_EXPIRE调高,让每次抓取之间的间隔更长; - 大部分专业源和学术源对低频请求容忍度很高,反而是资讯类、社交媒体类更容易遇到风控。
5.4 像 SolidWorks 参数化插件一样,自己造一条路由
最后说一下扩展。RSSHub 的真正魅力在于,你不仅能“用别人写好的路由”,还能自己写路由。这就像 SolidWorks 里你不仅是使用现成的参数化插件,你还能根据自己的零件改进设计,把新的建模流程固化成新插件。
自己写路由并没有想象的难。RSSHub 项目的文档里已经给出了路由开发模板,一个最简单的路由核心代码大概是这样:
module.exports = { route: '/example/:id', parameters: { id: '唯一标识' }, name: '示例源', categories: ['其他'], async handler(ctx) { const { id } = ctx.params; const response = await fetch(`https://example-site.com/item/${id}`); // 解析页面内容,映射为 RSS 条目 return { item: [...] }; }, };这段代码的意图很直白:接收参数id,请求目标页面,解析内容,返回条目数组。你只要会一点 JavaScript 基础,能看懂简单的网页结构,就能写出自己的路由。写完放在项目的lib/routes/目录下,本地测试通过后,可以直接提交 Pull Request 回馈给社区。
我自己写的第一条自定义路由,是给某个小众设计资源站用的。那个站没有任何 RSS 输出,首页也只展示最近十篇文章。按常规思路只能每天手动刷。后来我照着 RSSHub 的代码模板写了一条路由,把首页的列表解析成订阅源,挂进 FreshRSS 后就再也没手动打开过那个网站。
从设计理念上说,这和 SolidWorks 参数化插件是相通的:把重复的动作抽象成规则,把变化的部分暴露成参数,主程序保持精简,扩展能力全部交给插件。RSSHub 正是因为走了这条路,才可能覆盖上千个形态各异的网站。而 CSV 你也能利用这个机会,把任何你想要盯住的信息源变成自己的订阅,不需要等待哪个平台大发慈悲开放接口。
我个人在实际使用过程中最深的一点体会是:RSS 这套体系,越早搭越划算。刚开始接入了十几个源,确实还感觉不到和普通刷网页有多大区别。但当你慢慢积累了上百个精准源之后,那种信息完全按你意图流动的秩序感,是所有算法推荐都替代不了的。真正值得长期关注的,从来不是信息哪里最多,而是你能不能在最需要的地方,第一时间看到它。