refactor: reorganizar docs y pocs bajo INFO/
- docs/ → INFO/DOCS/CONTEXT/ (documentación técnica en markdown) - FLUJOS/DOCS/ + FLUJOS_DATOS/DOCS/ → INFO/DOCS/ (txts de arquitectura) - POCS/ → INFO/POCS/ (pruebas de concepto) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
83f67b76b4
commit
954f47996f
33 changed files with 0 additions and 0 deletions
205
INFO/DOCS/CONTEXT/SCRAPER_WIKIPEDIA.md
Normal file
205
INFO/DOCS/CONTEXT/SCRAPER_WIKIPEDIA.md
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
# 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/`).
|
||||
Loading…
Add table
Add a link
Reference in a new issue