Se l’obiettivo è leggere Wikipedia da console, la strada più pulita non è “clonare il sito” in senso letterale, ma costruire una copia locale dei contenuti che ti servono, interrogando le API ufficiali e salvando testo, metadati e collegamenti in un formato semplice da consultare. Un approccio del genere evita scraping fragile, riduce il carico sui server esterni e ti lascia un flusso controllabile: scarico, normalizzo, salvo, leggo.
In pratica, puoi realizzare un piccolo tool Python che prende un titolo di pagina, recupera l’estratto o il testo completo, lo mette in cache su disco e poi lo mostra in terminale con una navigazione minimale. Se vuoi farlo bene, conviene separare tre pezzi: acquisizione dati, archivio locale e interfaccia testuale. È il modo più solido per ottenere qualcosa di utile senza trasformare il progetto in un crawler ingestibile.
Obiettivo reale: lettura locale, non mirroring cieco
“Clonare Wikipedia” può voler dire cose molto diverse. Se intendi scaricare tutto il contenuto multilingua, immagini, revisioni e template, il progetto diventa enorme e poco pratico per un uso da console. Se invece vuoi leggere articoli offline o quasi offline, con una ricerca veloce e una cache locale, allora Python è perfetto. La differenza è importante: il primo caso è un problema di data engineering e storage, il secondo è un problema di accesso, normalizzazione e UX testuale.
Per un lettore da terminale, l’obiettivo ragionevole è questo: dato un titolo o una parola chiave, ottenere il testo della pagina, salvarlo in locale, visualizzarlo in modo leggibile e riutilizzare i dati già scaricati. Se poi vuoi estendere il progetto a un sottoinsieme di pagine, puoi aggiungere un indice locale o una ricerca full-text. Ma il primo traguardo deve restare semplice.
Perché usare le API di Wikipedia invece di fare scraping
Le pagine HTML di Wikipedia sono pensate per i browser, non per un parser artigianale. Cambiano struttura, includono elementi di navigazione, tabelle, note, template e markup che rendono il parsing meno stabile. Le API ufficiali, invece, offrono endpoint più puliti e prevedibili. Per esempio, puoi recuperare un estratto, un riepilogo o il contenuto in wikitext senza dover inseguire i dettagli del DOM.
In più, usare le API ti permette di rispettare meglio la piattaforma. Wikipedia espone un’infrastruttura pubblica che va trattata con attenzione: user agent chiaro, rate limit ragionevole, cache locale e richieste solo quando servono. Se il tuo script finisce per fare mille richieste per una sessione di lettura, hai già sbagliato design.
Architettura minima del progetto Python
La struttura più sensata è questa:
1. Un modulo che interroga l’API e scarica i contenuti.
2. Un archivio locale in JSON o SQLite.
3. Un renderer da terminale che stampa titolo, sommario e testo pulito.
4. Una funzione di ricerca che trova pagine già memorizzate.
Per un prototipo, JSON basta. Se inizi a gestire molte pagine, SQLite è più adatto: ti consente query rapide, full-text search e aggiornamenti incrementali. In generale, JSON è più immediato; SQLite è più robusto quando il dataset cresce.
Recuperare il contenuto con l’API MediaWiki
Il modo più semplice per iniziare è usare `requests` e interrogare l’API. Puoi partire con l’estratto della pagina, che è utile per un lettore da console perché fornisce un riassunto compatto. Se poi ti serve il testo completo, puoi passare a un endpoint che restituisce il contenuto in formato wikitext o HTML parsato.
pip install requests
Ecco un esempio essenziale per ottenere l’estratto di una voce:
import requests API_URL = "https://it.wikipedia.org/w/api.php" def get_summary(title: str) -> dict: params = { "action": "query", "format": "json", "prop": "extracts|info", "exintro": 1, "explaintext": 1, "inprop": "url", "titles": title, "redirects": 1, } headers = { "User-Agent": "WikiConsoleReader/1.0 (contatto@example.com)" } r = requests.get(API_URL, params=params, headers=headers, timeout=15) r.raise_for_status() data = r.json() page = next(iter(data["query"]["pages"].values())) return { "title": page.get("title", title), "extract": page.get("extract", ""), "url": page.get("fullurl", ""), } if __name__ == "__main__": info = get_summary("Python") print(info["title"]) print() print(info["extract"]) print() print(info["url"])
Questo codice non “clona” ancora nulla, ma ti mette in mano la base corretta: una richiesta pulita, un identificativo della pagina e un testo pronto da mostrare. L’header `User-Agent` non è un optional estetico: è una buona pratica minima quando interagisci con servizi pubblici.
Salvare le pagine in cache locale
La cache fa la differenza tra un lettore utile e uno irritante. Se l’utente apre la stessa voce cinque volte, non ha senso ripetere le richieste. Puoi salvare ogni pagina in un file JSON nominato in base al titolo normalizzato, oppure in un database SQLite con campi come `title`, `extract`, `url`, `fetched_at` e `source_revision`.
Per un prototipo semplice, una directory `cache/` con file JSON è sufficiente. Il vantaggio è che puoi ispezionare i dati a occhio, fare debug in fretta e capire subito se il problema è nella rete o nel parsing.
import json
import re
from pathlib import Path CACHE_DIR = Path("cache")
CACHE_DIR.mkdir(exist_ok=True) def safe_name(title: str) -> str: return re.sub(r"[^a-zA-Z0-9._-]+", "_", title.strip()) def save_page(data: dict) -> Path: path = CACHE_DIR / f"{safe_name(data['title'])}.json" path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") return path def load_page(title: str) -> dict | None: path = CACHE_DIR / f"{safe_name(title)}.json" if not path.exists(): return None return json.loads(path.read_text(encoding="utf-8"))
Con questa base puoi applicare una logica molto semplice: se il file esiste, lo leggi; se non esiste, interroghi Wikipedia e poi lo salvi. È un pattern banale ma efficace, e soprattutto evita di riscaricare contenuti già noti.
Stampare bene in terminale senza complicarsi la vita
La console non è un browser, quindi il rendering deve essere essenziale. Il testo va ripulito, spezzato in righe leggibili e presentato con una gerarchia minima: titolo, URL, estratto, eventualmente sezioni. Puoi usare il wrapping del testo di Python con il modulo `textwrap`, oppure passare a una libreria come `rich` se vuoi una resa più curata, con colori e box.
Per restare sobri, puoi iniziare così:
import textwrap def print_page(data: dict) -> None: print(data["title"]) print(data.get("url", "")) print() wrapped = textwrap.fill(data.get("extract", ""), width=88) print(wrapped)
Se vuoi aggiungere una navigazione più comoda, puoi mostrare un elenco di risultati e far scegliere all’utente una voce tramite numero. L’idea è mantenere il flusso da terminale corto: cerca, scegli, leggi, salva in cache. Più il ciclo è breve, più il tool viene usato davvero.
Ricerca locale: da singola voce a mini archivio consultabile
Una volta che hai salvato diverse pagine, la ricerca locale diventa la parte più utile. Anche qui hai due strade: scansione dei file JSON oppure database SQLite con indice. Se i documenti sono pochi, la scansione basta. Se superi qualche centinaio di pagine, SQLite è più sensato perché ti consente query più veloci e una struttura stabile.
Per esempio, puoi cercare nei titoli e negli estratti salvati in locale, senza interrogare la rete. Questo cambia parecchio l’esperienza: il terminale diventa reattivo e il progetto si avvicina a un vero lettore offline.
def search_local(term: str) -> list[dict]: results = [] for path in CACHE_DIR.glob("*.json"): data = json.loads(path.read_text(encoding="utf-8")) haystack = f"{data.get('title', '')} {data.get('extract', '')}".lower() if term.lower() in haystack: results.append(data) return results
Questo approccio è lineare e trasparente. Non è il più veloce del mondo, ma per una collezione piccola o media è più che sufficiente. Se in futuro vuoi prestazioni migliori, puoi indicizzare i dati in SQLite con FTS5 e mantenere la stessa logica di alto livello.
Gestire redirect, pagine mancanti e contenuti ambigui
Wikipedia è piena di casi reali che un tool serio deve gestire: titoli che reindirizzano, pagine disambiguate, voci inesistenti o contenuti che non hanno un estratto utile. Se non prevedi questi casi, il tuo script sembrerà funzionare finché non incontrerà il primo titolo ambiguo.
Per i redirect, l’API può seguirli automaticamente. Per le disambiguazioni, conviene intercettare il tipo di pagina e mostrare un messaggio chiaro all’utente, magari con un elenco di possibili alternative. Per le pagine mancanti, il comportamento corretto è semplice: notifica, non inventare nulla, e torna al prompt.
Se un contenuto non è disponibile, il miglior comportamento non è “riempire il vuoto”, ma dirlo chiaramente e lasciare all’utente il controllo del passo successivo.
Versione più completa con CLI minimale
Se vuoi trasformare il prototipo in uno strumento usabile, aggiungi una piccola interfaccia a riga di comando con `argparse`. Ti basta supportare tre azioni: `read`, `search` e `refresh`. Così il tool non è solo un esempio, ma un programma realmente sfruttabile.
import argparse parser = argparse.ArgumentParser(description="Lettore Wikipedia da console")
sub = parser.add_subparsers(dest="cmd", required=True) p_read = sub.add_parser("read")
p_read.add_argument("title") p_search = sub.add_parser("search")
p_search.add_argument("term") p_refresh = sub.add_parser("refresh")
p_refresh.add_argument("title") args = parser.parse_args()
La logica dietro ogni comando resta semplice: `read` prova la cache e, se serve, scarica; `search` interroga il dataset locale; `refresh` forza un aggiornamento della voce. Questa distinzione è utile anche per debug e manutenzione, perché separa chiaramente lettura e scrittura.
Se vuoi davvero “clonare” più contenuti, serve disciplina sui dati
Quando il progetto cresce, il rischio non è tecnico in senso stretto: è organizzativo. Senza una convenzione chiara per i file, una politica di aggiornamento e un modello dati minimo, finisci con una cartella piena di JSON non coerenti. Per evitarlo, definisci subito alcuni campi stabili: titolo canonico, URL, data di acquisizione, lingua, estratto, testo normalizzato e revision ID se disponibile.
La normalizzazione del testo è un altro punto delicato. Devi decidere cosa tenere e cosa eliminare: note a piè di pagina, link interni, riferimenti, tabelle, immagini. Per un lettore da console, spesso conviene conservare il testo principale e una versione ridotta dei link, lasciando perdere il resto. Più il contenuto è pulito, più la lettura è piacevole.
Un esempio di flusso completo
Il flusso più sensato, in sintesi, è questo:
- L’utente lancia `python wiki_reader.py read Python`.
- Il programma cerca `cache/Python.json`.
- Se il file esiste, lo legge e lo mostra.
- Se non esiste, interroga l’API, salva il risultato e poi lo stampa.
- Se l’utente cerca una parola chiave, il tool scandisce la cache locale e mostra i risultati pertinenti.
Questa sequenza è semplice, ma ha una qualità importante: ogni passaggio è verificabile. Puoi controllare la rete, la cache, il parsing e l’output terminale separatamente. È esattamente ciò che vuoi in uno strumento piccolo ma affidabile.
Limiti pratici da tenere presenti
Un clone locale basato sulle API non sostituisce un dump completo di Wikipedia. Non avrai tutto offline, non avrai necessariamente le immagini, e alcune pagine molto ricche di template potranno richiedere una pulizia aggiuntiva. Inoltre, se il tuo obiettivo è avere una copia massiva e sempre aggiornata, devi pianificare storage, sincronizzazione e trattamento dei dati con molta più attenzione.
Però, per leggere da console in modo rapido, questo approccio è quello giusto. Ti dà controllo, evita dipendenze inutili e si adatta bene a un uso personale o a un piccolo strumento interno. La chiave è non promettere il “mirror totale”, ma costruire un archivio locale utile e sostenibile.
Conclusione operativa: partire piccolo e crescere solo se serve
Se vuoi un lettore Wikipedia in Python che funzioni davvero da console, il percorso migliore è partire dall’estratto via API, aggiungere una cache locale, poi introdurre ricerca e aggiornamento incrementale. È una base pulita, leggibile e facile da mantenere. Se in seguito ti serve di più, puoi passare a SQLite, indicizzazione full-text e parsing più raffinato del contenuto completo. Ma la differenza tra un progetto che resta un esperimento e uno che diventa utile sta quasi sempre nella qualità del flusso minimo, non nella quantità di funzioni aggiunte all’inizio.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.