借助Github Action实现友圈动态自动获取——小十友圈RSS聚合工具

目录

回归博客内容创作也有几月有余,这期间认识了很多独立博客站长,也重新联系上了一些老朋友。友链作为独立博客的宝贵财富,在快节奏的今天,能够保留这种传统意义上的网友社交形式,显得格外有意义。

这次回归以来,我发现了很多友链展示的新形式,其中通过RSS自动获取并展示好友动态就是其中之一。市面上已有一些成熟的工具,最初我使用的是 Rock-Candy-Tea/hexo-circle-of-friends 这个开源项目。但该项目功能较为复杂,而我只需要核心的RSS聚合功能,通过定时更新data.json文件,再配合前端代码解析展示朋友动态。

对我来说,需求其实很简单:通过友链页面上的网站链接以及自定义的一些链接,自动获取相关动态并生成到json文件中。因此,我开发了一个轻量级但功能完整的RSS聚合工具:小十友圈RSS聚合工具,并利用GitHub Actions实现了全自动化运行,现已在GitHub上开源。

项目地址https://github.com/Jiosanity/xiaoten-rss.git

概述

小十友圈RSS聚合工具 是一个轻量级但功能完整的RSS聚合工具,它能够自动从友链页面抓取友链信息,发现并验证RSS源,聚合最新文章,生成标准化的JSON数据文件。通过GitHub Actions,定时自动运行,确保数据的实时性。

主要实现方式

模块化设计

小十友圈RSS聚合工具采用高度模块化的设计,确保各组件职责单一且易于维护:

FriendRSSAggregator (主控制器)
├── ConfigParser (配置解析器)
├── SiteFilter (站点过滤器) 
├── LinkPageScraper (友链爬取器)
├── RSSFetcher (RSS获取器)
├── DataAggregator (数据聚合器)
└── CacheManager (缓存管理器)

数据处理流程

  1. 配置加载 → 读取YAML配置文件
  2. 友链发现 → 从友链页面爬取 + 手动配置合并
  3. 站点过滤 → 黑白名单机制去噪
  4. RSS探测 → 多级回退的Feed URL发现
  5. 内容获取 → 解析RSS/Atom源
  6. 数据聚合 → 时间排序、去重、格式化
  7. 结果输出 → 生成标准JSON文件

核心技术实现

1. 友链获取方式

系统支持两种友链获取方式:

自动爬取

class LinkPageScraper:
    def scrape(self, url: str) -> List[Dict[str, str]]:
        # 使用CSS选择器从友链页面提取结构化数据
        author_elements = soup.select(self.rules.get('author')[0].get('selector'))
        # 提取名称、URL、头像信息

手动配置

SETTINGS_FRIENDS_LINKS:
  list:
    - ["小十博客", "https://www.xiaoten.com/", "https://www.xiaoten.com/avatar.png"]
    - ["王叨叨", "https://wangdaodao.com/", "https://cdn.xiaoten.com/friends/wangdaodao.png", "feed"]

2. 自动探测RSS源

RSS发现采用优先级策略,特别针对没有明确rss源后缀的链接,参照中文博客常见的WordPress、Typecho、Hugo等系统rss源后缀进行尝试:

def find_feed_url(self, base_url: str, custom_suffix: Optional[str] = None) -> Optional[str]:
    # 1. 检查缓存
    cached_url = self.cache.get_cached_feed_url(base_url)
    if cached_url and self._check_feed_url(cached_url):
        return cached_url
    
    # 2. 尝试自定义后缀(如果提供)
    if custom_suffix:
        feed_url = urljoin(base_url_normalized, custom_suffix)
        if self._check_feed_url(feed_url):
            return feed_url
    
    # 3. 尝试常见Feed后缀
    for suffix in self.feed_suffixes:
        feed_url = urljoin(base_url_normalized, suffix)
        if self._check_feed_url(feed_url):
            return feed_url
    
    return None

3. 时间处理

针对中文博客圈常见的时间格式问题,系统实现了智能时间解析:

def get_entry_time(entry, field_priority=['published_parsed', 'updated_parsed', 'created_parsed']):
    """智能时间获取,按优先级尝试不同时间字段"""
    for field in field_priority:
        if hasattr(entry, field) and getattr(entry, field):
            try:
                return datetime(*getattr(entry, field)[:6])
            except Exception:
                continue
    return datetime.now()

# 应用时间获取逻辑
pub_time = get_entry_time(entry, ['published_parsed', 'updated_parsed'])
update_time = get_entry_time(entry, ['updated_parsed', 'published_parsed'])

这样确保了:

  • 优先使用RSS源提供的准确更新时间
  • 在缺少更新时间时回退到发布时间
  • 最终保证时间的合理性和准确性
  • 特别处理中文博客常见的时间格式问题

4. 智能缓存与去重机制

class CacheManager:
    def get_article_id(self, article: dict) -> str:
        """基于标题和发布时间生成唯一文章ID"""
        key = f"{article.get('title', '')}{article.get('pub_date', '')}".encode('utf-8')
        return hashlib.md5(key).hexdigest()
    
    def is_article_seen(self, article: dict) -> bool:
        """检查文章是否已处理,避免重复"""
        return self.get_article_id(article) in self.cache['article_ids']

配置文件详解

小十友圈RSS聚合工具通过setting.yaml来自定义工具运转模式:

核心配置示例

# 友链页面爬取规则:
link_page_rules:
  {
    author: [{ selector: ".cf-friends a", attr: "text" }],    # 名称选择器
    link: [{ selector: ".cf-friends a", attr: "href" }],      # 链接选择器
    avatar: [{ selector: ".cf-friends img", attr: "src" }],   # 头像选择器
  }

# 站点过滤机制:使用正则表达式定义屏蔽规则
BLOCK_SITE:
  - "https://q.chyfh.com/"
  - "https?://mout.me"
BLOCK_SITE_REVERSE: false  # false为黑名单模式,true为白名单模式

# 数据处理策略
MAX_POSTS_NUM: 0      # 每站点最大文章数,0表示不限制
OUTDATE_CLEAN: 180    # 文章过期清理天数,180天前的文章自动过滤

GitHub Actions自动化部署

通过GitHub Actions实现完全自动化运行,确保数据实时更新:

# .github/workflows/aggregate-rss.yml
name: 聚合RSS订阅

on:
  schedule:
    - cron: '0 */6 * * *'  # 每6小时运行一次
  workflow_dispatch:        # 支持手动触发

jobs:
  aggregate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: 设置Python环境
        uses: actions/setup-python@v4
        with:
          python-version: '3.9'
          
      - name: 安装依赖
        run: pip install -r requirements.txt
        
      - name: 运行小十友圈RSS聚合工具
        run: python main.py
        
      - name: 提交更新
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          git add data.json
          git diff --staged --quiet || git commit -m "更新小十友圈数据"
          git push

输出数据格式

小十友圈RSS聚合工具生成标准化的JSON数据,便于前端直接使用:

{
  "updated_at": "2025-01-15T10:30:00.123456",
  "total_sites": 18,
  "total_posts": 156,
  "sites": [
    {
      "name": "小十博客",
      "url": "https://www.xiaoten.com/",
      "avatar": "https://www.xiaoten.com/avatar.png",
      "feed_url": "https://www.xiaoten.com/feed",
      "posts": [
        {
          "title": "文章标题",
          "link": "https://www.xiaoten.com/post/123",
          "description": "文章摘要内容...",
          "pub_date": "2025-01-15T08:00:00",
          "updated_at": "2025-01-15T09:30:00",
          "author": "作者名",
          "site_name": "小十博客",
          "site_url": "https://www.xiaoten.com/",
          "avatar": "https://www.xiaoten.com/avatar.png"
        }
      ]
    }
  ],
  "all_posts": [...],
  "failed_sites": [
    {
      "name": "示例站点",
      "url": "https://example.com/",
      "feed_url": "https://example.com/feed",
      "reason": "HTTP 404"
    }
  ]
}

后续使用

  • 前端集成:生成的data.json可直接被静态站点调用
  • 通知扩展:可集成Webhook实现更新通知
  • 数据备份:重要数据建议定期备份到其他存储
  • 主题适配:根据自己博客主题调整输出格式

欢迎Star:如果你觉得这个项目对你有帮助,请给项目一个Star支持!

项目地址https://github.com/Jiosanity/xiaoten-rss.git

评论