Skip to main content

cmd-rss-feed-generator

Generate Python RSS feed scrapers from blog websites, integrated with hourly GitHub Actions

ソース情報

リポジトリ
Olshansk/rss-feeds
ソースの最終更新活動
2026年5月1日 17:54
検出された SKILL.md の言語
英語
スター
700
フォーク
72

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
cmd-rss-feed-generator
description
Generate Python RSS feed scrapers from blog websites, integrated with hourly GitHub Actions
disable-model-invocation
false
context
fork
agent
general-purpose
# RSS Feed Generator Command You are the **RSS Feed Generator Agent**, specialized in creating Python scripts that convert blog websites without RSS feeds into properly formatted RSS/XML feeds. The script will automatically be included in the hourly GitHub Actions workflow once merged. Always reference existing generators in `feed_generators/` as your primary guide. ## Table of Contents <!-- omit in toc --> - [Project Context](#project-context) - [Workflow](#workflow) - [Step 0: Classify the URL](#step-0-classify-the-url) - [Step 1: Review Existing Feed Generators](#step-1-review-existing-feed-generators) - [Step 2: Analyze the Blog Source](#step-2-analyze-the-blog-source) - [Step 3: Create the Feed Generator Script](#step-3-create-the-feed-generator-script) - [Step 4: Update feeds.yaml](#step-4-update-feedsyaml) - [Step 5: Add Makefile Target](#step-5-add-makefile-target) - [Step 6: Update README](#step-6-update-readme) - [Step 7: Test and Verify](#step-7-test-and-verify) - [Reference Examples by Type](#reference-examples-by-type) - [Common Patterns](#common-patterns) - [Troubleshooting](#troubleshooting) ## Project Context This project generates RSS feeds for blogs that don't provide them natively. The system uses: - Python scripts in `feed_generators/` to scrape and convert blog content - `feeds.yaml` as the single source of truth for the feed registry - GitHub Actions for automated hourly updates - Makefile targets for easy testing and execution ## Workflow ### Step 0: Classify the URL **Before doing anything else**, determine which of the four cases applies. Each has a different exit path. --- #### Case A: GitHub repo URL (`https://github.com/{owner}/{repo}`) GitHub provides native Atom feeds — no scraper needed. Ask the user which to track: > "This is a GitHub repo. GitHub provides native Atom feeds — no scraper needed. Which would you like to track? > > 1. **Releases** — `https://github.com/{owner}/{repo}/releases.atom` > 2. **Tags** — `https://github.com/{owner}/{repo}/tags.atom` > 3. **Commits (specific branch)** — `https://github.com/{owner}/{repo}/commits/{branch}.atom` _(ask which branch)_ > 4. **Commits (main)** — `https://github.com/{owner}/{repo}/commits/main.atom`" Once the user picks: - Construct the final Atom URL. - **Go directly to [Step 6: Update README](#step-6-update-readme)** using `[Official RSS]` format. - Do **not** create a script, add to `feeds.yaml`, or add a Makefile target. --- #### Case B: Site has a native RSS/Atom feed Fetch the page and check for a native feed **before writing any code**: 1. Look for `<link rel="alternate" type="application/rss+xml">` or `type="application/atom+xml"` in `<head>`. 2. Try common feed paths: `/feed`, `/rss.xml`, `/atom.xml`, `/feed.xml`, `/rss`, `/blog/feed`. 3. If a working feed URL is found: - **Go directly to [Step 6: Update README](#step-6-update-readme)** using `[Official RSS]` format. - Do **not** create a script, add to `feeds.yaml`, or add a Makefile target. --- #### Case C: Static site (HTML served without JavaScript rendering) Signals that `requests` + BeautifulSoup will work: - Page HTML contains article content when fetched with `curl` or `requests` - No heavy JS framework signals in the HTML (no `<div id="__next">`, no `<div id="app">` with empty body) - Articles are visible in `view-source:` **Reference generator:** `feed_generators/ollama_blog.py` (simplest), `feed_generators/blogsurgeai_feed_generator.py` (more complete), `feed_generators/paulgraham_blog.py` Use `type: requests` in `feeds.yaml`. Proceed to Step 1. --- #### Case D: Dynamic site (JavaScript-rendered content) Signals that Selenium is required: - `curl`/`requests` returns a near-empty body or a loading spinner - HTML contains `<div id="__next">`, `<div id="root">`, or similar SPA shell - Content only appears after JS execution **Reference generators:** `feed_generators/xainews_blog.py` (Selenium + cache), `feed_generators/anthropic_news_blog.py` (Selenium + cache + incremental), `feed_generators/mistral_blog.py` Use `type: selenium` in `feeds.yaml`. Proceed to Step 1. --- ### Step 1: Review Existing Feed Generators **Always read the reference generator(s) for your case before writing any code:** ```bash # For static sites cat feed_generators/ollama_blog.py cat feed_generators/blogsurgeai_feed_generator.py # For dynamic/Selenium sites cat feed_generators/xainews_blog.py cat feed_generators/anthropic_news_blog.py ``` Study these to understand: - Import structure and shared `utils` helpers - `FEED_NAME` and `BLOG_URL` constants - Date parsing patterns and fallback chains - Article extraction logic and CSS selectors - Cache + incremental update pattern (Selenium generators) - Error handling approaches ### Step 2: Analyze the Blog Source 1. **Fetch the page** (use `fetch_page` from utils for static; Selenium for dynamic). 2. **Examine the HTML structure** to identify: - Article container CSS selectors - Title elements (h2, h3, h4, or custom) - Date formats and locations - Links to full articles - Description/summary text 3. **Handle access issues**: - If the site blocks automated requests (403/429), work with a local HTML file first - The user can provide HTML via browser's "Save Page As" - Support both local file and web fetching modes in the final script ### Step 3: Create the Feed Generator Script Create `feed_generators/<name>_blog.py` following the reference for your case. **Naming conventions:** - Script: `feed_generators/{site_name}_blog.py` (e.g. `acme_blog.py`) - Feed output: `feeds/feed_{site_name}.xml` (e.g. `feed_acme.xml`) - `FEED_NAME` constant: `"{site_name}"` (e.g. `"acme"`) **Required for all generators:** - `FEED_NAME` and `BLOG_URL` constants at module level - `setup_logging()` from utils - Robust date parsing with multiple format fallback (see `xainews_blog.py`) - Article deduplication (track seen links with a set) - Per-article error handling: log warning and continue, never crash the full run - Articles sorted newest-first before feed generation **Additional requirements for Selenium generators:** - Use `setup_selenium_driver()` from utils - Use `load_cache()` / `save_cache()` / `merge_entries()` from utils for incremental updates - Support `--full` flag via `argparse` for full-reset runs (see `anthropic_news_blog.py`) - Use `sort_posts_for_feed()` from utils See [Reference Examples by Type](#reference-examples-by-type) for full structural details. ### Step 4: Update feeds.yaml Add an entry to `feeds.yaml` in alphabetical order by key: **For static (requests) sites:** ```yaml site_name: script: site_name_blog.py type: requests blog_url: https://example.com/blog ``` **For dynamic (Selenium) sites:** ```yaml site_name: script: site_name_blog.py type: selenium blog_url: https://example.com/blog ``` ### Step 5: Add Makefile Target Add targets to `makefiles/feeds.mk` in alphabetical order. **For static (requests) sites:** ```makefile .PHONY: feeds_site_name feeds_site_name: ## Generate RSS feed for Site Name $(call check_venv) $(call print_info,Generating Site Name feed) $(Q)uv run feed_generators/site_name_blog.py $(call print_success,Site Name feed generated) ``` **For dynamic (Selenium) sites — always include both incremental and full-reset targets:** ```makefile .PHONY: feeds_site_name feeds_site_name: ## Generate RSS feed for Site Name (incremental) $(call check_venv) $(call print_info,Generating Site Name feed) $(Q)uv run feed_generators/site_name_blog.py $(call print_success,Site Name feed generated) .PHONY: feeds_site_name_full feeds_site_name_full: ## Generate RSS feed for Site Name (full reset) $(call check_venv) $(call print_info,Generating Site Name feed - FULL RESET) $(Q)uv run feed_generators/site_name_blog.py --full $(call print_success,Site Name feed generated - full reset) ``` ### Step 6: Update README Add a row to the table in `README.md` in **alphabetical order** by blog name. **For scraped feeds** (Cases C and D): ```markdown | [Site Name](https://example.com/blog) | [feed_site_name.xml](https://raw.githubusercontent.com/Olshansk/rss-feeds/main/feeds/feed_site_name.xml) | ``` **For native/official feeds** (Cases A and B): ```markdown | [Site Name](https://example.com) | [Official RSS](https://example.com/feed.xml) | ``` The raw GitHub URL format must be exactly: `https://raw.githubusercontent.com/Olshansk/rss-feeds/main/feeds/feed_{name}.xml` ### Step 7: Test and Verify **Run the generator:** ```bash # Static sites uv run feed_generators/site_name_blog.py # Dynamic sites (incremental) uv run feed_generators/site_name_blog.py # Dynamic sites (full reset) uv run feed_generators/site_name_blog.py --full ``` **Verify output:** ```bash ls -la feeds/feed_site_name.xml head -50 feeds/feed_site_name.xml ``` **Validate the feed:** ```bash uv run feed_generators/validate_feeds.py ``` **Run via Makefile:** ```bash make feeds_site_name ``` **Integration checklist before declaring done:** - [ ] Script follows naming pattern: `feed_generators/{name}_blog.py` - [ ] Output file follows pattern: `feeds/feed_{name}.xml` - [ ] Entry added to `feeds.yaml` with correct `type` - [ ] Makefile target(s) added to `makefiles/feeds.mk` (Selenium: both incremental + `_full`) - [ ] README row added in alphabetical order with correct raw GitHub URL - [ ] `validate_feeds.py` passes with no errors - [ ] Articles are sorted newest-first - [ ] Duplicate articles are filtered out - [ ] Individual article failures are caught and logged (don't crash the run) ## Reference Examples by Type ### Type 1: Static (requests + BeautifulSoup) **Simplest:** `feed_generators/ollama_blog.py` - Minimal imports, straightforward `fetch_page` + BeautifulSoup - Good starting point when the HTML structure is clean **More complete:** `feed_generators/blogsurgeai_feed_generator.py` - `fetch_page` + BeautifulSoup + `dateutil.parser` - Better date handling, good error patterns **Complex static with local-file fallback:** `feed_generators/paulgraham_blog.py` ### Type 2: Dynamic (Selenium + cache) **Selenium + cache, no local-file fallback:** `feed_generators/mistral_blog.py` - Minimal Selenium setup - Good for simple JS-rendered pages **Selenium + cache + incremental + argparse:** `feed_generators/xainews_blog.py` - Full incremental update pattern with `--full` reset flag - Use this as the base template for most Selenium generators **Selenium + cache + incremental + multiple entry points:** `feed_generators/anthropic_news_blog.py` - Same as xainews but handles multiple sections from one site - Reference when a single domain has multiple feeds (e.g. `/news`, `/research`, `/engineering`) ### Type 3: Multiple feeds from one site **Reference:** `feed_generators/anthropic_eng_blog.py`, `feed_generators/anthropic_research_blog.py` - Each section gets its own `FEED_NAME` and script - Share the Selenium driver setup pattern - Add separate `feeds.yaml` entries and Makefile targets per feed ## Common Patterns ### Official RSS Detection (Case B — run before writing any code) ```python import requests from bs4 import BeautifulSoup def check_native_feed(url): resp = requests.get(url, timeout=10) soup = BeautifulSoup(resp.text, "html.parser") link = soup.find("link", rel="alternate", type=lambda t: t and "rss" in t or "atom" in t) if link: return link.get("href") # Try common paths for path in ["/feed", "/rss.xml", "/atom.xml", "/feed.xml", "/rss"]: probe = requests.head(url.rstrip("/") + path, timeout=5) if probe.status_code == 200: return url.rstrip("/") + path return None ``` ### Incremental Updates (Selenium generators) See `feed_generators/anthropic_news_blog.py` for the `get_existing_links_from_feed()` + `load_cache()` + `merge_entries()` pattern that avoids re-fetching already-seen articles. ### Robust Date Parsing
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る