监控、筛选并定时汇总RSS/Atom信息流。适用场景:(1)追踪行业新闻或竞争对手博客,(2) 在多个来源设置关键词提醒...
RSS 聚合器是一项面向实际任务的技能,主要用于监控器 RSS/ Atom 以一个调度方式输入, 以关键字或日期过滤, 以及路径摘要到您所选择的频道;Setup. 要求种子 Python 包 :.;
该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;
若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
按计划监控 RSS/Atom 订阅源,支持按关键词或发布日期过滤,并将摘要路由至您偏好的通知渠道。
需安装 Python 包 feedparser:
pip install feedparser
保存为 scripts/fetch_feeds.py:
#!/usr/bin/env python3
"""RSS/Atom feed fetcher with filtering and summarization."""
import feedparser
import sys
import json
from datetime import datetime, timedelta
from pathlib import Path
def parse_date(entry):
"""Extract publication date from entry."""
for field in ('published_parsed', 'updated_parsed', 'created_parsed'):
if hasattr(entry, field) and entry.get(field):
return datetime(*entry[field][:6])
return None
def fetch_feed(url, max_age_days=None, keyword_filter=None):
"""Fetch and filter feed entries."""
feed = feedparser.parse(url)
entries = feed.entries
# Filter by age
if max_age_days:
cutoff = datetime.now() - timedelta(days=max_age_days)
entries = [e for e in entries if parse_date(e) and parse_date(e) >= cutoff]
# Filter by keyword
if keyword_filter:
kw_lower = keyword_filter.lower()
entries = [e for e in entries if kw_lower in (e.get('title', '') + e.get('summary', '')).lower()]
return {
'title': feed.feed.get('title', url),
'url': url,
'entries': [
{
'title': e.get('title', 'No title'),
'link': e.get('link', ''),
'published': parse_date(e).isoformat() if parse_date(e) else None,
'summary': e.get('summary', e.get('description', ''))[:500]
}
for e in entries
]
}
if __name__ == '__main__':
url = sys.argv[1] if len(sys.argv) > 1 else ''
max_age = int(sys.argv[2]) if len(sys.argv) > 2 else None
keyword = sys.argv[3] if len(sys.argv) > 3 else None
if not url:
print(json.dumps({'error': 'URL required'}))
sys.exit(1)
result = fetch_feed(url, max_age, keyword)
print(json.dumps(result, indent=2))
cron_add(
name="Tech news digest",
schedule={"kind": "cron", "expr": "0 8 * * 1-5", "tz": "Africa/Johannesburg"},
payload={
"kind": "agentTurn",
"message": "Run: python scripts/fetch_feeds.py https://news.ycombinator.com/rss 7. Then summarize the top 5 stories as a clean bullet list with titles and links."
},
delivery={"mode": "announce"},
sessionTarget="isolated"
)
// First, create scripts/multi_fetch.py:
"""
import feedparser, json, sys
from scripts.fetch_feeds import fetch_feed
feeds = [
"https://techcrunch.com/feed/",
"https://www.theverge.com/rss/index.xml",
"https://feeds.feedburner.com/TechCrunch/"
]
results = [fetch_feed(url, max_age_days=1) for url in feeds]
print(json.dumps(results, indent=2))
"""
然后添加定时任务:
cron_add(
name="Industry pulse",
schedule={"kind": "cron", "expr": "0 */6 * * *", "tz": "UTC"},
payload={
"kind": "agentTurn",
"message": "Run: python scripts/multi_fetch.py. Filter entries from last 6 hours. Post new articles to #news channel on Discord with title + link."
},
delivery={"mode": "announce"},
sessionTarget="isolated"
)
cron_add(
name="AI keyword alert",
schedule={"kind": "cron", "expr": "0 */4 * * *", "tz": "UTC"},
payload={
"kind": "agentTurn",
"message": "Run: python scripts/fetch_feeds.py https://feeds.feedburner.com/venturebeat/Settings 1 "AI OR machine learning OR LLM". If results have entries, format as: **Alert** [Article Title](URL). Send to Discord #alerts channel."
},
delivery={"mode": "webhook", "to": "https://discord.com/api/webhooks/..."},
sessionTarget="isolated"
)
cron_add(
name="Feed health check",
schedule={"kind": "cron", "expr": "0 9 * * *", "tz": "UTC"},
payload={
"kind": "agentTurn",
"message": "Check if these feeds are still live: Hacker News (https://news.ycombinator.com/rss), TechCrunch (https://techcrunch.com/feed/). Run fetch without filters. If any feed returns 0 entries or error, alert via webhook."
},
delivery={"mode": "announce"},
sessionTarget="isolated",
failureAlert={"after": 3, "mode": "announce", "cooldownMs": 86400000}
)
cron_add(
name="RSS to Notion",
schedule={"kind": "cron", "expr": "0 7 * * *", "tz": "Africa/Johannesburg"},
payload={
"kind": "agentTurn",
"message": "Run: python scripts/fetch_feeds.py https://example.com/rss 1. Create Notion page for each entry in your Reading List database with title, link, and summary as page content."
},
delivery={"mode": "none"},
sessionTarget="isolated"
)
# Test a feed directly python scripts/fetch_feeds.py[max-age-days] [keyword-filter] # Example python scripts/fetch_feeds.py https://news.ycombinator.com/rss 7 python scripts/fetch_feeds.py https://techcrunch.com/feed/ 1 "AI"
可通过以下方式在任意网站查找 RSS 订阅源:
/feed 或 /rsssite:rss 进行搜索常见订阅源地址格式:
https://www.youtube.com/feeds/videos.xml?channel_id=CHANNEL_IDhttps://www.reddit.com/r/SUBREDDIT.rss(获取完整内容需身份认证)| 现象 | 原因 | 解决方法 |
|---|---|---|
| 返回空条目列表 | 订阅源可能需要身份认证,或仅提供 XML 内容(不含 HTML 渲染) | 使用 curl 直接请求并检查原始 feed 响应 |
feed 解析出现 decode error |
编码格式异常 | 在 feedparser.parse() 调用中显式指定 , encoding='utf-8' |
| Unicode 解析错误 | 存在非 UTF-8 字符 | 在 feedparser.parse() 调用中添加参数 , response_encoding='utf-8' |
| 仅返回较旧条目 | max_age_days 设置过于严格 |
调高该值,或移除该过滤条件 |
| 摘要内容缺失 | 站点屏蔽了 feed 抓取行为 | 尝试使用 e.get('content', [{}])[0].get('value', '') 获取完整正文内容 |
fuzzy-cron-scheduler skill — 实现周期性订阅源检查的调度能力notion-integration skill — 将文章存入 Notion 数据库discord skill — 将文章推送至 Discord 频道webhook-automation skill — 通过 HTTP webhook 向任意终端发送数据相关专题
热门下载
相关下载
精品课程
共6课时 | 54.7万人学习
共89课时 | 134.1万人学习
共49课时 | 82.6万人学习
最新文章