| Crates.io | finance-news-aggregator-rs |
| lib.rs | finance-news-aggregator-rs |
| version | 0.2.2 |
| created_at | 2025-08-24 07:49:09.798764+00 |
| updated_at | 2025-11-01 23:36:43.102966+00 |
| description | Finance News Aggregator - Rust port of the Python finance-news-aggregator |
| homepage | |
| repository | https://github.com/codingthings-com/finance-news-aggregator-rs |
| max_upload_size | |
| id | 1808150 |
| size | 244,632 |
A Rust library for aggregating financial news from various RSS feed sources. Port of the Python finance-news-aggregator.
| Source | Working Feeds | Status |
|---|---|---|
| CNBC | 24 topics | ✅ 100% |
| MarketWatch | 4 topics | ✅ 100% |
| NASDAQ | 10 topics | ✅ 100% |
| Seeking Alpha | 12 topics | ✅ 100% |
| Wall Street Journal | 6 topics | ✅ 100% |
| Yahoo Finance | 2 topics + symbols | ✅ 100% |
[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_integration
opinions(), world_news(), us_business_news(), market_news(), technology_news(), lifestyle()top_news(), world_news(), business(), technology(), investing()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 symbolsAll 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_example
src/
├── 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.
cargo test