""" Laddar ned motioner från riksdagens öppna data som ZIP-arkiv med JSON-filer. Arkiven är uppdelade i fyraårsperioder (förankrade vid 1998; allt före ligger i 1990-1997) och uppdateras dagligen: https://data.riksdagen.se/dataset/dokument/mot-{range}.json.zip Varje arkiv innehåller en JSON-fil per motion (dokumentstatus-kuvert med metadata + fulltext som HTML). Extraheras till motioner/mot-{range}/. Backfill (alla perioder 1990→): python scripts/download_motions.py Används av sync_motions.py för daglig uppdatering av aktuell period. """ from pathlib import Path import logging import os import sys from io import BytesIO from urllib.request import urlopen from zipfile import ZipFile sys.path.insert(0, str(Path(__file__).resolve().parents[1])) import bootstrap # noqa: E402,F401 — sets cwd and sys.path to the project root logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", ) logger = logging.getLogger(__name__) RANGES = [ "1990-1997", "1998-2001", "2002-2005", "2006-2009", "2010-2013", "2014-2017", "2018-2021", "2022-2025", ] URL_TEMPLATE = "https://data.riksdagen.se/dataset/dokument/mot-{r}.json.zip" MOTIONS_DIR = "motioner" def get_current_range(session_year: int) -> str: """Fyraårsperiod förankrad vid 1998; allt före 1998 ligger i 1990-1997.""" if session_year < 1998: return "1990-1997" start = session_year - ((session_year - 1998) % 4) return f"{start}-{start + 3}" def download_range(r: str, force: bool = False) -> str: """ Laddar ned och extraherar arkivet för en period till motioner/mot-{r}/. Hoppar över om mappen redan är ifylld, om inte force=True (töms först). """ dir_path = os.path.join(MOTIONS_DIR, f"mot-{r}") if os.path.exists(dir_path) and os.listdir(dir_path): if not force: logger.info(f"Skipping {dir_path}, already exists and is not empty.") return dir_path for f in os.listdir(dir_path): os.remove(os.path.join(dir_path, f)) os.makedirs(dir_path, exist_ok=True) url = URL_TEMPLATE.format(r=r) logger.info(f"Downloading {url} → {dir_path}") with urlopen(url) as resp: with ZipFile(BytesIO(resp.read())) as zf: zf.extractall(dir_path) count = len(os.listdir(dir_path)) logger.info(f"Extracted {count} files to {dir_path}") return dir_path def download_all(force: bool = False) -> None: for r in RANGES: download_range(r, force=force) if __name__ == "__main__": if len(sys.argv) > 1: download_range(sys.argv[1], force="--force" in sys.argv) else: download_all()