# Scraper de Wikipedia — Contexto técnico FLUJOS **Fecha:** 2026-04-21 **Archivo:** `FLUJOS_DATOS/WIKIPEDIA/main.py` **Utilidades:** `FLUJOS_DATOS/WIKIPEDIA/wikipedia_utils.py` **Entorno:** `FLUJOS_DATOS/myenv/` (Python 3.11, venv) --- ## Qué hace Descarga artículos de Wikipedia en español organizados por temas de FLUJOS, los limpia, tokeniza con BERT y los guarda en disco (`.txt`) y MongoDB (`wikipedia`). --- ## Temas y palabras clave El scraper itera sobre un diccionario de temas con listas de keywords. Para cada keyword hace una búsqueda en la Wikipedia API y descarga los artículos encontrados. ```python temas = { "inteligencia y seguridad": [ "inteligencia", "seguridad", "espionaje", "ciberseguridad", "NSA", "FBI", "CIA", "contraterrorismo", "criptografía", "vigilancia", "hackeo", "ransomware", ... ], "guerras": [ "guerra", "conflicto", "batalla", "militar", "guerra civil", "intervención militar", "fuerzas armadas", "ejército", "terrorismo", "crímenes de guerra", ... ], "corporaciones": [ "empresa", "multinacionales", "mercado bursátil", "BlackRock", "Vanguard", "fusiones", "adquisiciones", "venture capital", "evasión fiscal", ... ], "demografía": [ "población", "migración", "natalidad", "urbanización", "refugiados", "desigualdad", "pobreza", "pandemia", ... ], "cambio climático": [ "cambio climático", "calentamiento global", "energías renovables", "deforestación", "emisiones de carbono", "acuerdo de París", ... ], "organizaciones internacionales": [ "OTAN", "BRICS", "ONU", "Unión Europea", "FMI", "Banco Mundial", ... ], "gobiernos autoritarios": [ "dictadura", "autoritario", "represión política", "censura", "prisioneros políticos", ... ], } ``` Cada tema tiene entre 50 y 100 palabras clave. En total son ~500 keywords → cada una genera hasta 50 artículos = **potencial de ~25.000 artículos**. --- ## Flujo de scraping ``` para cada (tema, palabras_clave): para cada palabra_clave: buscar_articulos(palabra_clave, max_articulos=50, offset=0) └── GET https://es.wikipedia.org/w/api.php action=query, list=search, srsearch={keyword} para cada titulo encontrado: if titulo not in titulos_descargados: contenido = obtener_contenido_wikipedia(titulo) └── GET https://es.wikipedia.org/w/api.php action=query, prop=revisions, rvprop=content guardar en articulos_wikipedia/{titulo_limpio}.txt titulos_descargados.add(titulo) offset += 50 # paginación time.sleep(1) # cortesía hacia la API ``` **Límite de tamaño:** Para cuando `articulos_wikipedia/` supera 100 GB (en la práctica nunca se ha alcanzado). --- ## Limpieza de texto ```python def limpiar_texto(texto): texto = texto.lower() texto = re.sub(r'[^\w\s]', '', texto) # elimina puntuación palabras = texto.split() palabras_limpias = [p for p in palabras if p not in stopwords] return ' '.join(palabras_limpias) ``` Stopwords: lista manual en español (~200 palabras). No usa NLTK en este módulo (sí en pipeline_completo.py). --- ## Tokenización BERT ```python from transformers import BertTokenizer tokenizer = BertTokenizer.from_pretrained('dccuchile/bert-base-spanish-wwm-cased') def TOKENIZER(): archivos = os.listdir('articulos_wikipedia') for archivo in archivos: contenido = open(f'articulos_wikipedia/{archivo}').read() tokens_ids = tokenizer.encode(contenido, add_special_tokens=False) with open(f'articulos_tokenizados/{archivo}', 'w') as f: f.write(' '.join(map(str, tokens_ids))) ``` - Modelo BERT: `dccuchile/bert-base-spanish-wwm-cased` (BERT en español de la U. de Chile) - Truncación: 512 tokens máximo por documento - Output: archivo `.txt` con IDs numéricos separados por espacios --- ## Limpiar nombre de fichero ```python def limpiar_nombre_archivo(nombre): nombre = re.sub(r'[\\/*?:"<>|]', "_", nombre) return nombre # Ejemplo: "Guerra_del_Golfo_(1990)" → "Guerra_del_Golfo__1990_" ``` El nombre del fichero es el título del artículo de Wikipedia limpiado. Es también el `archivo` en MongoDB (clave de dedup). --- ## Asignación de tema y subtema Esta lógica vive en `pipeline_completo.py::asignar_tema_y_subtema()`, no en el scraper. El scraper solo guarda texto; el tokenizador/comparador asigna el tema. ```python tematicas = { 'inteligencia y seguridad': ['inteligencia', 'ciberseguridad', 'espionaje', ...], 'cambio climático': ['cambio climático', 'desastres naturales', ...], 'guerra global': ['conflictos internacionales', 'guerras civiles', ...], 'demografía y sociedad': ['sobrepoblación', 'migraciones', ...], 'economía y corporaciones': ['economía global', 'corporaciones multinacionales', ...], } # Si ningún keyword coincide: tema='otros', subtema='general' ``` --- ## Documento MongoDB generado (colección `wikipedia`) ```json { "_id": ObjectId, "archivo": "Guerra_del_Golfo.txt", "tema": "guerra global", "subtema": "conflictos internacionales", "texto": "La Guerra del Golfo fue un conflicto armado...", "fecha": null // Wikipedia no suele tener fecha de publicación clara } ``` La inserción usa upsert por `archivo` para deduplicar. --- ## Almacenamiento en disco (ignorado por git) ``` FLUJOS_DATOS/WIKIPEDIA/ ├── articulos_wikipedia/ # .gitignore — txt en español por artículo ├── articulos_tokenizados/ # .gitignore — IDs BERT por artículo ├── main.py ├── wikipedia_utils.py └── docs.txt ``` --- ## Ejecución dentro del pipeline maestro `pipeline_maestro.py` Fase 1 llama: ```bash /var/www/theflows.net/flujos/FLUJOS_DATOS/myenv/bin/python3 \ FLUJOS_DATOS/WIKIPEDIA/main.py ``` Desde el directorio `FLUJOS_DATOS/WIKIPEDIA/` para que las rutas relativas (`articulos_wikipedia/`) funcionen. --- ## Limitaciones conocidas 1. **Sin fecha en artículos Wikipedia** — El scraper no extrae la fecha de revisión. El campo `fecha` queda en `null` o vacío en Mongo, lo que rompe los filtros de fecha en la API. 2. **Nombres duplicados potenciales** — Artículos con títulos similares generan el mismo nombre de fichero después de la limpieza. 3. **No hay control de idioma** — Si un keyword es un acrónimo (NSA, CIA), puede devolver artículos en inglés mezclados con los españoles. 4. **Tokenización trunca a 512 tokens** — Artículos largos pierden la segunda mitad para el cálculo de similitud. 5. **Sin rate limiting robusta** — Solo `time.sleep(1)` entre keywords, pero la Wikipedia API tiene un límite de 200 req/s por IP (raramente alcanzado). --- ## Dependencias ``` transformers>=4.45 (BertTokenizer) tqdm requests pymongo ``` BERT (`dccuchile/bert-base-spanish-wwm-cased`) se descarga automáticamente en el primer uso (~500 MB, se cachea en `~/.cache/huggingface/`).