File size: 5,396 Bytes
6f77dbb
f80191b
f9f6108
 
6f77dbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f80191b
6f77dbb
 
f80191b
6f77dbb
 
f80191b
6f77dbb
 
 
 
 
 
 
 
 
354e511
9e98716
6f77dbb
 
f80191b
6f77dbb
f80191b
 
6f77dbb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import gradio as gr
import requests
from bs4 import BeautifulSoup
import time
import random
from urllib.parse import urljoin

# --- Técnicas Anti-Scraping ---
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
]

def get_random_user_agent():
    """ Devuelve un User-Agent al azar. """
    return random.choice(USER_AGENTS)

# --- Función Principal de Scraping ---
def scrape_website(url, max_links_str):
    """
    Scrapea la URL, entra en cada link de detalle, extrae el contenido de las tablas
    y devuelve un archivo de texto para descargar.
    """
    if not url.startswith('http'):
        url = 'https://' + url

    # Convertir el número máximo de links a entero, con un valor por defecto
    try:
        max_links = int(max_links_str)
    except (ValueError, TypeError):
        max_links = 10 # Valor por defecto si la entrada no es válida

    links_to_visit = set()
    all_content = f"Resultados del scraping para: {url}\n"
    all_content += "========================================\n\n"

    try:
        # 1. Petición a la URL principal
        headers = {'User-Agent': get_random_user_agent()}
        response = requests.get(url, headers=headers, timeout=15)
        response.raise_for_status()
        soup = BeautifulSoup(response.content, 'html.parser')

        # 2. Encontrar todos los links que parecen ser de audiencias
        # Se busca un patrón específico para ser más preciso
        for a_tag in soup.find_all('a', href=True):
            link = a_tag['href']
            # Usamos urljoin para construir correctamente la URL absoluta
            full_link = urljoin(url, link)
            # Filtramos para quedarnos solo con los links de audiencias del mismo sitio
            if url in full_link and '/audiencias/' in full_link:
                links_to_visit.add(full_link)

        all_content += f"Se encontraron {len(links_to_visit)} links de audiencias para visitar.\n"
        all_content += f"Procesando los primeros {min(len(links_to_visit), max_links)} links...\n\n"

        # 3. Visitar cada link y extraer el contenido de la tabla
        for i, link in enumerate(list(links_to_visit)[:max_links]):
            try:
                time.sleep(random.uniform(1, 2.5)) # Pausa respetuosa
                headers = {'User-Agent': get_random_user_agent()}
                detail_response = requests.get(link, headers=headers, timeout=10)
                detail_response.raise_for_status()
                detail_soup = BeautifulSoup(detail_response.content, 'html.parser')

                title = detail_soup.find('title').get_text(strip=True) if detail_soup.find('title') else "Sin título"
                all_content += f"--- Contenido de: {link} ---\n"
                all_content += f"Título: {title}\n\n"

                # Buscar la tabla de detalles (inspeccionando la página, vemos que tiene la clase 'table') [4, 5]
                table = detail_soup.find('table', class_='table')
                if table:
                    # Extraer todas las filas de la tabla [1]
                    rows = table.find_all('tr')
                    for row in rows:
                        # Extraer las celdas de cabecera (th) y datos (td)
                        cols = row.find_all(['th', 'td'])
                        # Limpiar y unir el texto de las celdas
                        cleaned_cols = [ele.text.strip() for ele in cols]
                        all_content += " | ".join(cleaned_cols) + "\n"
                else:
                    all_content += "No se encontró una tabla de detalles en esta página.\n"

                all_content += "\n----------------------------------------\n\n"

            except requests.RequestException as e:
                all_content += f"Error al visitar {link}: {e}\n\n"

    except requests.RequestException as e:
        return f"Error al acceder a la URL principal: {e}", None # Devuelve dos valores

    # 4. Crear el archivo de texto y devolverlo
    # Gradio maneja la creación del archivo temporal automáticamente [7, 8]
    file_path = "resultados_scraping.txt"
    with open(file_path, "w", encoding="utf-8") as f:
        f.write(all_content)

    # Devolvemos un mensaje de éxito y la ruta del archivo para la descarga
    return f"¡Proceso completado! Se procesaron {min(len(links_to_visit), max_links)} links. Descarga el archivo para ver los resultados.", file_path


# --- Interfaz con Gradio ---
iface = gr.Interface(
    fn=scrape_website,
    inputs=[
        gr.Textbox(lines=1, placeholder="Ingresa una URL (ej. leylobby.gob.cl/...)"),
        gr.Textbox(value="10", label="Número máximo de links a visitar")
    ],
    outputs=[
        gr.Textbox(label="Estado del Proceso"),
        gr.File(label="Descargar Resultados (.txt)") # Componente de descarga de archivo [7, 9]
    ],
    title="🤖 Web Scraper Pro v2",
    description="Ingresa una URL para extraer el contenido de los links de detalle. El resultado se genera en un archivo .txt descargable. ¡Ideal para análisis de datos!",
    allow_flagging="never"
)

# ¡Lanzamos la app!
iface.launch()