feat: world news aggregator from RSS (BBC, HN, BBC中文)
This commit is contained in:
60
scripts/fetch_news.py
Normal file
60
scripts/fetch_news.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
"""Fetch world news from RSS feeds and save for the daily brief page."""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import feedparser
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
|
OUTPUT = "/var/www/nav/data/news.json"
|
||||||
|
tz = timezone(timedelta(hours=8))
|
||||||
|
|
||||||
|
# RSS feeds - balanced selection of world news sources
|
||||||
|
FEEDS = [
|
||||||
|
{"name": "BBC World", "url": "http://feeds.bbci.co.uk/news/world/rss.xml", "lang": "en"},
|
||||||
|
{"name": "BBC \u4e2d\u6587", "url": "https://www.bbc.com/zhongwen/simp/index.xml", "lang": "zh"},
|
||||||
|
{"name": "Reuters", "url": "https://www.reutersagency.com/feed/", "lang": "en"},
|
||||||
|
{"name": "HN", "url": "https://hnrss.org/frontpage?count=10", "lang": "en"},
|
||||||
|
]
|
||||||
|
|
||||||
|
MAX_PER_FEED = 8
|
||||||
|
MAX_TOTAL = 30
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_news():
|
||||||
|
items = []
|
||||||
|
for feed_info in FEEDS:
|
||||||
|
try:
|
||||||
|
feed = feedparser.parse(feed_info["url"])
|
||||||
|
for entry in feed.entries[:MAX_PER_FEED]:
|
||||||
|
items.append({
|
||||||
|
"title": entry.get("title", ""),
|
||||||
|
"link": entry.get("link", ""),
|
||||||
|
"summary": entry.get("summary", "")[:200],
|
||||||
|
"published": entry.get("published", ""),
|
||||||
|
"source": feed_info["name"],
|
||||||
|
"lang": feed_info["lang"],
|
||||||
|
})
|
||||||
|
print(f" {feed_info['name']}: {len(feed.entries[:MAX_PER_FEED])} items")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" {feed_info['name']}: ERROR - {e}")
|
||||||
|
|
||||||
|
# Sort by published time (newest first), but keep feeds mixed
|
||||||
|
items.sort(key=lambda x: x.get("published", ""), reverse=True)
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"updated_at": datetime.now(tz).strftime("%Y-%m-%d %H:%M"),
|
||||||
|
"total": len(items),
|
||||||
|
"items": items[:MAX_TOTAL],
|
||||||
|
"sources": [f["name"] for f in FEEDS],
|
||||||
|
}
|
||||||
|
|
||||||
|
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
|
||||||
|
with open(OUTPUT, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(result, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
print(f"\nTotal: {len(items)} items -> {OUTPUT}")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(f"Fetching news at {datetime.now(tz).strftime('%Y-%m-%d %H:%M')}")
|
||||||
|
fetch_news()
|
||||||
Reference in New Issue
Block a user