A Rust library for aggregating financial news from various RSS feed sources. Port of the Python finance-news-aggregator.
| Source | Working Feeds |
|---|---|
| CNBC | 24 topics |
| MarketWatch | 4 topics |
| NASDAQ | 10 topics |
| Seeking Alpha | 12 topics |
| Wall Street Journal | 6 topics |
| Yahoo Finance | 2 topics + symbols |
[dependencies]
finance-news-aggregator-rs = "0.2.2"use finance_news_aggregator_rs::NewsClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = NewsClient::new();
// Get news from any source
let wsj = client.wsj();
let articles = wsj.opinions().await?;
println!("Found {} articles", articles.len());
for article in articles.iter().take(5) {
println!("- {}", article.title.as_ref().unwrap_or(&"No title".to_string()));
}
Ok(())
}let mut client = NewsClient::new();
// Wall Street Journal
let wsj = client.wsj();
let opinions = wsj.opinions().await?;
let world_news = wsj.world_news().await?;
// CNBC
let cnbc = client.cnbc();
let top_news = cnbc.top_news().await?;
let tech = cnbc.technology().await?;
// NASDAQ
let nasdaq = client.nasdaq();
let tech_news = nasdaq.technology().await?;
let crypto = nasdaq.cryptocurrency().await?;
// Yahoo Finance (with stock symbols)
let yahoo = client.yahoo_finance();
let headlines = yahoo.headlines().await?;
let aapl_news = yahoo.headline(&["AAPL", "MSFT"]).await?;Fetch any RSS feed directly without using a specific source:
use finance_news_aggregator_rs::news_source::NewsSource;
let generic = client.generic();
let articles = generic.fetch_feed_by_url("https://example.com/feed.xml").await?;All sources support a generic topic-based API:
let cnbc = client.cnbc();
// List available topics
let topics = cnbc.available_topics();
println!("Available topics: {:?}", topics);
// Fetch by topic name
let articles = cnbc.fetch_topic("technology").await?;use finance_news_aggregator_rs::types::SourceConfig;
let config = SourceConfig::default()
.with_timeout(60)
.with_user_agent("My News Bot 1.0")
.with_retries(5, 2000);
let mut client = NewsClient::with_config(config);let wsj = client.wsj();
let articles = wsj.fetch_feed_by_url("https://feeds.a.dj.com/rss/RSSOpinion.xml").await?;client.save_to_file(&articles, "news_articles").await?;
// Saves to: examples/responses/news_articles.json# Run all sources example
cargo run --example all_sources_example
# Topic-based API example
cargo run --example topic_based_example
# Configuration example
cargo run --example config_example# Run all tests
cargo test
# Run only unit tests
cargo test --lib
# Run integration tests
cargo test --tests
# Run specific source tests
cargo test --test test_nasdaq_integration
cargo test --test test_cnbc_integration
cargo test --test test_wsj_integrationopinions(),world_news(),us_business_news(),market_news(),technology_news(),lifestyle()
top_news(),world_news(),business(),technology(),investing()- Plus: economy, finance, politics, health_care, real_estate, wealth, energy, media, retail, travel, and more
original_content(),commodities(),cryptocurrency(),dividends(),earnings()economics(),financial_advisors(),innovation(),stocks(),technology()
top_stories(),real_time_headlines(),market_pulse(),bulletins()
latest_articles(),all_news(),market_news(),editors_picks(),etfs(),forex()ipo_analysis(),long_ideas(),short_ideas(),transcripts(),wall_street_breakfast(),most_popular_articles()
headlines(),topstories()headline(&["AAPL", "MSFT", ...])- Get news for specific stock symbols
All sources implement the NewsSource trait:
pub trait NewsSource {
fn name(&self) -> &'static str;
fn url_map(&self) -> &HashMap<String, String>;
fn client(&self) -> &Client;
fn parser(&self) -> &NewsParser;
fn available_topics(&self) -> Vec<&'static str>;
async fn fetch_feed_by_url(&self, url: &str) -> Result<Vec<NewsArticle>>;
async fn fetch_topic(&self, topic: &str) -> Result<Vec<NewsArticle>>;
}pub struct NewsArticle {
pub title: Option<String>,
pub link: Option<String>,
pub description: Option<String>,
pub pub_date: Option<String>,
pub source: Option<String>,
}use finance_news_aggregator_rs::error::FanError;
match client.wsj().opinions().await {
Ok(articles) => println!("Got {} articles", articles.len()),
Err(FanError::Http(e)) => eprintln!("Network error: {}", e),
Err(FanError::XmlParsing(e)) => eprintln!("Parse error: {}", e),
Err(e) => eprintln!("Error: {}", e),
}Enable logging with the RUST_LOG environment variable:
RUST_LOG=debug cargo run --example all_sources_examplesrc/
├── lib.rs # Library root
├── news_client.rs # Main client
├── error.rs # Error types
├── parser.rs # RSS parser
├── types.rs # Data types
└── news_source/ # Source implementations
├── mod.rs # NewsSource trait
├── cnbc.rs
├── market_watch.rs
├── nasdaq.rs
├── seeking_alpha.rs
├── wsj.rs
└── yahoo_finance.rs
MIT License - see LICENSE file for details.
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass:
cargo test - Submit a pull request