Skip to content

Instantly share code, notes, and snippets.

@roycoding

roycoding/rss.md

Created May 21, 2020
Embed
What would you like to do?
It's 2020 and I made an RSS feed for my blog (with Python)

It's 2020 and I made an RSS feed for my blog (with Python)

Roy Keyes

21 May 2020 - This is a post on my blog. Grab the RSS feed here 😉

I was recently telling someone about all of the awesome blog posts I have sitting in my backlog, just waiting to actually be written. They asked if there was a way to subscribe or get notified when my next post was live. The answer was "watch my Twitter", which was admittedly unsatisfactory.

Coincidentally I have been seeing a number of recent articles on the desire for more independent blog content and a return to RSS-based syndication. I think this is all part of a broader push for a (return to a?) more decentralized internet. And possibly a dose of nostalgia for the internet of days past.

So I decided to add an RSS feed to my blog 🤷

Since you're reading this, you'll know that I host my blog posts on Github gists. My blog index is on my website, which is on Github pages.

Looking around at options I eventually landed on the idea of creating the feed myself. There are a lot of services to create RSS feeds, but those felt like overkill for putting some links in an XML file.

After a bit of digging, I found feedgen, which is a python library for generating RSS and Atom feeds. feedgen allows you to easily build up an XML feed document from raw (meta)data. For simplicity, I'm keeping metadata about my blog posts in a CSV file. Then I simply read in the CSV file and generate a feed.

For convenience I made the script into a command line program using click. There is some hardcoded metadata specific to my blog, but you may still find the code of interest to you.

from typing import Dict

import click
from feedgen.feed import FeedGenerator
import pandas as pd

# Static metadata about my blog
blog = {
    "id": "https://roycoding.com/blog",
    "title": "The Roycoding Blog",
    "author": {"name": "Roy Keyes", "email": "roy@roycoding.com"},
    "link": "https://roycoding.com/blog",
    "logo": "https://www.gravatar.com/avatar/0b896dff2667cbfee4237e889f6d4446.jpg",
    "language": "en",
    "description": "Occasional blog posts from roycoding",
}


@click.command()
@click.argument("csvfile", type=click.Path(exists=True))
@click.option(
    "--xmlfile", help="File name of RSS XML file to create.", type=click.Path()
)
@click.option("--tabs", is_flag=True, help="Whether CSV separator is tab.")
def create_feed(
    csvfile: str,
    blog: Dict = blog,
    xmlfile: str = "rss.xml",
    tabs: bool = False,
) -> None:
    """
    Create an RSS XML file from a CSV file containing blog entry metadata.

    csvfile: (String) path to CSV file with blog post entry metadata
    blog: Internal dictionary with static blog metadata
    xmlfile: (String) path to RSS XML file to write to disk
    tabs: Boolean of whether CSV separator is a tab

    The expected CSV format is columns in order of 'title', 'url', 'date' (with a header).
    """
    if tabs:
        sep = "\t"
    else:
        sep = ","
    df = pd.read_csv(csvfile, sep=sep, parse_dates=[2])

    fg = FeedGenerator()
    fg.id(blog["id"])
    fg.title(blog["title"])
    fg.author(
        {"name": blog["author"]["name"], "email": blog["author"]["email"]}
    )
    fg.logo(blog["logo"])
    fg.link(href=blog["link"], rel="self")
    fg.language(blog["language"])
    fg.description(blog["description"])

    for i, row in df.iterrows():
        fe = fg.add_entry(order="append")
        fe.id(row["url"])
        fe.title(row["title"])
        fe.published(row["date"].tz_localize("utc"))
        fe.author(
            {"name": blog["author"]["name"], "email": blog["author"]["email"]}
        )
        fe.link({"href": row["url"], "title": row["title"]})

    rssfeed = fg.rss_str(pretty=True)
    fg.rss_file(xmlfile)


if __name__ == "__main__":
    create_feed()

So fire up your RSS reader and subscribe to my blog. I'm sure my new posts will be out real soon, any day, ymmv 😎

Please leave a comment below or ping me on Twitter @roycoding!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment