Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Repository Banner

📰 Open News

A lightweight Python toolkit for discovering, extracting, filtering, and summarizing news.

License Python PyPI Tests

Fetch. Search. Discover. Extract. Process. Summarize.

Open News provides one small, scriptable interface over live news discovery, article extraction, website discovery, filtering, deduplication, topic filtering, relevance ranking, story clustering, and extractive summarization — with Markdown/JSON export and CLI + TUI interfaces included.

🚀 Quick Start · 🏗️ Architecture · 📦 Installation · 🐍 Python API · 📚 Documentation · 🤝 Contributing


✨ What is Open News?

Open News is intentionally not a full news platform. It is a reusable library and set of interfaces for applications that need reliable access to news data without building the entire acquisition and processing stack themselves.

                         ┌─────────────────────┐
                         │      Your App       │
                         └──────────┬──────────┘
                                    │
                         Python API / CLI / TUI
                                    │
                         ┌──────────▼──────────┐
                         │    Open News API    │
                         └──────────┬──────────┘
                                    │
                    ┌───────────────┼───────────────┐
                    │               │               │
                 Acquire         Process         Extract
                    │               │               │
                    ▼               ▼               ▼
              live sources    filter · dedupe   article text
              RSS / search    rank · enrich     metadata/media

🎯 Design goals

  • Lightweight — use ordinary Python tooling where possible.
  • Resilient — acquisition can fall back across multiple sources.
  • Composable — public functions can be embedded into other projects.
  • Local-first processing — filtering, deduplication, ranking, and summarization do not require an LLM or hosted AI service.
  • Cluster-aware — group related stories and rank by outlet coverage, not just by date.
  • Scriptable — JSON output makes the CLI suitable for pipelines.
  • Portable — desktop Linux, macOS, WSL/Git Bash, and Termux are supported by the installation workflow.
  • Stable core — v1.0.3 freezes the architecture developed and validated during the 1.0.3 pre-release cycle.

🧭 v1.0.4 at a glance

v1.0.4 builds on the v1.0.3 acquisition baseline.

v1.0.4 is a processing/output release: clustering, topic filtering, BM25/TF-IDF relevance ranking, and clean Markdown/JSON export — plus a keyboard-driven TUI refresh.

What v1.0.4 adds on top

pipeline results
       │
       ▼
filter_articles(topic=…)     narrow by topic across title/description/text/category/keywords
       │
       ▼
rank_articles(query=…)       BM25 if bm25s is installed, else TF-IDF
       │
       ▼
cluster_articles()           group by title similarity; keep every article
       │
       ▼
export.to_markdown()/to_json()   clean, schema-versioned output

All four are also available as CLI flags (--topic, --rank-query, cluster, export) and inside the TUI.

This is complemented by stronger URL resolution, aggregator-aware source attribution, hub/listing detection, deterministic test infrastructure, Android/Termux support, and a hardened installer.


🌟 Features

Capability What it provides
📰 Live news Category/location news through a resilient multi-tier acquisition chain
🔎 Keyword search Google News RSS search with query modes, exclusions, locale, and date ranges
🔴 Streaming search Polling APIs that yield only newly-seen articles
📄 Article extraction Title, text, authors, dates, images, videos, source, and metadata
🌐 Website discovery RSS-first discovery with same-domain crawler fallback
🧭 Source resolution Best-effort original-publisher resolution for aggregator-hosted stories
🧹 Processing Language guard, token filtering, domain filters, dedupe, and ranking
✂️ Summarization Lightweight extractive summaries with no network requirement for raw text
🖥️ CLI Human-readable or JSON output for shell workflows
📺 TUI Numbered terminal interface for interactive use
📱 Termux Dedicated installation flow and acquisition safeguards
🧪 Testing Unit, contract, network, native-dependency, and local-server test infrastructure
🧩 Clustering Group related stories by title similarity; rank by outlet coverage
📊 Ranking BM25 / TF-IDF relevance re-ranking with an optional bm25s backend
📤 Export Clean Markdown and schema-versioned JSON, written to a path or returned as a string

📦 Installation

Package name: open-news-api
Python: 3.10+

⚡ Interactive installer

curl -fsSL https://raw.githubusercontent.com/alphap365/open-news/main/install.sh | bash

The installer detects the environment, can create an isolated environment, optionally installs JavaScript rendering, configures PATH, saves CLI preferences, and verifies the resulting installation.

🐍 pip

pip install open-news-api

Pin v1.0.3 explicitly when you want the stable release:

pip install open-news-api==1.0.4

⚡ uv

uv add open-news-api

Or try the CLI without adding it to a project:

uvx --from open-news-api open-news --help

🛠️ From source

git clone https://github.com/alphap365/open-news.git
cd open-news
python -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
pytest -q

Windows activation:

.venv\Scripts\activate

🌐 Optional JavaScript rendering

pip install "open-news-api[js]"
playwright install chromium

JavaScript rendering is optional. Plain HTTP extraction remains the default.

🧠 Optional NLP ranking

pip install "open-news-api[nlp]"

Enables BM25 ranking in rank_articles() (via bm25s) and higher-quality LSA summarization (via sumy). Without it, ranking falls back to pure-Python TF-IDF.

🚀 Quick Start

1. Fetch live news

from open_news import fetch

articles = fetch(category="tech", max_results=5)

for article in articles:
    print(article["title"])
    print(article["url"])

2. Search news

from open_news import search

articles = search(
    "artificial intelligence",
    query_mode="all",
    exclude_terms=["sports"],
    country="in",
    max_results=5,
)

for article in articles:
    print(f"{article['title']} → {article['url']}")

3. Extract an article

from open_news import get_article

article = get_article("https://example.com/article")

print(article["title"])
print(article["text"])
print(article["source"])

4. Discover a website

from open_news import discover_and_get

articles = discover_and_get("https://example.com", limit=5)

Open News tries RSS discovery first and falls back to same-domain crawling when appropriate.

5. Stream new search results

from open_news import stream_search

for articles in stream_search("budget 2026", refresh_interval=30):
    for article in articles:
        print(article["title"])

6. Summarize

from open_news import search_and_summarize

results = search_and_summarize(
    "renewable energy",
    limit=5,
    sentence_count=2,
)

for result in results:
    print(result["summary"])
from open_news import fetch, cluster_articles

articles = fetch(category="tech", max_results=40)

clusters = cluster_articles(
    articles,
    threshold=0.72,
    topic="artificial intelligence",
    rank_query="openai gemini",
    drop_singletons=True,
)

for c in clusters:
    print(f"{c['size']} outlets: {c['label']}")

8. Rank by relevance

from open_news import search, rank_articles

articles = search("eu ai act", max_results=30)
ranked = rank_articles(articles, query="EU AI Act", method="auto")

print(ranked[0]["title"], ranked[0]["_rank_score"])

9. Export

from open_news import export

export.to_markdown(clusters, path="out/clusters.md", include_all_members=True)
export.to_json(clusters, path="out/clusters.json")

Both functions return the serialized string as well, so you can pipe or stream instead of writing to disk.


🏗️ Architecture

Open News is organized around a small number of layers rather than one monolithic engine.

open_news/
│
├── api.py                  Public API boundary
├── config.py               Validated configuration objects
│
├── feeds/                  News acquisition and feed discovery
│   ├── duckduckgo_engine.py   Five-tier fetch orchestrator
│   ├── googlenews_engine.py   Google News search/fetch
│   ├── bingnews_engine.py     Bing News fallback
│   ├── yahoonews_engine.py    Yahoo News fallback
│   ├── sources.py             RSS/search sources
│   └── rss_discovery.py       RSS detection
│
├── fetch/                  URL and website acquisition
│   ├── article.py             Single article retrieval
│   ├── crawler.py             Async + JS crawlers
│   └── url_resolver.py        Redirect/hub/aggregator classification
│
├── processing/             Shared result processing
│   ├── pipeline.py            Filter → dedupe → rank → enrich
│   ├── dedupe.py
│   ├── ranker.py
│   ├── language_guard.py
│   ├── domain_filter.py
│   ├── token_filter.py
│   ├── batch.py
│   └── summarizer.py
│
└── core/                   Article extraction
    ├── extractor.py           Strategy coordinator
    ├── strategies.py          JSON-LD / Open Graph / HTML heuristics
    └── renderer.py            Playwright support

For the full data flow, see docs/architecture.md.


🖥️ CLI & 📺 TUI

CLI

open-news fetch --category tech --limit 5
open-news search "artificial intelligence" --country in --limit 5
open-news extract https://example.com/article
open-news discover https://example.com --limit 10
open-news search-site "climate policy" reuters.com
open-news summarize --query "renewable energy" --limit 5
open-news search "eu ai act" --topic "policy,regulation" --rank-query "EU AI Act" \
    --export-md out/ai-act.md --export-json out/ai-act.json
open-news cluster --query "openai" --limit 40 --drop-singletons \
    --export-md out/clusters.md --export-all-members
open-news export out/ai-act.json --md out/ai-act.md

For scripting:

open-news search "AI" --format json | jq '.[].title'

TUI

open-news-tui

The TUI provides a numbered workflow for fetching, searching, discovery, extraction, summarization, settings, and live category refresh.


🔐 Resilience & failure behavior

Open News deliberately treats acquisition as a best-effort operation.

A source failure does not automatically mean the whole fetch() operation fails. The acquisition orchestrator can continue through its fallback chain.

Likewise, article enrichment does not intentionally destroy good existing metadata merely because a later extraction step returned an empty field.

For aggregator-hosted stories, source resolution is explicitly best effort. The library records whether the source was identified as an aggregator and whether the original publisher was resolved. Consumers should not treat an unresolved aggregator attribution as ground truth.


🧪 Testing

The v1.0.3 development cycle expanded the test environment beyond ordinary unit tests.

It includes infrastructure for:

  • deterministic local article-server tests;
  • Android/Termux emulation;
  • network-dependent test separation;
  • native-dependency test separation;
  • acquisition-engine contracts;
  • extraction and URL-resolution behavior;
  • processing and deduplication contracts;
  • CLI behavior.

Run the suite locally with:

pytest -q

📚 Documentation

Document Purpose
🏗️ architecture.md Internal structure and data flow
📦 installation.md Installer, manual setup, JS, Termux, uninstall
🐍 python-api.md Public Python API
🖥️ cli-reference.md Complete CLI commands and options
📺 tui-guide.md Interactive terminal interface
🌍 parameters-reference.md Parameter formats and accepted values
📝 changelog.md Release history and v1.0.3 stabilization story

🧭 Versioning philosophy

Open News follows semantic-version-style release numbering.

The 1.0.3 pre-release series is intentionally treated as one development cycle rather than a collection of unrelated public feature releases:

Issue #1
   │
   ▼
1.0.3a1 → a2 → a3 → a4 → a5 → a6
   │
   ▼
1.0.3b1 → 1.0.3b2
   │
   ▼
1.0.3 stable

The stable release freezes the resulting architecture and makes the v1.0.3 behavior the documented baseline.


🤝 Contributing

Contributions are welcome, especially around:

  • new acquisition fallbacks;
  • extraction strategies;
  • deterministic tests;
  • portability improvements;
  • documentation;
  • performance and resource usage.

Please read CONTRIBUTING.md before opening a pull request.


📄 License

Open News is released under the MIT License. See LICENSE.

📰 Open News — small enough to embed, capable enough to build on.

Metadata

Release files for open-news-api 1.0.4a1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for open-news-api 1.0.4a1
File Size Uploaded
open_news_api-1.0.4a1.tar.gz 110.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for open-news-api 1.0.4a1
File Interpreter ABI Platform
open_news_api-1.0.4a1-py3-none-any.whl Python 3 none any Details

Total release size: 204.2 kB

Release files / open_news_api-1.0.4a1.tar.gz

Download URL open_news_api-1.0.4a1.tar.gz
Size 110.0 kB
Tags Source
SHA-256 checksum
How to use checksums
132729da4ea502680cdce0a6b10fe20ab13b5cae4df258d94d9eab6656a59996
BLAKE2b-256 checksum
How to use checksums
fe09b40e9e63b7dd326fc8b524dd4534ab184b6eec4bd29ced47ce5b204e775f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / open_news_api-1.0.4a1-py3-none-any.whl

Download URL open_news_api-1.0.4a1-py3-none-any.whl
Size 94.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
016b22deafc336a2aa1cca669d019c2c2058166e0547a2c639f69cfd866ce007
BLAKE2b-256 checksum
How to use checksums
83b5eaed24537997b229e649bb9a95d7154b8af90b7e82d899c31d00335238b5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page