Skip to content

Repository files navigation

feedparser-rs

Crates.iodocs.rsPyPInpmCIcodecovMSRVLicense

High-performance RSS/Atom/JSON Feed parser written in Rust, with Python and Node.js bindings. A drop-in replacement for Python feedparser that is 90-100x faster.

Features

  • Multi-format support -- RSS 0.9x, 1.0, 2.0 / Atom 0.3, 1.0 / JSON Feed 1.0, 1.1
  • Tolerant parsing -- Handles malformed feeds gracefully with the bozo flag pattern, propagated at both feed and entry level
  • HTTP fetching -- Built-in URL fetching with compression (gzip, deflate, brotli) and conditional GET (ETag/Last-Modified)
  • Podcast support -- iTunes and Podcast 2.0 namespace extensions
  • Security -- DoS protection via ParserLimits, SSRF protection, input size validation
  • Multi-language bindings -- Native Python (PyO3) and Node.js (napi-rs) bindings
  • feedparser drop-in -- Dict-style access, field aliases, same API patterns as Python feedparser

Supported Formats

FormatVersionsStatus
RSS0.90, 0.91, 0.92, 1.0, 2.0Full support
Atom0.3, 1.0Full support
JSON Feed1.0, 1.1Full support

Namespace Extensions

NamespaceDescription
Dublin CoreCreator, date, rights metadata
ContentEncoded HTML content
Media RSSMedia attachments and metadata (media:content, media:thumbnail, media:title, media:description, media:credit, media:copyright, media:rating, media:keywords)
iTunesPodcast metadata (author, duration, explicit)
Podcast 2.0Chapters, transcripts, funding
SyndicationUpdate schedule (period, frequency, base)
GeoRSSGeographic location data (point, line, polygon, box)
Creative CommonsLicense information with rel="license" links
SlashComment count (slash:comments)
WFWComment feed URL (wfw:commentRss)
Atom Threading (thr:)In-reply-to, reply count, reply datetime (RFC 4685)

Installation

Rust

cargo add feedparser-rs

Or add to your Cargo.toml:

[dependencies]
feedparser-rs = "0.5"

Important

Requires Rust 1.88.0 or later (edition 2024).

Python

pip install feedparser-rs

Note

Requires Python 3.10 or later.

Node.js

npm install feedparser-rs
# or
pnpm add feedparser-rs

Note

Requires Node.js 18 or later.

Usage

Rust

use feedparser_rs::parse;fnmain() -> Result<(),Box<dyn std::error::Error>>{let xml = r#" <?xml version="1.0"?> <rss version="2.0"> <channel> <title>Example Feed</title> <link>https://example.com</link> <item> <title>First Post</title> <link>https://example.com/post/1</link> </item> </channel> </rss> "#;let feed = parse(xml.as_bytes())?;println!("Version: {}", feed.version.as_str());// "rss20"println!("Title: {:?}", feed.feed.title);println!("Entries: {}", feed.entries.len());for entry in&feed.entries{println!(" - {:?}", entry.title);}Ok(())}

Fetching from URL

use feedparser_rs::parse_url;fnmain() -> Result<(),Box<dyn std::error::Error>>{let feed = parse_url("https://example.com/feed.xml",None,None,None)?;println!("Fetched {} entries", feed.entries.len());Ok(())}

Tip

Use parse_url for URL fetching with automatic compression handling (gzip, deflate, brotli) and conditional GET via the etag/modified parameters.

Python

importfeedparser_rsasfeedparser# Drop-in replacement# Parse from bytes, string, or URL (auto-detected)d=feedparser.parse(b'<rss>...</rss>')
d=feedparser.parse('https://example.com/feed.xml') # URL auto-detected# Attribute-style accessprint(d.version) # 'rss20'print(d.feed.title)
print(d.bozo) # True if parsing had issues# Dict-style access (feedparser-compatible)print(d['feed']['title'])
print(d['entries'][0]['link'])
# Deprecated field aliases workprint(d.feed.description) # -> d.feed.subtitleprint(d.channel.title) # -> d.feed.title

Note

Python bindings provide full feedparser compatibility: dict-style access, field aliases, and time.struct_time for date fields.

Node.js

import{parse,parseUrl}from'feedparser-rs';// Parse from stringconstfeed=parse('<rss version="2.0">...</rss>');console.log(feed.version);// 'rss20'console.log(feed.feed.title);console.log(feed.entries.length);// Fetch from URL (synchronous)constremoteFeed=parseUrl('https://example.com/feed.xml');

See Node.js API documentation for complete reference.

Cargo Features

FeatureDescriptionDefault
httpEnable URL fetching with reqwest (gzip/deflate/brotli support)Yes

To disable HTTP support and reduce dependencies:

[dependencies]
feedparser-rs = { version = "0.5", default-features = false }

Workspace Structure

CrateDescriptionPackage
feedparser-rsCore Rust parsercrates.io
feedparser-rs-nodeNode.js bindingsnpm
feedparser-rs-pyPython bindingsPyPI

Development

# Install cargo-make
cargo install cargo-make
# Run all checks (format, lint, test)
cargo make ci-all
# Run tests with coverage
cargo make coverage
# Run benchmarks
cargo make bench

See all available tasks:

cargo make --list-all-steps

Benchmarks

Measured on Apple M1 Pro, parsing real-world RSS feeds:

Feed SizeTimeThroughput
Small (2 KB)10.7 us187 MB/s
Medium (20 KB)93.6 us214 MB/s
Large (200 KB)939 us213 MB/s

Format detection: 128 ns (near-instant)

vs Python feedparser

Operationfeedparser-rsPython feedparserSpeedup
Parse 20 KB RSS0.09 ms8.5 ms94x
Parse 200 KB RSS0.94 ms85 ms90x

Tip

Run your own benchmarks with cargo bench or compare against Python with cargo make bench-compare.

MSRV Policy

Minimum Supported Rust Version: 1.88.0 (edition 2024).

MSRV increases are considered breaking changes and will result in a minor version bump.

License

Licensed under either of:

at your option.

Contributing

Contributions are welcome! Please read our Contributing Guide before submitting a pull request.

This project follows the Rust Code of Conduct.

About

High-performance RSS/Atom/JSON Feed parser for Rust with Python and Node.js bindings

Resources

Contributing

Stars

8 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages