Spaces:
Running
Running
fix(M-09): guard os.makedirs() in save_json() against empty dirname -- filenames without path component no longer crash
0e43bbf | """ | |
| BharatGraph - Base Scraper | |
| All scrapers inherit from this class. | |
| """ | |
| import time | |
| import os | |
| import requests | |
| from loguru import logger | |
| from dotenv import load_dotenv | |
| # Load .env file automatically for ALL scrapers that inherit this class | |
| load_dotenv() | |
| class BaseScraper: | |
| def __init__(self, name, delay=2.0): | |
| self.name = name | |
| self.delay = delay | |
| self.session = requests.Session() | |
| self.session.headers.update({ | |
| "User-Agent": "BharatGraph Civic Research Tool (public data only)" | |
| }) | |
| os.makedirs("logs", exist_ok=True) # BUG-29 FIX: ensure logs/ exists | |
| logger.add(f"logs/{name}.log", rotation="10 MB", enqueue=True, catch=True) | |
| def get_json(self, url, params=None): | |
| try: | |
| logger.info(f"[{self.name}] Fetching: {url}") | |
| resp = self.session.get(url, params=params, timeout=30) | |
| resp.raise_for_status() | |
| time.sleep(self.delay) | |
| return resp.json() | |
| except Exception as e: | |
| logger.error(f"[{self.name}] Error: {e}") | |
| return None | |
| def get_html(self, url, params=None): | |
| try: | |
| logger.info(f"[{self.name}] Fetching HTML: {url}") | |
| resp = self.session.get(url, params=params, timeout=30) | |
| resp.raise_for_status() | |
| time.sleep(self.delay) | |
| return resp.text | |
| except Exception as e: | |
| logger.error(f"[{self.name}] Error: {e}") | |
| return None | |
| def save_json(self, data, filepath): | |
| import json | |
| # M-09 FIX: dirname("output.json") returns "" -- makedirs("") crashes. | |
| # Guard with: only call makedirs if there is actually a directory component. | |
| dir_path = os.path.dirname(filepath) | |
| if dir_path: | |
| os.makedirs(dir_path, exist_ok=True) | |
| with open(filepath, "w", encoding="utf-8") as f: | |
| json.dump(data, f, indent=2, ensure_ascii=False) | |
| logger.info(f"[{self.name}] Saved: {filepath}") | |
| if __name__ == "__main__": | |
| s = BaseScraper("test") | |
| print("BaseScraper ready.") | |