luchitochavez / app.py
djzero2's picture
Update app.py
b2adf47 verified
Raw History Blame Contribute Delete
6.41 kB
import gradio as gr
import requests
from newspaper import Article
import base64
def extraer_info(url):
if not url.strip():
return "[Error]: Por favor, ingresa una URL válida.", "<p>Sin imagen</p>"
try:
# Cabeceras simulando un navegador real para el HTML de la noticia
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "es-ES,es;q=0.9",
"Referer": "https://www.google.com/"
}
# Descargamos el HTML de la noticia
response = requests.get(url, headers=headers, timeout=15)
if response.status_code != 200:
return f"[Error del Servidor Web]: El sitio respondió con código {response.status_code}. Bloqueo Anti-Bot activo.", "<p>No se pudo cargar la noticia debido al bloqueo del sitio web.</p>"
# Procesamos con newspaper3k
articulo = Article(url, language='es')
articulo.set_html(response.text)
articulo.parse()
titulo_y_texto = f"TÍTULO: {articulo.title}\n\n{articulo.text}"
# --- BLOQUE SEGURO DE DESCARGA DE IMAGEN ---
html_imagen = ""
if articulo.top_image:
try:
# Modificamos el Referer para que parezca que estamos viendo la imagen desde el propio periódico
headers_imagen = headers.copy()
headers_imagen["Referer"] = url
# Intentamos descargar la imagen
img_response = requests.get(articulo.top_image, headers=headers_imagen, timeout=10)
if img_response.status_code == 200:
content_type = img_response.headers.get('content-type', 'image/jpeg')
encoded_img = base64.b64encode(img_response.content).decode('utf-8')
# --- SOLUCIÓN VISUAL PARA INTEGRACIÓN EN PANTALLA DE INICIO (iOS) ---
html_imagen = f"""
<div style="text-align: center;">
<p style="color: #6b7280; font-size: 13px; margin-bottom: 8px; font-weight: 500;">
📱 En iPhone: Mantén presionada la imagen para guardarla en tus Fotos
</p>
<img src="data:{content_type};base64,{encoded_img}" style="max-width:100%; height:auto; border-radius:8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);" alt="Imagen de la noticia">
</div>
"""
else:
# Si da 403 o cualquier otro error, NO rompemos la app, damos una alternativa
html_imagen = f"""
<div style='border: 1px dashed #ef4444; padding: 10px; border-radius: 8px; text-align: center;'>
<p style='color:#ef4444; margin: 0; font-weight: bold;'>⚠️ Error {img_response.status_code} al descargar imagen</p>
<p style='color:gray; font-size: 12px; margin: 5px 0 0 0;'>El servidor de la noticia bloqueó la descarga automatizada de la imagen, pero el texto se extrajo con éxito.</p>
</div>
"""
except Exception as e:
# Si hay timeout o error de conexión en la imagen, la app sigue viva
html_imagen = f"<p style='color:orange;'>⚠️ No se pudo previsualizar la imagen (Error de conexión).</p>"
else:
html_imagen = "<p style='color:gray;'>Este artículo no contiene una imagen principal.</p>"
return titulo_y_texto, html_imagen
except Exception as e:
# Este catch solo atrapa errores graves del procesamiento de texto
return f"[Error al extraer la información]: {str(e)}", "<p style='color:red;'>Error crítico en el proceso</p>"
# Interfaz Gráfica con gr.Blocks
with gr.Blocks(title="Extractor de Noticias") as demo:
gr.Markdown("## 📰 Extractor de Texto e Imagen de Noticias")
gr.Markdown("Pega el enlace de un artículo para obtener su contenido limpio y la imagen principal.")
with gr.Row():
with gr.Column(scale=2):
url_input = gr.Textbox(
label="URL de la noticia",
placeholder="https://ejemplo.com/noticia",
lines=1
)
btn_extraer = gr.Button("🚀 Extraer Contenido", variant="primary")
gr.HTML("""
<button id="btn_copiar" style="
width: 100%;
background-color: #2563eb;
color: white;
padding: 10px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: bold;
margin-top: 10px;
" onclick="
const txt = document.querySelector('#texto_extraido textarea');
if (txt && txt.value) {
navigator.clipboard.writeText(txt.value).then(() => {
const btn = document.getElementById('btn_copiar');
const original = btn.innerHTML;
btn.innerHTML = '✔️ ¡Copiado!';
btn.style.backgroundColor = '#16a34a';
setTimeout(() => {
btn.innerHTML = original;
btn.style.backgroundColor = '#2563eb';
}, 2000);
});
} else {
alert('No hay texto para copiar');
}
">📋 Copiar texto extraído</button>
""")
with gr.Column(scale=3):
gr.Markdown("### Imagen principal")
imagen_output = gr.HTML(value="<p style='color:gray;'>La imagen aparecerá aquí...</p>")
texto_output = gr.Textbox(
label="Texto e información extraída",
lines=12,
interactive=False,
elem_id="texto_extraido"
)
btn_extraer.click(
fn=extraer_info,
inputs=[url_input],
outputs=[texto_output, imagen_output]
)
demo.launch()