148 lines
6.5 KiB
Python
148 lines
6.5 KiB
Python
import requests
|
|
from bs4 import BeautifulSoup
|
|
import os
|
|
from datetime import datetime
|
|
from urllib.parse import quote
|
|
from tkinter import \
|
|
messagebox # Para usar messagebox en errores críticos si el Tkinter Loop lo permite (Aunque se recomienda devolver el error)
|
|
|
|
# --- CONSTANTES DE CONFIGURACIÓN ---
|
|
# URL base para realizar búsquedas en Wikipedia en español.
|
|
URL_BASE_BUSQUEDA = "https://es.wikipedia.org/w/index.php?search="
|
|
URL_TERMINACION = "&title=Especial:Buscar&go=Ir"
|
|
ARCHIVO_SALIDA = "res/datos_extraidos.txt"
|
|
|
|
|
|
def hacer_scraping(termino_busqueda: str):
|
|
"""
|
|
Construye una URL de búsqueda en Wikipedia con el término proporcionado,
|
|
extrae el contenido del primer artículo encontrado y guarda el resultado.
|
|
|
|
Args:
|
|
termino_busqueda (str): El texto a buscar (ej: "Expedición 30").
|
|
|
|
Returns:
|
|
tuple: (bool, str, str) - Éxito (bool), mensaje de estado (str), y contenido extraído (str).
|
|
"""
|
|
termino_busqueda = termino_busqueda.strip()
|
|
|
|
if not termino_busqueda:
|
|
return False, "❌ El término de búsqueda no puede estar vacío.", ""
|
|
|
|
# 1. Construir la URL de búsqueda
|
|
url_codificada = quote(termino_busqueda)
|
|
url_final = URL_BASE_BUSQUEDA + url_codificada + URL_TERMINACION
|
|
|
|
print(f"🔗 Buscando y extrayendo datos de: {url_final}")
|
|
|
|
try:
|
|
# 2. Realizar la solicitud HTTP
|
|
headers = {
|
|
'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
|
|
'AppleWebKit/537.36 (KHTML, like Gecko) '
|
|
'Chrome/91.0.4472.124 Safari/537.36')
|
|
}
|
|
response = requests.get(url_final, headers=headers, timeout=15)
|
|
response.raise_for_status()
|
|
|
|
# 3. Parsear el contenido
|
|
soup = BeautifulSoup(response.content, 'html.parser')
|
|
|
|
# 4. Intentar encontrar el artículo directamente
|
|
title_tag = soup.find('h1', id='firstHeading')
|
|
title = title_tag.get_text().strip() if title_tag else "Sin Título"
|
|
|
|
# Si el resultado es una lista de búsqueda (no fue a un artículo directo)
|
|
if title.startswith('Buscar:'):
|
|
# Intentamos extraer el enlace del primer resultado de búsqueda
|
|
results_list = soup.find('ul', class_='mw-search-results')
|
|
if results_list:
|
|
first_result = results_list.find('a')
|
|
if first_result:
|
|
# Construir la URL completa del primer resultado
|
|
new_url = "https://es.wikipedia.org" + first_result['href']
|
|
print(f"➡️ Redirigiendo a primer resultado: {new_url}")
|
|
# Llamamos a la función auxiliar con la URL del artículo
|
|
return hacer_scraping_articulo(new_url, termino_busqueda)
|
|
|
|
# Si no hay resultados o no se puede seguir el enlace:
|
|
return False, f"❌ Wikipedia no encontró resultados de artículo para '{termino_busqueda}'.", ""
|
|
|
|
# Si encontramos un artículo directamente, extraemos el contenido inmediatamente
|
|
else:
|
|
return hacer_scraping_articulo(url_final, termino_busqueda, title, soup)
|
|
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
return False, f"❌ Error de red o HTTP al buscar: {e}", ""
|
|
except Exception as e:
|
|
return False, f"❌ Error desconocido en la búsqueda: {type(e).__name__}: {e}", ""
|
|
|
|
|
|
# --- FUNCIÓN AUXILIAR DE EXTRACCIÓN DE ARTÍCULO ---
|
|
|
|
def hacer_scraping_articulo(url_articulo, termino_busqueda, title=None, soup=None):
|
|
"""
|
|
Función auxiliar para extraer el contenido de una URL de artículo específica de Wikipedia.
|
|
"""
|
|
try:
|
|
# Si no se pasó el objeto soup (ej. llamada desde redirección), hacemos la solicitud
|
|
if soup is None:
|
|
headers = {
|
|
'User-Agent': ('Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
|
|
'AppleWebKit/537.36 (KHTML, like Gecko) '
|
|
'Chrome/91.0.4472.124 Safari/537.36')
|
|
}
|
|
response = requests.get(url_articulo, headers=headers, timeout=15)
|
|
response.raise_for_status()
|
|
soup = BeautifulSoup(response.content, 'html.parser')
|
|
title_tag = soup.find('h1', id='firstHeading')
|
|
title = title_tag.get_text().strip() if title_tag else "Sin Título"
|
|
|
|
# 4b. Extraer el Cuerpo de Texto del artículo
|
|
# Buscamos en el div principal y excluimos elementos de navegación/metadatos.
|
|
content_div = soup.find('div', id='mw-content-text')
|
|
|
|
if content_div:
|
|
# Extraer párrafos, encabezados y listas dentro del contenido principal
|
|
text_elements = content_div.find_all(['p', 'h2', 'h3', 'li'])
|
|
full_text = "\n".join(element.get_text().strip() for element in text_elements if element.get_text().strip())
|
|
else:
|
|
full_text = "No se pudo encontrar el contenido principal del artículo."
|
|
|
|
# Limitar la longitud del texto
|
|
max_length = 1500
|
|
extracted_text = full_text[:max_length]
|
|
if len(full_text) > max_length:
|
|
extracted_text += "\n[... Contenido truncado ...]"
|
|
|
|
# 5. Formatear
|
|
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
output = (
|
|
f"\n\n==========================================================\n"
|
|
f"== 🌐 DATOS EXTRAÍDOS (Búsqueda: '{termino_busqueda}') ==\n"
|
|
f"==========================================================\n"
|
|
f"URL Artículo: {url_articulo}\n"
|
|
f"TÍTULO: {title}\n"
|
|
f"FECHA/HORA: {timestamp}\n"
|
|
f"----------------------------------------------------------\n"
|
|
f"CONTENIDO (Primeros {len(extracted_text)} chars):\n"
|
|
f"----------------------------------------------------------\n"
|
|
f"{extracted_text}\n"
|
|
)
|
|
|
|
# 6. Guardar en archivo
|
|
os.makedirs('res', exist_ok=True)
|
|
with open(ARCHIVO_SALIDA, 'a', encoding='utf-8') as f:
|
|
f.write(output)
|
|
|
|
print(f"✅ Extracción completada. Datos guardados en {ARCHIVO_SALIDA}")
|
|
|
|
# 7. Devolver el resultado para su visualización en la GUI
|
|
return True, f"✅ Extracción de '{title}' (Artículo de Wikipedia) completada.", output
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
return False, f"❌ Error de red o HTTP al acceder al artículo: {e}", ""
|
|
except Exception as e:
|
|
return False, f"❌ Error desconocido en la extracción del artículo: {type(e).__name__}: {e}", "" |