Sandbox
@dhvcc/rss-parser

Typed RSS parser for Python and CLI

`rss-parser` turns feed XML into typed Pydantic models, so you get autocomplete, validation, and clear errors when parsing RSS, Atom, RDF, and podcast extensions. It provides explicit parsers plus a CLI for validation, item output, and JSON Feed conversion.

54 stars5 forksPythonUpdated 23d ago
Who it's for

Builders who want to parse feeds, inspect items, or validate XML with Python code or the `rss-parser` CLI.

What it delivers

You can work with feed data as typed models instead of nested XML or dict structures.

What it does

Typed feed parsing

Parses RSS 2.0, RSS 0.91/0.92, Atom 1.0, RSS 1.0 (RDF), and podcast extensions into Pydantic v2 models.

Feed validation CLI

Provides `rss-parser validate` to check a feed, report errors, and emit JSON status when asked.

Item and JSON Feed output

Provides `rss-parser items` for NDJSON item output and `rss-parser jsonfeed` for converting supported feeds to JSON Feed.

Custom schemas

Supports generic models and subclassing so you can add fields like namespaced tags without rebuilding the whole tree.

Agent skill docs

Includes `skills/rss-parser/SKILL.md` and `context7.json` so agents can use the parser with repo-specific guidance.

How to get it

  1. 1Run
    pip install rss-parser

README

rss-parser

Typed, pydantic-powered RSS/Atom parsing for Python.

PyPI version Python versions Downloads Wheel status License

CI Docs PyPi publish

rss-parser turns RSS/Atom XML into typed pydantic models — autocomplete, validation, and clear errors instead of digging through nested dicts.

Documentation

At a glance

EcosystemPython 3.10+ — installed with pip install rss-parser, imported as rss_parser. This is not the npm package of the same name; there is no JavaScript/Node.js distribution.
Feed formatsRSS 2.0, RSS 0.91/0.92, Atom 1.0, RSS 1.0 (RDF), plus typed Apple Podcasts (itunes:*) extensions
Runtime dependenciespydantic v2 (>=2.7), xmltodict, typing-extensions
Repositorygithub.com/dhvcc/rss-parser
Documentationdhvcc.github.io/rss-parser
Packagepypi.org/project/rss-parser
LicenseGPL-3.0
Issuesgithub.com/dhvcc/rss-parser/issues
SecurityReport vulnerabilities privately — see SECURITY.md. Do not open a public issue.

Installation

pip install rss-parser

For AI coding agents

skills/rss-parser/SKILL.md is an Agent Skill: the API model, recipes and the pitfalls that trip agents up, in one file. Install it into Claude Code, Cursor, Copilot, Codex and friends with:

npx skills add dhvcc/rss-parser

The library also ships context7.json, so Context7 serves these docs with Python-specific rules.

Command line

Installing the package installs an rss-parser command — handy from a shell or an agent, with validate as the verb that has no substitute (nothing else knows the three feed schemas):

rss-parser validate feed.xml            # exit 0 ok, 1 rejected; errors on stderr
rss-parser validate --json feed.xml     # {"valid": true, "feed_type": "rss", "items": 36}
rss-parser items feed.xml | jq -r '.content.title.content'   # NDJSON, one item per line
rss-parser jsonfeed feed.xml            # JSON Feed 1.1 document (lossy - see the docs)
curl -sSL "$url" | rss-parser validate -                     # it never fetches for you

Full reference, exit codes and caveats: Command line interface.

Parsing from a URL

rss-parser does not fetch anything — it parses text you already have, so there is no parseURL/parseString (that is the npm package). Bring your own HTTP client:

import requests
from rss_parser import parse

feed = parse(requests.get(url, timeout=10).text)

parse() accepts str or bytes — pass response.content and the feed's own encoding declaration is honored, which matters for feeds that are not UTF-8. Polling, conditional GET, deduplication by guid/id and normalizing across RSS/Atom/RDF are covered in Fetching feeds from a URL.

Quickstart

from rss_parser import parse
from requests import get  # noqa

rss_url = "https://rss.art19.com/apology-line"
response = get(rss_url)

feed = parse(response.content)  # detects RSS 2.0 / 0.9x, Atom 1.0 or RSS 1.0 (RDF)

print("Language", feed.channel.language)
print("RSS", feed.version)

for item in feed.channel.items:
    print(item.title)
    print(str(item.description)[:50])

# Language en
# RSS 2.0
# Wondery Presents - Flipping The Bird: Elon vs Twitter
# <p>When Elon Musk posted a video of himself arrivi
# Introducing: The Apology Line
# <p>If you could call a number and say you’re sorry

parse() picks the right parser from the XML root element and raises UnknownFeedTypeError if the document is not a feed. If you already know the feed type, use the explicit parsers: RSSParser, AtomParser, RDFParser, PodcastParser.

Podcasts

itunes:* tags are supported out of the box, fully typed:

from rss_parser import PodcastParser

podcast = PodcastParser.parse(feed_xml)
channel = podcast.channel.content

channel.itunes_author                    # 'Wondery'
channel.itunes_owner.content.email       # 'iwonder@wondery.com'
channel.itunes_image.attributes["href"]  # artwork url

episode = channel.items[0].content
episode.itunes_duration                  # '00:05:01'
episode.itunes_episode_type              # 'trailer'

Custom fields: one subclass away

The models are generic, so extending the schema doesn't require re-declaring the whole tree:

from typing import Optional
from pydantic import Field

from rss_parser import RSSParser
from rss_parser.models.rss import RSS, Channel, Item
from rss_parser.models.types import Tag


class MyItem(Item):
    dc_creator: Optional[Tag[str]] = Field(alias="dc:creator", default=None)


rss = RSSParser.parse(data, schema=RSS[Channel[MyItem]])

rss.channel.items[0].content.dc_creator

And even without a custom schema, unknown tags are never dropped — they're kept in model_extra:

rss = RSSParser.parse(podcast_xml)
rss.channel.content.model_extra["itunes:author"]  # 'Wondery'

See Customizing the schema for mixins, repeatable tags, and the field types cheat sheet.

Migrating from 3.x

4.0 removes the legacy pydantic v1 models, fixes several RSS 2.0 spec violations, and makes the models generic and lossless. See the migration guide for the full list.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Install dependencies with uv sync (install uv).

Using pre-commit is highly recommended. To install hooks, run:

uv run pre-commit install -t=pre-commit -t=pre-push

See Contributing for tests, snapshots, and docs.

License

GPLv3

Files in the repo

Repository payload15 top-level entries
  • .github
  • docs
  • rss_parser
  • scripts
  • skills
  • tests
  • .gitignore
  • .pre-commit-config.yaml
  • context7.json
  • LICENSE
  • mkdocs.yml
  • pyproject.toml
  • README.md
  • SECURITY.md
  • uv.lock

Discussion (0)

Ask about usage, or say what you built with it

Sign in to join the discussion.

No comments yet. Be the first to say what this is good for.

More frameworks & sdks

HKUDS/nanobotFrameworks & SDKs

Ultra-lightweight, open-source, self-hosted personal AI agent framework in Python with WebUI, tools, memory, MCP, multi-agent workflows, automation, and chat apps

48k
microsoft/
SkillOpt
microsoft/SkillOptFrameworks & SDKs

SkillOpt is a text-space optimizer that trains reusable natural-language skills for frozen LLM agents through trajectory-driven edits, validation-gated updates, and deployable best_skill.md artifacts.

17k
omnigent-ai/omnigentFrameworks & SDKs

Omnigent is an open-source AI agent framework and meta-harness: orchestrate Claude Code, Codex, Cursor, Pi, and custom agents — swap harnesses without rewriting, enforce policies and sandboxing, and collaborate in real time from any device.

9.8k
kyegomez/
OpenMythos
kyegomez/OpenMythosFrameworks & SDKs

A theoretical reconstruction of the Claude Mythos architecture, built from first principles using the available research literature.

15k
D4Vinci/ScraplingFrameworks & SDKs

🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!

80k