Coding-With-Bashir commited on
Commit
fd0216f
·
verified ·
1 Parent(s): c02894a

Upload .\src\data_collection\rss_collector.py with huggingface_hub

Browse files
.//src//data_collection//rss_collector.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """RSS feed collector for news sources."""
2
+
3
+ import json
4
+ import logging
5
+ import time
6
+ import xml.etree.ElementTree as ET
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ import requests
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class RSSCollector:
16
+ """Collects articles from RSS feeds."""
17
+
18
+ def __init__(self, output_dir: str, config: dict[str, Any]):
19
+ self.output_dir = Path(output_dir)
20
+ self.output_dir.mkdir(parents=True, exist_ok=True)
21
+ self.config = config
22
+ self.session = requests.Session()
23
+ self.session.headers.update({
24
+ "User-Agent": "BwengeAi/0.1 (Kinyarwanda AI Research)"
25
+ })
26
+
27
+ rss_config = config.get("newtimes", {})
28
+ self.feeds = rss_config.get("rss_feeds", [])
29
+ self.rate_limit = rss_config.get("rate_limit", 1.0)
30
+
31
+ def fetch_feed(self, url: str) -> list[dict[str, Any]]:
32
+ """Fetch and parse an RSS feed."""
33
+ items = []
34
+ try:
35
+ time.sleep(self.rate_limit)
36
+ response = self.session.get(url, timeout=30)
37
+ response.raise_for_status()
38
+
39
+ root = ET.fromstring(response.content)
40
+
41
+ ns = {"atom": "http://www.w3.org/2005/Atom"}
42
+ entries = root.findall(".//item") or root.findall(".//atom:entry", ns)
43
+
44
+ for entry in entries:
45
+ item = {}
46
+
47
+ title = entry.find("title") or entry.find("atom:title", ns)
48
+ if title is not None and title.text:
49
+ item["title"] = title.text.strip()
50
+
51
+ link = entry.find("link") or entry.find("atom:link", ns)
52
+ if link is not None:
53
+ item["url"] = link.get("href", link.text or "").strip()
54
+
55
+ description = entry.find("description") or entry.find("atom:summary", ns)
56
+ if description is not None and description.text:
57
+ item["text"] = description.text.strip()
58
+
59
+ content = entry.find("content:encoded", {"content": "http://purl.org/rss/1.0/modules/content/"})
60
+ if content is not None and content.text:
61
+ item["text"] = content.text.strip()
62
+
63
+ pub_date = entry.find("pubDate") or entry.find("atom:published", ns)
64
+ if pub_date is not None and pub_date.text:
65
+ item["date"] = pub_date.text.strip()
66
+
67
+ if item.get("text") and len(item["text"]) > 50:
68
+ item["source"] = "newtimes_rss"
69
+ items.append(item)
70
+
71
+ except Exception as e:
72
+ logger.error(f"Failed to fetch RSS feed {url}: {e}")
73
+
74
+ return items
75
+
76
+ def collect_all(self) -> list[dict[str, Any]]:
77
+ """Collect articles from all configured RSS feeds."""
78
+ logger.info("Starting RSS feed collection...")
79
+
80
+ all_items = []
81
+
82
+ for feed_config in self.feeds:
83
+ feed_name = feed_config.get("name", "unknown")
84
+ feed_url = feed_config.get("url", "")
85
+
86
+ if not feed_url:
87
+ continue
88
+
89
+ logger.info(f"Collecting from RSS feed: {feed_name}")
90
+ items = self.fetch_feed(feed_url)
91
+ all_items.extend(items)
92
+ logger.info(f" Feed '{feed_name}': {len(items)} items collected")
93
+
94
+ output_path = self.output_dir / "newtimes_rss_articles.jsonl"
95
+ with open(output_path, "w", encoding="utf-8") as f:
96
+ for item in all_items:
97
+ f.write(json.dumps(item, ensure_ascii=False) + "\n")
98
+
99
+ summary = {
100
+ "source": "newtimes_rss",
101
+ "feeds": [f.get("name", "") for f in self.feeds],
102
+ "total_articles": len(all_items),
103
+ "output_path": str(output_path),
104
+ "total_characters": sum(len(item.get("text", "")) for item in all_items),
105
+ }
106
+
107
+ summary_path = self.output_dir / "newtimes_rss_summary.json"
108
+ with open(summary_path, "w", encoding="utf-8") as f:
109
+ json.dump(summary, f, indent=2, ensure_ascii=False)
110
+
111
+ logger.info(f"Collected {len(all_items)} articles from RSS feeds")
112
+ return all_items