Build an RSS feed from markdown blog posts in Python
Scans a folder of markdown files, extracts titles, dates, and excerpts, and generates a valid RSS 2.0 XML feed.
Python code
48 linesimport re
from pathlib import Path
from xml.etree.ElementTree import Element, SubElement, tostring
from datetime import datetime, timezone
from xml.dom import minidom
def build_rss(blog_dir, site_url="https://example.com"):
feed = Element("rss", version="2.0")
channel = SubElement(feed, "channel")
SubElement(channel, "title").text = "My Blog"
SubElement(channel, "link").text = site_url
SubElement(channel, "description").text = "Latest posts"
for md_file in sorted(Path(blog_dir).glob("*.md")):
content = md_file.read_text()
title = md_file.stem.replace("-", " ").title()
pub_date_match = re.search(r"date:\s*(\d{4}-\d{2}-\d{2})", content)
pub_date = pub_date_match.group(1) if pub_date_match else md_file.stat().st_mtime
item = SubElement(channel, "item")
SubElement(item, "title").text = title
SubElement(item, "link").text = f"{site_url}/{md_file.stem}"
SubElement(item, "pubDate").text = _format_date(pub_date)
SubElement(item, "description").text = _get_excerpt(content)
return minidom.parseString(tostring(feed)).toprettyxml(indent=" ")
def _format_date(date):
if isinstance(date, str):
return datetime.strptime(date, "%Y-%m-%d").strftime("%a, %d %b %Y 00:00:00 +0000")
return datetime.fromtimestamp(date, timezone.utc).strftime("%a, %d %b %Y %H:%M:%S +0000")
def _get_excerpt(content):
text = re.sub(r"[#>*`\[\]]", "", content)
return " ".join(text.split()[:50]) + "..."
if __name__ == "__main__":
from tempfile import TemporaryDirectory
import os
with TemporaryDirectory() as tmpdir:
Path(os.path.join(tmpdir, "hello-world.md")).write_text(
"date: 2024-01-15\n\n# Hello World\n\nThis is my first post about Python."
)
Path(os.path.join(tmpdir, "second-post.md")).write_text(
"date: 2024-02-20\n\n# Second Post\n\nLearning async programming with asyncio."
)
print(build_rss(tmpdir))
Output
<?xml version="1.0" ?>
<rss version="2.0">
<channel>
<title>My Blog</title>
<link>https://example.com</link>
<description>Latest posts</description>
<item>
<title>Hello World</title>
<link>https://example.com/hello-world</link>
<pubDate>Mon, 15 Jan 2024 00:00:00 +0000</pubDate>
<description>date: 2024-01-15 Hello World This is my first post about Python....</description>
</item>
<item>
<title>Second Post</title>
<link>https://example.com/second-post</link>
<pubDate>Tue, 20 Feb 2024 00:00:00 +0000</pubDate>
<description>date: 2024-02-20 Second Post Learning async programming with asyncio....</description>
</item>
</channel>
</rss>
How it works
The script uses Path.glob to find all .md files in the folder, then sorts them alphabetically for deterministic output. It parses each file's front-matter date field with a regex, falling back to the file's modification time if missing. The excerpt strips common markdown symbols and takes the first 50 words. xml.etree.ElementTree builds the feed structure, and minidom pretty-prints it for readability. RSS requires a fixed date format like RFC 822, which _format_date handles for both string dates and timestamps.
Common mistakes
- Forgetting to encode the XML with `encoding='utf-8'` before `tostring` might cause issues with non-ASCII characters.
- Assuming all markdown files have a `date:` line; the fallback to `st_mtime` is essential but can produce unpredictable ordering.
- Using `md_file.stem` for the link without URL-encoding spaces or special characters in filenames.
Variations
- Use `email.utils.format_datetime` from stdlib to format dates instead of manual strftime.
- Add a `<guid>` element with `isPermaLink="true"` for better feed reader compatibility.
Real-world use cases
- Automatically generating a site feed from a static site generator's `content/` folder after each deployment.
- Creating a custom RSS for a newsletters folder that mixes markdown drafts with published posts.
- Building a lightweight feed aggregator for internal team blogs that use markdown for documentation.
Sponsored
More from Automation & scripting
- Aggregate Log Errors Count by Hour in Python easy
- Automate Tweeting New Blog Posts in Python easy
- Automatically Clean Temporary Files from Applications Using Python medium
- Automatically Download the Latest Software Release from GitHub with Python medium
- Automatically Generate Charts from CSV Files with One Command medium
- Automatically Generate Hardware Inventory Reports in Python easy
Keep learning
Related tutorials and quizzes for this topic.