Actualización del 2025-06-15 a las 16:43:02
This commit is contained in:
parent
273bc4e02e
commit
d23754d3b8
7 changed files with 333 additions and 63 deletions
93
url_processor.py
Normal file
93
url_processor.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import hashlib
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import newspaper
|
||||
from newspaper import Config
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
def _process_individual_article(article_url, config):
|
||||
"""
|
||||
Función auxiliar que descarga y procesa un solo artículo.
|
||||
Está diseñada para ser ejecutada en un hilo separado.
|
||||
"""
|
||||
try:
|
||||
# Es crucial crear un nuevo objeto Article dentro de cada hilo.
|
||||
article = newspaper.Article(article_url, config=config)
|
||||
article.download()
|
||||
|
||||
# Un artículo necesita ser parseado para tener título, texto, etc.
|
||||
article.parse()
|
||||
|
||||
# Si no se pudo obtener título o texto, no es un artículo válido.
|
||||
if not article.title or not article.text:
|
||||
return None
|
||||
|
||||
# El método nlp() es necesario para el resumen.
|
||||
article.nlp()
|
||||
return article
|
||||
except Exception:
|
||||
# Ignoramos errores en artículos individuales (p.ej., enlaces rotos, etc.)
|
||||
return None
|
||||
|
||||
def process_newspaper_url(url, categoria_id, pais_id):
|
||||
"""
|
||||
Explora la URL de un periódico, extrae los artículos que encuentra
|
||||
en paralelo y devuelve una lista de noticias listas para la base de datos.
|
||||
"""
|
||||
logging.info(f"Iniciando el scrapeo en paralelo de la fuente: {url}")
|
||||
|
||||
todas_las_noticias = []
|
||||
|
||||
try:
|
||||
config = Config()
|
||||
config.browser_user_agent = 'RssApp/1.0 (Scraper)'
|
||||
config.request_timeout = 15 # Timeout más corto para artículos individuales.
|
||||
config.memoize_articles = False # No guardar en caché para obtener siempre lo último.
|
||||
|
||||
source = newspaper.build(url, config=config, language='es')
|
||||
|
||||
# Limitar el número de artículos para no sobrecargar el servidor.
|
||||
articles_to_process = source.articles[:25]
|
||||
|
||||
logging.info(f"Fuente construida. Procesando {len(articles_to_process)} artículos en paralelo...")
|
||||
|
||||
# Usamos un ThreadPoolExecutor para procesar los artículos concurrentemente.
|
||||
with ThreadPoolExecutor(max_workers=10) as executor:
|
||||
# Creamos un futuro para cada URL de artículo.
|
||||
future_to_article = {executor.submit(_process_individual_article, article.url, config): article for article in articles_to_process}
|
||||
|
||||
for future in as_completed(future_to_article):
|
||||
processed_article = future.result()
|
||||
|
||||
# Si el artículo se procesó correctamente, lo añadimos a la lista.
|
||||
if processed_article:
|
||||
noticia_id = hashlib.md5(processed_article.url.encode()).hexdigest()
|
||||
|
||||
if processed_article.summary:
|
||||
resumen = processed_article.summary
|
||||
else:
|
||||
# Fallback a un extracto del texto si no hay resumen.
|
||||
resumen = (processed_article.text[:400] + '...') if len(processed_article.text) > 400 else processed_article.text
|
||||
|
||||
fecha = processed_article.publish_date if processed_article.publish_date else datetime.now()
|
||||
|
||||
todas_las_noticias.append((
|
||||
noticia_id,
|
||||
processed_article.title,
|
||||
resumen,
|
||||
processed_article.url,
|
||||
fecha,
|
||||
processed_article.top_image or '',
|
||||
categoria_id,
|
||||
pais_id
|
||||
))
|
||||
|
||||
if not todas_las_noticias:
|
||||
return [], "No se encontraron artículos válidos en la URL proporcionada."
|
||||
|
||||
return todas_las_noticias, f"Se procesaron {len(todas_las_noticias)} noticias con éxito."
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Excepción al construir la fuente desde '{url}': {e}", exc_info=True)
|
||||
return [], f"Error al explorar la URL principal: {e}"
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue