这是一个轻量的 RSS 聚合工具,它会从「友链页面」与配置的手动友链中发现 RSS/Atom 源,抓取并聚合文章,最终输出为由 OUTPUT_JSON_FILENAME 指定的 JSON 文件(默认 data.json),可供前端或静态站点使用。
核心功能(最新)
- 支持爬取静态及动态渲染(如基于 JS 获取 JSON)的友链页面(可选 Playwright)
- RSS 请求遇到 HTTP 403 时,可使用 Playwright 浏览器上下文兜底抓取
- 从友链页面按 CSS 规则自动提取站点链接
- 支持手动添加友链并可配置自定义 feed 后缀(如
rss、rss.xml等) - 自动发现并验证常见 Feed 后缀
- 支持从首页
link rel="alternate"自动发现 RSS/Atom 地址 - 黑名单 / 白名单站点过滤
- 支持不限制过期文章(
OUTDATE_CLEAN: 0表示不过滤) - 为每篇文章提供发布时间
pub_date与更新时间updated_at - 在最终输出中包含抓取失败的站点列表
failed_sites(含失败原因) - 支持上一版输出兜底与发布门禁,避免网络波动导致线上友圈数据大面积缩水
- 支持 GitHub Actions 定时运行(例如每 6 小时)
最小文件清单(保留)
main.py— 主程序setting.yaml— 配置requirements.txt— 依赖README.md— 本说明(你现在正在查看)- 输出 JSON(默认
data.json,可通过OUTPUT_JSON_FILENAME自定义)
快速使用
- 克隆并进入仓库
git clone <your-repo-url>
cd xiaoten-rss- 安装依赖
pip install -r requirements.txt
python -m playwright install chromium # 如果需要在配置中开启 js_render 抓取动态页面,则需补充安装此浏览器内核- 运行聚合
python main.py程序运行结束后会在仓库根目录写入或更新输出 JSON(默认 data.json,可在 setting.yaml 的 OUTPUT_JSON_FILENAME 中自定义,例如 rss.json)。
配置要点(setting.yaml)
LINK:友链页面 配置列表。每项可含link(URL), 以及可选属性js_render: true(开启浏览器渲染),wait_selector(等待指定 CSS 元素)link_page_rules:从友链页提取 姓名/链接/头像 的 CSS 规则SETTINGS_FRIENDS_LINKS:手动友链[name, url, avatar, optional_feed_suffix]BLOCK_SITE/BLOCK_SITE_REVERSE:黑/白名单(正则)OPTIONAL_FEED_SITE:RSS 可选站点(正则),仍会尝试发现 RSS;没发现时只计入skipped_sites,不计入failed_sitesfeed_suffix:常见 Feed 后缀尝试顺序MAX_POSTS_NUM:每站最多文章数(0 不限)OUTDATE_CLEAN:过期清理天数(≤0 表示不过滤)TIMEZONE_CORRECTION:是否换算为北京时间(true换算;false保留来源显示的时间但标注 +08:00)SORT_BY:排序字段(pub_date或updated_at)OUTPUT_JSON_FILENAME:输出文件名(如rss.json,默认data.json)STALE_FALLBACK_ENABLED:本轮抓取失败时,是否使用上一版输出中的站点数据兜底STALE_FALLBACK_INCLUDE_MISSING_SITES:友链页本轮明显缩水时,是否补回上一版中本轮未出现的站点MIN_SITE_RETENTION_RATIO/MIN_POST_RETENTION_RATIO:发布门禁,控制新结果相对上一版允许缩水的最低比例MAX_FAILED_SITES_FOR_PUBLISH:发布门禁,失败站点数超过该值时停止覆盖旧数据
- 有
feed_suffix:当手动友链为同一url指定了feed_suffix,将直接采用拼接后的地址(覆盖已从友链页自动发现的feed_url)。 - 无
feed_suffix且 URL 已存在:跳过该手动项,保留自动发现结果(避免重复)。 - 无
feed_suffix且 URL 不存在:按常见后缀(feed/、feed、feed.xml、rss、rss/、atom.xml、feed/atom/、feed/atom、index.xml、rss.xml)尝试自动发现;固定后缀均失败后,会继续读取首页中的link rel="alternate"RSS/Atom 声明。 - 黑名单不影响手动项:
BLOCK_SITE仅作用于友链页面爬取,手动配置的站点不受其限制。 OPTIONAL_FEED_SITE不会跳过探测;如果后续站点开放 RSS,会自动进入聚合。只有本轮仍未发现 RSS 时,才进入skipped_sites。
LOG_LEVEL:日志级别(DEBUG, INFO, WARNING, ERROR),默认 INFOMAX_WORKERS:并发处理友链的线程数,0 或负数表示串行处理,建议 4-8(默认 4)REQUEST_TIMEOUT:HTTP 请求超时时间(秒),默认 10FEED_CHECK_TIMEOUT:Feed URL 检查超时时间(秒),默认 5REQUEST_RETRIES:HTTP 请求重试次数,默认 1RETRY_BACKOFF:重试退避系数(秒),默认 0.3
程序启动时会读取上一版输出文件(例如 rss.json)。如果某个站点本轮 feed 抓取失败,但上一版中有该站点数据,最终输出会保留上一版文章,并为该站点标记:
stale: truestale_reason:兜底原因,如fetch_failed或not_seen_this_runlast_error:本轮失败原因last_success_at:上一版成功输出时间
发布前还会执行质量门禁:当新结果的站点数、文章数相对上一版明显缩水,或失败站点数超过阈值时,程序会报错退出。GitHub Actions 因此不会继续提交本仓库,也不会触发 static-xiaoten-com 的 ingest-rss.yml,线上会继续保留上一版健康数据。
输出格式(默认 data.json)— 速览
- 顶层:
updated_at、total_sites、total_posts、sites[]、all_posts[]、failed_sites[]、skipped_sites[] sites[i]:name、url、avatar、feed_url、posts[]sites[i].posts[j]:title、link、description、pub_date、updated_at、authorall_posts[k]:为所有文章的扁平列表,包含上面字段,且附带site_name、site_url、avatarfailed_sites[m]:抓取失败站点清单,含name、url、feed_url(如有)与reasonskipped_sites[n]:RSS 可选站点本轮未发现 Feed 的清单,不参与发布失败门禁
在 GitHub 上自动化运行
- 项目包含一个 Actions workflow(
.github/workflows/main.yml),示例设为每 6 小时运行一次。若你自定义了输出文件名(如rss.json),请相应更新工作流中对输出文件的引用(默认示例使用data.json)。 - 生成结果只提交回本仓库;随后 workflow 会触发
Jiosanity/static-xiaoten-com的ingest-rss.yml。静态仓库负责拉取rss.json、写入dist/rss.json并部署到static.xiaoten.com。
- 新增动态页面支持:通过可选的
Playwright依赖,支持抓取基于 JS 动态渲染的友链页面(通过配置js_render: true及wait_selector触发)。 - 优化程序降级逻辑:当未安装 Playwright 但配置了
js_render: true时,不会引发程序崩溃,而是会自动回退为基于requests的静态请求。 - Action 更新:内置 GitHub Action 工作流已默认加入 Playwright 环境依赖配置,保障自动化执行不受影响。
- 优化手动配置优先级逻辑:手动配置的友链不再受黑名单限制,优先级更高
- 支持自定义RSS后缀覆盖:当手动配置中指定了自定义
feed_suffix时,即使该站点已从友链页面抓取,也会使用手动配置的RSS地址覆盖 - 修复特殊RSS路径获取问题:解决了如
rss.php、article/rss.xml等非标准后缀的RSS源无法获取的问题 - 移除rss.json追踪:将自动生成的
rss.json从版本控制中移除,避免不必要的提交