news-watch: Indonesia's top news websites scraper
news-watch is a Python package that scrapes structured news data from Indonesia's top news websites, offering keyword and date filtering queries for targeted research.
Ethical Considerations & Disclaimer
Purpose: For educational and research purposes only. Not designed for commercial use that could be detrimental to news source providers.
User responsibility: Comply with each website's Terms of Service and
robots.txt. Aggressive scraping may lead to IP blocking. Scrape responsibly and respect server limitations.
Installation
Using pip
pip install news-watch
playwright install chromium
Development setup: see https://okky.dev/news-watch/getting-started/
Performance Notes
⚠️ Works best locally. Cloud environments (Google Colab, servers) may experience degraded performance or blocking due to anti-bot measures.
Some scrapers may work on a local machine but fail on remote servers, Linux CI, or GitHub Actions. This usually happens because of anti-bot protection, rate limits, geolocation differences, JavaScript rendering differences, or sudden source-side changes.
Using a proxy
When running on a server or behind anti-bot blocks, route requests through a residential/datacenter proxy. The proxy applies to every layer (aiohttp, rnet, and the Playwright fallback):
# via flag
newswatch -k ihsg -sd 2025-01-01 --proxy "http://proxy.example.com:8080"
# via env (also honors standard HTTPS_PROXY / HTTP_PROXY)
export NEWSWATCH_PROXY="socks5://proxy.example.com:1080"
newswatch -k ihsg -sd 2025-01-01
import newswatch as nw
df = nw.scrape_to_dataframe(
"ihsg",
"2025-01-01",
proxy="http://proxy.example.com:8080",
)
Other reliability overrides (env vars): NEWSWATCH_USER_AGENT (custom User-Agent), NEWSWATCH_MAX_RETRIES (retry count, default 3), NEWSWATCH_TIMEZONE (zone for publish_date and date filters, default Asia/Jakarta).
Usage
To run the scraper from the command line:
newswatch --method <search|latest> -k <keywords> -sd <start_date> -s [<scrapers>] -of <output_format> -v
Command-Line Arguments
| Argument | Description |
|---|---|
--method |
Retrieval method: search (default) or latest |
-k, --keywords |
Comma-separated keywords to scrape (required for search, optional for latest) |
-sd, --start_date |
Start date in YYYY-MM-DD format (required for search, ignored in latest) |
-s, --scrapers |
Scrapers to use: specific names (e.g., "kompas,viva"), "auto" (default, platform-appropriate), or "all" (force all, may fail) |
-of, --output_format |
Output format: csv, xlsx, json, or jsonl (default: csv). csv and jsonl stream to disk incrementally; xlsx and json are held in memory and written once at the end |
-o, --output_path |
Custom output file path (optional) |
-v, --verbose |
Show detailed logging output (default: silent) |
--list_scrapers |
List all supported scrapers and exit |
--health-report |
Run source health probes and print status table. JSON/CSV via --output_path |
--limit |
Maximum number of articles to collect in latest mode |
--max-pages |
Maximum pages to fetch per scraper in latest mode |
--scraper-timeout |
Per-scraper timeout in seconds |
--max-concurrent-scrapers |
Maximum scrapers running at once (default: 6). Browser-required scrapers share a smaller pool capped at 2 |
--progress |
Print per-scraper progress lines |
--daterange |
Filter articles by an inclusive date window. Format: YYYY-MM-DD/YYYY-MM-DD (e.g. 2026-07-13/2026-07-14); start = 00:00:00, end = 23:59:59.999999 of the same day |
--dedup-file |
Path to a previous output file (JSON/JSONL/CSV); articles with matching links are skipped |
--proxy |
Proxy URL for all requests (e.g. http://proxy.example.com:8080 or socks5://proxy.example.com:1080). Also via NEWSWATCH_PROXY env |
Examples
# Basic usage
newswatch --keywords ihsg --start_date 2025-01-01
# Latest monitoring mode
newswatch --method latest --scrapers "antaranews,kompas,viva"
# Multiple keywords with specific scraper
newswatch -k "ihsg,bank" -s "tempo" --output_format xlsx -v
# List available scrapers
newswatch --list_scrapers
Python API Usage
import newswatch as nw
# Basic scraping - returns list of article dictionaries
articles = nw.scrape("ekonomi,politik", "2025-01-01")
print(f"Found {len(articles)} articles")
# Get results as pandas DataFrame for analysis
df = nw.scrape_to_dataframe("teknologi,startup", "2025-01-01")
print(df['source'].value_counts())
# Latest monitoring
latest = nw.latest_to_dataframe(scrapers="antaranews,kompas,viva")
print(latest[["source", "title"]].head())
# Save directly to file
nw.scrape_to_file(
keywords="bank,ihsg",
start_date="2025-01-01",
output_path="financial_news.xlsx"
)
# Quick recent news
recent_news = nw.quick_scrape("politik", days_back=3)
# Get available news sources
sources = nw.list_scrapers()
print("Available sources:", sources)
See the practical guide for end-to-end CLI and Python-API examples and common research patterns. For interactive examples, see the API reference notebook.
Run on Google Colab
You can run news-watch on Google Colab
Output
The scraped articles are saved as a CSV, XLSX, JSON, or JSONL file in the current working directory with the format news-watch-{keywords}-YYYYMMDD_HH.
Each record has 8 fields: title, publish_date, author, content, keyword, category, source, link. (scrape_timestamp exists on the internal Article model but is not emitted to output.)
The output file contains the following columns:
titlepublish_dateauthorcontentkeywordcategorysourcelink
Retrieval Methods
searchis the default and keeps the current keyword/date research workflow.latestis intended for latest-news monitoring and does not require keywords.
Supported Websites (82)
ABC News, Alinea.id, Al Jazeera, Antara News, AP News, Bali Post, Banten News, BBC News, Berita Jatim, BeritaSatu, Betahita, Bisnis.com, Bloomberg Technoz, CNA Indonesia, CNBC Indonesia, CNN Indonesia, The Conversation Indonesia, DailySocial, Dandapala, DDTC News, Detik, Fajar, Galamedia, Gatra, Good News From Indonesia, Grid, Harian Jogja, Hipwee, Hukumonline, IDN Financials, IDN Times, IDX Channel, Independen.id, Indopolitika, iNews, Infobanknews, Investor.id, Jakarta Globe, The Jakarta Post, Jakarta Selaras, Jawa Pos, JPNN (Jawa Pos News Network), Kaltim Post (Borneo24), Katadata, KBR, Kompas, Kontan, Kumparan, Liputan6, Media Indonesia, Merdeka, MetroTV News, Mojok, Mongabay Indonesia, NBC News, Niaga.Asia, NTVNews.id, NusaBali, Okezone, Pantau.com, Pikiran Rakyat, Poskota, Project Multatuli, Harian Rakyat Aceh, Republika, RM.ID (Rakyat Merdeka), RMOL, RRI (RRI.co.id), SINDOnews, Suara, Suara Merdeka, Surabaya Pagi, SWA, Tempo, Tirto, Tribunnews, TVOne, TVRI News, Viva, VOA Indonesia, VOI.id, Warta Ekonomi
Notes:
- 82 registered sources: 77 with keyword search, 82 with latest mode.
- 80 stable scrapers in the current release: 75 with keyword search, 80 with latest mode.
- 1 source under investigation; 1 source quarantined.
- AP News uses topic hub pages with keyword-in-title filtering (robots disallows /search?q=*).
- Al Jazeera is latest-only via RSS feed (search page is JS-rendered).
- Reuters skipped (WAF blocked).
- Use
-s allto force-run all scrapers (may cause errors/timeouts).- Some sources are environment-sensitive and may fail on remote servers even if they work locally.
- Limitation: Kontan scraper maximum 50 pages.
Contributing
Contributions are welcome. Open an issue or pull request to add a source or improve an existing one.
Keep tests with their owning behavior: shared scraper contracts in tests/test_basescraper.py, registry metadata and discovery in tests/test_registry.py, and source-specific parsing and extraction in tests/test_scrapers_focused.py. Do not add catch-all files such as tests/test_new_scrapers.py. Before adding coverage, search the owning module and extend or parameterize an existing test when it already exercises the same observable behavior. Keep another case only for a distinct boundary, precedence rule, transition, or real error path; avoid assertions on source text, private plumbing, or registry counts.
License
This project is licensed under the MIT License - see the LICENSE file for details. The authors assume no liability for misuse of this software.
Citation
@software{mabruri_newswatch,
author = {Okky Mabruri},
title = {news-watch},
year = {2025},
doi = {10.5281/zenodo.14908389}
}
Related Work
Metadata
Release files for news-watch 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| news_watch-1.3.0.tar.gz | 4.6 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| news_watch-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 4.8 MB
Release files / news_watch-1.3.0.tar.gz
| Download URL | news_watch-1.3.0.tar.gz |
|---|---|
| Size | 4.6 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a60526e94747a8ae0dc492eaacbb81c74434dcf95fef461a3283294da4e7b79f
|
|
BLAKE2b-256 checksum How to use checksums |
da9748385f74e6bdf7dad79ea1abd563e3024539822a28f9cbcba189a438fe32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency logRelease files / news_watch-1.3.0-py3-none-any.whl
| Download URL | news_watch-1.3.0-py3-none-any.whl |
|---|---|
| Size | 241.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4102a2e3b4a9b128f3a4a095b750aeeeb30430196c2c583f8fb54b48adf29a0c
|
|
BLAKE2b-256 checksum How to use checksums |
e0e522fa306a70489eed36faf42ab6b06d130247869127776d1075dc20d60ec5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 30, 2026.
Transparency log