From 892852835f0c136b4e8f1619006d9cf75d3f3202 Mon Sep 17 00:00:00 2001 From: kevin Date: Sat, 14 Dec 2024 23:09:39 +0100 Subject: [PATCH] Scrapping - mas README.md --- MainController.py | 52 +++++ MainView.py | 26 +++ README.md | 54 ++++- __pycache__/MainController.cpython-313.pyc | Bin 19553 -> 23260 bytes __pycache__/MainView.cpython-313.pyc | Bin 12577 -> 14386 bytes models/ScraperModel.py | 63 +++++ .../GamblingGameModel.cpython-313.pyc | Bin 2360 -> 2360 bytes .../__pycache__/MusicPlayer.cpython-313.pyc | Bin 2651 -> 2651 bytes .../NetworkingScanner.cpython-313.pyc | Bin 1884 -> 1884 bytes .../__pycache__/ScraperModel.cpython-313.pyc | Bin 0 -> 3553 bytes models/__pycache__/Sniffer.cpython-313.pyc | Bin 3052 -> 3052 bytes .../__pycache__/SystemStats.cpython-313.pyc | Bin 2542 -> 2542 bytes pruebas.py | 215 ++++++++++-------- 13 files changed, 307 insertions(+), 103 deletions(-) create mode 100644 models/ScraperModel.py create mode 100644 models/__pycache__/ScraperModel.cpython-313.pyc diff --git a/MainController.py b/MainController.py index 768da89..76c0470 100644 --- a/MainController.py +++ b/MainController.py @@ -5,6 +5,7 @@ from models.NetworkingScanner import NetworkScanner from models.Sniffer import packet_callback, sniff from models.MusicPlayer import MusicPlayerModel from models.GamblingGameModel import GamblingGameModel +from models.ScraperModel import ScraperModel import tkinter as tk import time import datetime @@ -21,6 +22,9 @@ class MainController: self.game_model = GamblingGameModel() self.roulette_running = False self.roulette_thread = None + + self.model = ScraperModel() # Modelo para gestionar el scraping + self.scraper_running = False def connect_events(self): """Conecta los eventos de la vista con las funciones del controlador.""" @@ -37,6 +41,54 @@ class MainController: self.view.button_start_roulette.config(command=self.start_roulette) self.view.button_stop_roulette.config(command=self.stop_roulette) + """Conecta los eventos de la vista con las funciones del controlador.""" + self.view.button_start_scraper.config(command=self.start_scraper_thread) + self.view.button_stop_scraper.config(command=self.stop_scraper) + + + def start_scraper_thread(self): + """Inicia el scraping en un hilo separado.""" + start_url = self.view.entry_scraper_url.get().strip() + if not start_url: + self.view.text_scraper_output.insert("end", "Por favor, introduce una URL válida.\n") + return + + self.model.add_url(start_url) # Añadir URL inicial al modelo + self.scraper_running = True + self.view.button_start_scraper.config(state="disabled") + self.view.button_stop_scraper.config(state="normal") + + # Iniciar hilo para el scraping + threading.Thread(target=self.run_scraper, daemon=True).start() + + + def stop_scraper(self): + """Detiene el scraping.""" + self.scraper_running = False + self.view.button_start_scraper.config(state="normal") + self.view.button_stop_scraper.config(state="disabled") + self.view.text_scraper_output.insert("end", "Scraper detenido.\n") + + + def run_scraper(self): + """Ejecuta el scraping y actualiza la interfaz con los resultados.""" + while self.scraper_running and self.model.has_pending_urls(): + current_url, result = self.model.scrape_next_url() + + if isinstance(result, str): # Error + self.view.text_scraper_output.insert("end", f"{result}\n") + else: # Éxito + self.view.text_scraper_output.insert("end", f"Explorando: {current_url}\n") + for link in result: + self.view.text_scraper_output.insert("end", f" - {link}\n") + + self.view.text_scraper_output.see("end") + time.sleep(1) # Retardo para evitar sobrecarga + + self.scraper_running = False + self.view.text_scraper_output.insert("end", "Scraping completado.\n") + self.view.button_start_scraper.config(state="normal") + self.view.button_stop_scraper.config(state="disabled") def start_sniffer_thread(self): """Inicia el sniffer en un hilo separado.""" diff --git a/MainView.py b/MainView.py index 7e2c15f..708235c 100644 --- a/MainView.py +++ b/MainView.py @@ -38,6 +38,8 @@ class MainView: self.create_status_bar() self.create_music_player() + + self.create_scraper_ui() def create_tabs(self): """Crea las solapas dentro del notebook.""" @@ -189,3 +191,27 @@ class MainView: self.result_label = ttk.Label(tab, text="", font=("Arial", 12), foreground="blue") self.result_label.pack(pady=10) + + def create_scraper_ui(self): + """ + Crea la interfaz para el scraping: + - Input y botones en el frame_left. + - TextArea de resultados en la Solapa 5. + """ + # --- Input y botones en frame_left --- + tk.Label(self.frame_left, text="URL del Scraper:", bg="lightblue", font=("Arial", 10)).pack(pady=5) + self.entry_scraper_url = tk.Entry(self.frame_left, width=25, font=("Arial", 10)) + self.entry_scraper_url.pack(pady=5) + + self.button_start_scraper = tk.Button(self.frame_left, text="Iniciar Scraper", font=("Arial", 10)) + self.button_start_scraper.pack(pady=5) + + self.button_stop_scraper = tk.Button(self.frame_left, text="Detener Scraper", font=("Arial", 10), state="disabled") + self.button_stop_scraper.pack(pady=5) + + # --- TextArea en Solapa 5 --- + tab5 = self.notebook.nametowidget(self.notebook.tabs()[4]) # Obtener la solapa 5 + tk.Label(tab5, text="Resultados del Scraper", font=("Arial", 12)).pack(pady=5) + self.text_scraper_output = scrolledtext.ScrolledText(tab5, wrap=tk.WORD, height=20, width=80) + self.text_scraper_output.pack(pady=10, padx=10, fill="both", expand=True) + diff --git a/README.md b/README.md index cc3bd4b..43d9118 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,49 @@ El objetivo principal de este proyecto es implementar tareas distribuidas en dif --- +## 📝 Explicación de las principales funcionalidades + +### Solapas (Tabs) + +1. **IP Tracker** + - Permite rastrear información sobre una dirección IP, como ubicación, tipo, y más, utilizando la API de ipwhois.io. + - Los resultados se muestran en un área de texto con scroll. + +2. **Escaneo de Red** + - Realiza un escaneo de dispositivos conectados a la red local usando la biblioteca `python-nmap`. + - Lista dispositivos encontrados con sus respectivas direcciones IP y MAC. + +3. **Sniffer** + - Captura y analiza paquetes de red en tiempo real utilizando `Scapy`. + - Muestra información relevante del paquete, como origen, destino, protocolo y puertos. + - Incluye funcionalidad para iniciar y detener el análisis. + +4. **Juego de Azar (Ruleta)** + - Un mini-juego de ruleta donde el usuario puede apostar seleccionando un número del 1 al 10. + - Calcula si el jugador gana o pierde y actualiza el saldo en la interfaz. + +5. **Scraper** + - Permite explorar una URL inicial y extraer enlaces relacionados usando `BeautifulSoup`. + - Los resultados se almacenan en una base de datos MongoDB y se muestran en la interfaz en tiempo real. + +### Frame Izquierdo +- **Gestión del Scraper:** + - Entrada para la URL inicial del scraping. + - Botones para iniciar y detener la operación. + +### Frame Derecho +- **Reproductor de Música:** + - Lista canciones disponibles en una carpeta local. + - Botones para reproducir, detener y actualizar la lista de canciones. + +### Barra Inferior (Estado) +- **Indicadores del sistema:** + - Uso de CPU y RAM en tiempo real. + - Velocidad de subida y descarga de red. + - Fecha y hora actualizadas dinámicamente. + +--- + ## 🌍 Contribuciones Si deseas contribuir a este proyecto: @@ -90,12 +133,5 @@ Si deseas contribuir a este proyecto: ## 🎮 Autor -**Kevin Developer**\ -[GitHub](https://github.com/KevinOlarte1) - ---- - -## 📝 Tutorial - -(En este apartado podrás incluir un tutorial detallado para que los usuarios aprendan a utilizar tu proyecto paso a paso.) - +**Kevin Developer** +[GitHub](https://github.com/KevinOlarte1) diff --git a/__pycache__/MainController.cpython-313.pyc b/__pycache__/MainController.cpython-313.pyc index 9287fb3054de84489efc739ca44d0d5a5e783ccb..3d9ddc507ddf9f31d39839886ebcbd8cbca6236c 100644 GIT binary patch delta 4534 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 K-DLEKKJ`H}-VM0eK5;Q{ znWeOB$CqsAA4}4#W(PQc`37^;n&%<(4~mC_J!6|YqHhIeCgz zELHPznJk1uLeTUW3 zhAhAw@5YRIQH=Jvjgz?({j_)^+DAw6X>@j*ktHKRW*S1_2zP9Nt!ra3 zE8>|L7+~y-cycg8by^<`QJuauIK|!+KMp>6BX#%3{np`E=0z)7H;=oAD zi)ft$FMxIM5;z0y0~bK#L)ZsC0C{i}tPq)mPi%~j*YCoGVXzy_fLX8$jDUB*9zx$P zNqCKlc}Z4PUd+{0r7B66OdOB8`Cnp33)tveMcKS;YMJ|OceEa2J+|&v+G87Pb-QfC zt=m1e>6W-O(eC)u7q-QDN_;&LpZy5;-&{^_yLW}kwWOr^$27pOW+(Bxg)#QCspD5u P?7Dr;%;GH*G;aJGS4BNx diff --git a/models/ScraperModel.py b/models/ScraperModel.py new file mode 100644 index 0000000..1d41b94 --- /dev/null +++ b/models/ScraperModel.py @@ -0,0 +1,63 @@ +import requests +from bs4 import BeautifulSoup +from urllib.parse import urljoin +from pymongo import MongoClient + + +class ScraperModel: + def __init__(self): + self.to_visit = [] + self.visited = set() + + # Conexión a MongoDB + self.client = MongoClient("mongodb://localhost:27017/") + self.db = self.client["scraping"] + self.collection = self.db["visited_links"] + + # Crear índice único para evitar duplicados + self.collection.create_index("url", unique=True) + + def add_url(self, url): + """Añade una URL a la lista de pendientes.""" + if url not in self.visited and url not in self.to_visit: + self.to_visit.append(url) + + def scrape_next_url(self): + """Scrapea la siguiente URL.""" + if not self.to_visit: + return None, [] + + current_url = self.to_visit.pop(0) + self.visited.add(current_url) + + try: + # Solicitar la URL + response = requests.get(current_url, timeout=10) + response.raise_for_status() + except requests.RequestException as e: + return current_url, f"Error al acceder a {current_url}: {e}" + + # Procesar los enlaces encontrados + soup = BeautifulSoup(response.text, 'html.parser') + found_links = [] + + for link in soup.find_all('a', href=True): + full_url = urljoin(current_url, link['href']) + if full_url not in self.visited and full_url not in self.to_visit: + self.to_visit.append(full_url) + found_links.append(full_url) + + # Guardar URL visitada en MongoDB + self.save_to_database(current_url) + return current_url, found_links + + def save_to_database(self, url): + """Guarda la URL visitada en la base de datos.""" + try: + self.collection.insert_one({"url": url}) + except Exception as e: + print(f"Error al guardar en la base de datos: {e}") + + def has_pending_urls(self): + """Verifica si hay URLs pendientes.""" + return bool(self.to_visit) diff --git a/models/__pycache__/GamblingGameModel.cpython-313.pyc b/models/__pycache__/GamblingGameModel.cpython-313.pyc index ab30132bba96730e0a4238f8acdb79e3d491ebf6..a9908756a0a16c068975fc2aebdc2c8e319cf795 100644 GIT binary patch delta 19 ZcmdlXv_pvNGcPX}0}x1k+{mTJ2>>*L1hW7D delta 19 ZcmdlXv_pvNGcPX}0}u$_-N>cK2>>(b1eO2* diff --git a/models/__pycache__/MusicPlayer.cpython-313.pyc b/models/__pycache__/MusicPlayer.cpython-313.pyc index 1ef43119ef0109b86aeb0a60adb0ee3480a3318b..fff023b0555dcaf01ea24328af27c450d83641eb 100644 GIT binary patch delta 19 ZcmcaDa$AJ!GcPX}0}x1k+{hKk1pqnu1t9yLRRXq(5}wE-^eOvPUMjIFQeW)`YHJD-Qul?olu&imed#&lpEyyfsyFey z=iYnnnVECW_no^H3N;gGtKVPFrUgR&j+0vBtHRbe2+Kq!GBZUej_ee3fu*d3GB?Ft z;3@CP{FLv4pZX=zO`=5h^$^*Af~{Dgfh-dXyurzIjB!Ih*3`VCXYz(@<#VtQ$W!C0 zrJEoIyQBF}cr_s2T){Hj+Fq5hoMcY33aq!!E4&5>tCP`v|RB5xg`6nh(KJ0{pwX$t*q+^lbsQ>R;rwnBWSIrFc3nXKRidsOnREQP-dHqUW;ddAB)b8HSc}bjx(b z6xCEmQ*<+}-FVEnysa4-8{H+jpQpy=lD0@1tyqJUbZcQuuNtm2^e>` zAAxh!4+-uzo~^2RyYFKL?X{bzXVtdVWIa0}9~k_LvH8QWf9_9Tt7%Qjo2rydT$EJF zfPdX~R0&pdnwds8YWC1{jH40Ir!COAel>@CF_w1X8m6R;?2F%t?h+4u*s3bXPH7U zN_*hY4(K8~#i)60rc(}L{?x4mW^#LdGp1k~d>)TNlIHgEdR^mV zFHx)Z8;8VujkAiJ4Ai_Wk)-c`X~b1Rf&?^4V*eht8j^md1Ec}LUNiM z#KV_lTA+|6xfb#DV0mvPbJID1`#|)Dpr?>+o!^FhJ_bPer!N=CKc@H&+sG(_! zz<7h~j`hyb7c?vHEVfNhYEelwBsG=N(i(`;B0DB62Cp~^#!ybBz=gU12v=M4k(ZA5`oZ55&j+g@c>On4E` zyZhzcFUxIRtF8A=E?s)v*|V~6f1%VlSnM2p#B6kauoNr{;$88MSQ5I6Lig(a=fc1y z?`!&u`L^r8%B`<%txY{?Ep~mnG+7qgOX5IL9C$7czH26t-qo3hmmgey6yFGsE%D{f z?xo=C_U@JV{rK9!N8|V68|}xI#$R^zt^RVo^YO)vu2C=%?s|CZ!L1kJBkRJSL*Im6 z9F3PF?JJ@Cp;Dy380lY|c^(-mNA{N@(PAXJcJi;05C73bI*xC)K;0+_y+xsS_1bgc zgL1g15FRWDgWtV7KqB3x@ZnG^^*S!kPlAx?h3 z$>ILL?LKhNH=%*?edO7`_VH2f*+A3y2={D=L3zXn{f^U~eRmKK1@ry@(l2>Wk0}~b{?~b9u zTr;seVLD=Ug4DF^A+Pu>9;(AB>m8+g>5fU$F`l-;*SgI*WG!_R%hcSaIx1XWj_RfZ zrLJDq=rE|;=qAWpFJ~!~W#abk%+pfe2(RQ-*Srk zqYs1~Wf0%b3njkWGMNR4RNCG*gc`;610^j=ztE_j(Nn5q>(UkVCbE{@So&kE%g`K}fP6I5QWOfwNN6v1 zBiNyjD87c;qr3v0{SLDFI{3n@%ZwYkX;r{?%miyBH literal 0 HcmV?d00001 diff --git a/models/__pycache__/Sniffer.cpython-313.pyc b/models/__pycache__/Sniffer.cpython-313.pyc index 29ec3a0d055a2a7c656f3a7597fa079ab174cf53..590701a49dbecdca822ba41ac4d17bc41acb746f 100644 GIT binary patch delta 19 ZcmaDO{zjbZGcPX}0}x1k+{pEa8vs4#1=|1s delta 19 ZcmaDO{zjbZGcPX}0}$9<-^lfd8vs5$1?2z$ diff --git a/models/__pycache__/SystemStats.cpython-313.pyc b/models/__pycache__/SystemStats.cpython-313.pyc index abbc1fc5f12ee21460207869d0fbfef7bbcdcb0d..f098b602767ca479532cbd8c532b7749e4beadd8 100644 GIT binary patch delta 19 ZcmaDS{7#tbGcPX}0}x1k+{pEW697G^1=j!o delta 19 ZcmaDS{7#tbGcPX}0}$9<-^lfZ697H_1>pby diff --git a/pruebas.py b/pruebas.py index 8620488..a003b29 100644 --- a/pruebas.py +++ b/pruebas.py @@ -1,123 +1,150 @@ -import tkinter as tk -from tkinter import messagebox -import threading -import random +import requests +from bs4 import BeautifulSoup +from urllib.parse import urljoin +from pymongo import MongoClient import time +import tkinter as tk +from tkinter import scrolledtext +import threading -class GamblingGameWithThreads: +def setup_database(): + """ + Configura la conexión a la base de datos MongoDB y retorna la colección. + """ + client = MongoClient("mongodb://localhost:27017/") # Conectar a MongoDB + db = client["scraping"] # Base de datos llamada 'scraping' + collection = db["visited_links"] # Colección llamada 'visited_links' + + # Crear índice único para evitar duplicados + collection.create_index("url", unique=True) + + return collection + + +def insert_visited_link(collection, url): + """ + Inserta una URL visitada en la base de datos. + """ + try: + collection.insert_one({"url": url}) + except Exception as e: + print(f"Error al insertar la URL visitada {url}: {e}") + + +class ScraperApp: def __init__(self, root): self.root = root - self.root.title("Juego de Azar - Ruleta con Hilos") - self.root.geometry("400x400") + self.root.title("Scraper de Enlaces con Hilos") + self.root.geometry("800x500") - # Variables del juego - self.balance = 100 - self.roulette_number = None - self.roulette_running = False - self.roulette_thread = None + # Base de datos MongoDB + self.collection = setup_database() - # Etiqueta de saldo - self.balance_label = tk.Label(self.root, text=f"Saldo: $ {self.balance}", font=("Arial", 14)) - self.balance_label.pack(pady=10) + # Variable para detener el scraping + self.running = False - # Entrada para la apuesta - tk.Label(self.root, text="Tu Apuesta ($):", font=("Arial", 12)).pack() - self.bet_entry = tk.Entry(self.root, width=10, font=("Arial", 12)) - self.bet_entry.pack(pady=5) + # Frame para la URL y botón + frame_top = tk.Frame(self.root) + frame_top.pack(pady=10) - # Entrada para elegir número - tk.Label(self.root, text="Elige un número (1-10):", font=("Arial", 12)).pack() - self.number_entry = tk.Entry(self.root, width=10, font=("Arial", 12)) - self.number_entry.pack(pady=5) + tk.Label(frame_top, text="Introduce la URL inicial:", font=("Arial", 12)).pack(side=tk.LEFT, padx=5) + self.url_entry = tk.Entry(frame_top, width=50, font=("Arial", 12)) + self.url_entry.pack(side=tk.LEFT, padx=5) + self.start_button = tk.Button(frame_top, text="Iniciar Scraping", font=("Arial", 12), command=self.start_scraping) + self.start_button.pack(side=tk.LEFT, padx=5) - # Botones de control - self.start_button = tk.Button(self.root, text="Iniciar Ruleta", font=("Arial", 12), command=self.start_roulette) - self.start_button.pack(pady=10) + self.stop_button = tk.Button(frame_top, text="Detener Scraping", font=("Arial", 12), command=self.stop_scraping, state="disabled") + self.stop_button.pack(side=tk.LEFT, padx=5) - self.stop_button = tk.Button(self.root, text="Detener Ruleta", font=("Arial", 12), state="disabled", command=self.stop_roulette) - self.stop_button.pack(pady=5) + # TextArea para los resultados + self.result_area = scrolledtext.ScrolledText(self.root, wrap=tk.WORD, font=("Arial", 12), height=20, width=90) + self.result_area.pack(pady=10) - # Resultado del juego - self.result_label = tk.Label(self.root, text="", font=("Arial", 12), fg="blue") - self.result_label.pack(pady=10) - - # Número de la ruleta en tiempo real - self.roulette_label = tk.Label(self.root, text="Ruleta: ---", font=("Arial", 16), fg="red") - self.roulette_label.pack(pady=10) - - def start_roulette(self): - """Inicia el giro de la ruleta en un hilo.""" - if self.roulette_running: - messagebox.showwarning("Advertencia", "La ruleta ya está girando.") + def start_scraping(self): + """ + Inicia el scraping en un hilo separado. + """ + start_url = self.url_entry.get().strip() + if not start_url: + self.result_area.insert(tk.END, "Por favor, introduce una URL válida.\n") return - try: - bet = int(self.bet_entry.get()) - chosen_number = int(self.number_entry.get()) - except ValueError: - messagebox.showerror("Error", "Por favor, ingresa valores numéricos válidos.") - return + self.result_area.insert(tk.END, f"Iniciando scraping desde: {start_url}\n") + self.result_area.see(tk.END) - if bet <= 0 or chosen_number < 1 or chosen_number > 10: - messagebox.showwarning("Advertencia", "La apuesta debe ser mayor a $0 y elige un número entre 1 y 10.") - return - - if bet > self.balance: - messagebox.showwarning("Advertencia", "No tienes suficiente saldo para esta apuesta.") - return - - self.bet = bet - self.chosen_number = chosen_number - self.roulette_running = True + self.running = True self.start_button.config(state="disabled") self.stop_button.config(state="normal") - # Crear y arrancar el hilo de la ruleta - self.roulette_thread = threading.Thread(target=self.spin_roulette) - self.roulette_thread.start() + # Iniciar un hilo para el scraping + self.scraping_thread = threading.Thread(target=self.scrape_links_forever, args=(start_url,)) + self.scraping_thread.daemon = True # Hilo se detiene cuando la app se cierra + self.scraping_thread.start() - def spin_roulette(self): - """Simula el giro continuo de la ruleta.""" - while self.roulette_running: - self.roulette_number = random.randint(1, 10) - self.roulette_label.config(text=f"Ruleta: {self.roulette_number}") - time.sleep(0.1) - - def stop_roulette(self): - """Detiene la ruleta y evalúa el resultado del juego.""" - if not self.roulette_running: - return - - self.roulette_running = False + def stop_scraping(self): + """ + Detiene el scraping. + """ + self.running = False + self.result_area.insert(tk.END, "Deteniendo scraping...\n") + self.result_area.see(tk.END) self.start_button.config(state="normal") self.stop_button.config(state="disabled") - # Evaluar resultado - if self.chosen_number == self.roulette_number: - winnings = self.bet * 2 - self.balance += winnings - self.result_label.config( - text=f"¡Ganaste! El número fue {self.roulette_number}. Ganaste $ {winnings}.", - fg="green", - ) - else: - self.balance -= self.bet - self.result_label.config( - text=f"Perdiste. El número fue {self.roulette_number}. Perdiste $ {self.bet}.", - fg="red", - ) + def scrape_links_forever(self, start_url): + """ + Scrapea enlaces indefinidamente y guarda solo los visitados en MongoDB. + Se ejecuta en un hilo separado. + + Args: + start_url (str): URL inicial para comenzar el scraping. + """ + to_visit = [start_url] # Lista de URLs por visitar + visited = set() # Conjunto para evitar bucles - # Actualizar saldo - self.balance_label.config(text=f"Saldo: $ {self.balance}") + while to_visit and self.running: + current_url = to_visit.pop(0) # Tomar la URL actual de la lista - # Revisar si el jugador se quedó sin saldo - if self.balance <= 0: - messagebox.showinfo("Juego Terminado", "¡Te quedaste sin saldo! Gracias por jugar.") - + if current_url in visited: + continue + + self.result_area.insert(tk.END, f"Explorando: {current_url}\n") + self.result_area.see(tk.END) + visited.add(current_url) # Marcar como visitada + + try: + # Realizar la solicitud HTTP + response = requests.get(current_url, timeout=10) + response.raise_for_status() + except requests.RequestException as e: + self.result_area.insert(tk.END, f"Error al acceder a {current_url}: {e}\n") + self.result_area.see(tk.END) + continue + + # Parsear el contenido HTML + soup = BeautifulSoup(response.text, 'html.parser') + + # Encontrar y procesar los enlaces + for link in soup.find_all('a', href=True): + full_url = urljoin(current_url, link['href']) + if full_url not in visited and full_url not in to_visit: + to_visit.append(full_url) + + # Insertar la URL visitada en la base de datos + insert_visited_link(self.collection, current_url) + + # Retardo para evitar sobrecargar el servidor + time.sleep(1) + + # Finalización del scraping + self.result_area.insert(tk.END, "Scraping finalizado.\n") + self.result_area.see(tk.END) + self.start_button.config(state="normal") + self.stop_button.config(state="disabled") if __name__ == "__main__": root = tk.Tk() - app = GamblingGameWithThreads(root) + app = ScraperApp(root) root.mainloop()