def scrapearBusquedaSinCuenta(self, busqueda): print( f"[SCRAPER] Recuperando artículos de búsqueda '{busqueda.keywords}' del usuario {self.usuario.id_telegram}" ) articulos_recuperados = self.recuperarArticulosWallapop(busqueda) gestorBBDD = GestorBBDD() for articulo in articulos_recuperados: # Si no está en la base de datos, no está estudiado para esta búsqueda. excluido = articulo.estaExcluido(busqueda) existe = gestorBBDD.existeArticulo(articulo.id_articulo, busqueda.id_busqueda) # Solo notifico if (not (excluido) and not (existe)): self.notificador.notificarAnuncio(self.usuario.id_telegram, articulo, busqueda) # Finalmente, lo añado a la base de datos. gestorBBDD.insertarArticulo(articulo) print( f"[SCRAPER] Scrapeo de la búsqueda {busqueda.id_busqueda} del usuario {self.usuario.id_telegram} finalizado." )
def scrapearBusquedas(self, lista_busquedas_usuario): gestorBBDD = GestorBBDD() try: for busqueda in lista_busquedas_usuario: # Verifico si es la primera vez que se realiza la búsqueda articulos = gestorBBDD.recuperarArticulosBusqueda( busqueda.id_busqueda) no_hay_articulos = len(articulos) == 0 # Si es la primera vez, añado artículos de una búsqueda inicial, para no notificar de los anuncios ya existentes. if (no_hay_articulos): print( f"[SCRAPER] La búsqueda {busqueda.id_busqueda} se lanza por primera vez. Scrapeo artículos iniciales. " ) self.scrapeoInicial(busqueda) if (self.tiene_cuenta): self.scrapearBusqueda(busqueda) else: self.scrapearBusquedaSinCuenta(busqueda) print( f"[SCRAPER] Scrapeo de todas las búsquedas del usuario {self.usuario.id_telegram} finalizado." ) except Exception as e: print( f"[SCRAPER] Error scrapeando las búsquedas de {self.usuario.id_telegram}: {e}. Se aborta el scrapeo..." ) finally: self.notificador.notificarFinScrapeo(self.usuario.id_telegram) # Cierro el driver y con ello el navegador. self.driver.quit()
def borrar_busqueda(self, update, context): gestorBBDD = GestorBBDD() id_telegram = update.message.from_user.id opciones = [] if(gestorBBDD.existeUsuario(id_telegram)): print(f"[TELEGRAM] Usuario {id_telegram} quiere borrar búsquedas. ") try: busquedas = gestorBBDD.recuperarBusquedasUsuario(id_telegram) if(len(busquedas) > 0): texto = "¿Qué busqueda quieres borrar?" contador = 1 for busqueda in busquedas: texto+=f"\n[{contador}] - {busqueda.keywords} [{busqueda.precio_min},{busqueda.precio_max}]" opciones.append([f"Borrar {contador}"]) contador+=1 texto+=f"\n Utiliza /cancelar_borrar_busqueda para cancelar el borrado. " keyboard = ReplyKeyboardMarkup(opciones, one_time_keyboard=True) update.message.reply_text(texto, reply_markup=keyboard) return self.STATUS1 else: update.message.reply_text("No tienes ninguna búsqueda guardada.") except: update.message.reply_text("No tienes ninguna búsqueda guardada.") else: update.message.reply_text("No estás registrado. Escribe /registrarse. ") return ConversationHandler.END
def add_busqueda_siete(self, update, context): # Recojo keywords lista_keywords_descripcion_reincluyentes = update.message.text context.user_data[ "lista_keywords_descripcion_reincluyentes"] = lista_keywords_descripcion_reincluyentes.split( ", ") # Habilito comparación solo si el usuario ha metido su cuenta de WP en la BBDD. gestorBBDD = GestorBBDD() id_telegram = update.message.from_user.id usuario = gestorBBDD.recuperarUsuario(id_telegram) tiene_cuenta = (usuario.email != "None" and usuario.password != "None") if (tiene_cuenta): keyboard = ReplyKeyboardMarkup([["Si"], ["No"]], one_time_keyboard=True) texto = "La autocomparación hace que se estudien todos los anuncios nuevos, y solo se te avise de los anuncios que se consideren chollos. Si no la activas, se te avisarán de todos los anuncios. ¿Deseas activar la autocomparación?" update.message.reply_text(texto, reply_markup=keyboard) return self.STATUS8 else: # Si no tiene cuenta, relleno los campos restantes con valores por defecto, # teniendo en cuenta que no se van a utilizar. context.user_data["multiplicador_minimo"] = 0.4 context.user_data["multiplicador_maximo"] = 0.6 context.user_data["porcentaje_considerado_chollo"] = 0.2 context.user_data["comparar_automaticamente"] = False context.user_data["enviar_mensaje_auto"] = False texto = "Muy bien. Guardando búsqueda... " update.message.reply_text(texto) self.guardarBusqueda(id_telegram, update, context) return ConversationHandler.END
def iniciar_registro(self, update, context): # Si ya tiene cuenta, no dejo que se registre. gestorBBDD = GestorBBDD() id_telegram = update.message.from_user.id if(gestorBBDD.existeUsuario(id_telegram)): update.message.reply_text("Ya tienes una cuenta, no puedes añadir otra. Puedes borrar la previamente introducida con /borrar_cuenta. ") return ConversationHandler.END # Si no, pido código de invitación. else: print(f"[TELEGRAM] usuario {id_telegram} empieza a registrarse.") update.message.reply_text("Introduce código de invitación o usa /cancelar_registro en cualquier momento para cancelar el registro: ", reply_markup=ForceReply()) return self.STATUS1
def start(self, update, context): id_telegram = update.message.from_user.id nombre_usuario = update.message.from_user.username print(f"[TELEGRAM] Usuario {id_telegram} lanza /start. ") gestorBBDD = GestorBBDD() context.user_data["tiene_cuenta"] = gestorBBDD.existeUsuario(update.message.from_user.id) context.user_data["email"] = "" context.user_data["password"] = "" context.user_data["mensaje"] = "" context.user_data["codigo_postal"] = "" bienvenida = f'¡Hola {nombre_usuario}! Soy un bot para actualizarte con los nuevos anuncios que se suban en Wallapop. Utiliza /ayuda para ver los comandos disponibles.' update.message.reply_text(bienvenida)
def __init__(self, usuario, notificador, recursos="altos", ejecucion_en_background=False): # Cargo el notificador self.notificador = notificador # Recupero usuario y veo si tiene cuenta self.usuario = usuario self.tiene_cuenta = (self.usuario.email != None) and (self.usuario.password != None) # Recupero búsquedas de la BBDD gestorBBDD = GestorBBDD() self.lista_busquedas = gestorBBDD.recuperarBusquedasUsuario( self.usuario.id_telegram) # Ajustes de configuración del webdriver self.recursos = recursos self.ejecucion_en_bakcground = ejecucion_en_background # Ignoro errores de certificado self.options = webdriver.ChromeOptions() self.options.add_argument('--ignore-certificate-errors') self.options.add_argument('--ignore-ssl-errors') self.options.add_argument("--start-maximized") self.options.add_argument("log-level=3") self.options.add_argument("--silent") # Configuro ventana para su ejecución en segundo plano if (ejecucion_en_background): self.options.add_argument('--disable-gpu') self.options.add_argument('--headless') self.options.add_argument("--window-size=1920x1080") # Si el host es un ordenador con bajos recursos, abrirá ventanas de una en una cerrándolas # en lugar de varias de golpe if (self.recursos == "bajos"): self.driver = webdriver.Chrome(ChromeDriverManager().install(), options=self.options) else: caps = DesiredCapabilities().CHROME caps["pageLoadStrategy"] = "eager" self.driver = webdriver.Chrome(ChromeDriverManager().install(), desired_capabilities=caps, options=self.options) # Lanzo el bot self.iniciarBot()
def iniciar(self, update, context): id_telegram = update.message.from_user.id print(f"[TELEGRAM] Usuario {id_telegram} lanza /iniciar. ") gestorBBDD = GestorBBDD() if(gestorBBDD.existeUsuario(id_telegram) and len(gestorBBDD.recuperarBusquedasUsuario(id_telegram)) > 0): if(self.diccionario_scrapers.get(id_telegram) == None): usuario = gestorBBDD.recuperarUsuario(id_telegram) busquedas_usuario = gestorBBDD.recuperarBusquedasUsuario(id_telegram) for busqueda in busquedas_usuario: # Si está activada la autocomparación, borro artículos anteriores # y relleno con los nuevos desde scraperwallapop, de forma que # solo se van comparando los artículos nuevos subidos. if(busqueda.comparar_automaticamente == True): print(f"[TELEGRAM] Borro artículos previos de la búsqueda {busqueda.keywords} del usuario {id_telegram} porque tiene autocomparación. ") gestorBBDD.borrarArticulosBusqueda(busqueda.id_busqueda) notificador = Notificador(self.TOKEN) tarea = TareaPeriodica(10, ScraperWallapop, usuario, notificador, ejecucion_en_background=False) update.message.reply_text("Iniciando scrapeo. ") self.diccionario_scrapers[id_telegram] = tarea tarea.start() else: update.message.reply_text("Ya se está scrapeando, utiliza /detener para detener el scrapeo.") else: update.message.reply_text("Debes tener una cuenta y al menos una búsqueda para iniciar el scrapeo. ")
def borrar_cuenta(self, update, context): gestorBBDD = GestorBBDD() id_telegram = update.message.from_user.id print(f"[TELEGRAM] Usuario {id_telegram} va a borrar su cuenta. ") if (gestorBBDD.existeUsuario(id_telegram)): texto = "Se borrará tu cuenta y todas las búsquedas y artículos guardados asociados. Esta acción no se puede deshacer. ¿Estás seguro de que quieres continuar?" reply_keyboard = [["Si"], ["No"]] keyboard = ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True) update.message.reply_text(texto, reply_markup=keyboard) return self.STATUS1 else: update.message.reply_text( "Debes haberte registrado para poder borrar tu cuenta.") return ConversationHandler.END
def add_busqueda(self, update, context): gestorBBDD = GestorBBDD() id_telegram = update.message.from_user.id if (gestorBBDD.existeUsuario(id_telegram)): print( f"[TELEGRAM] Usuario {id_telegram} comienza a registrar búsqueda. " ) self.iniciar_diccionario_busqueda(update, context) update.message.reply_text( "Introduce las keywords de tu búsqueda o utiliza en cualquier momento /cancelar_add_busqueda para cancelar.", reply_markup=ForceReply()) return self.STATUS1 else: update.message.reply_text( "Necesitas registrarte para poder añadir una búsqueda. Usa /registrarse ." )
def scrapearBusqueda(self, busqueda): print( f"[SCRAPER] Recuperando artículos de búsqueda '{busqueda.keywords}'" ) articulos_recuperados = self.recuperarArticulosWallapop(busqueda) gestorBBDD = GestorBBDD() for articulo in articulos_recuperados: # Si no está en la base de datos, no está estudiado para esta búsqueda. excluido = articulo.estaExcluido(busqueda) existe = gestorBBDD.existeArticulo(articulo.id_articulo, busqueda.id_busqueda) if (not (excluido) and not (existe)): # Lo añado a la base de datos. gestorBBDD.insertarArticulo(articulo) # Si está activada la autocomparación, pues comparo. if (busqueda.comparar_automaticamente): preciosArticulo = self.__extraerPreciosArticulo( articulo, busqueda) chollo = self.__esChollo(articulo, busqueda, preciosArticulo) if (chollo): print( f"[SCRAPER] El usuario {self.usuario.id_telegram} ha encontrado un chollo: {articulo.titulo} - {articulo.precio} [{articulo.enlace}]" ) self.notificador.notificarChollo( self.usuario.id_telegram, articulo, busqueda) if (busqueda.enviar_mensaje_auto): self.enviarMensaje(articulo) else: print( f"[SCRAPER] El usuario {self.usuario.id_telegram} ha analizado {articulo.titulo} - {articulo.precio}, pero no es un chollo..." ) # Si no está activada la autocomparación, solo notifico. else: self.notificador.notificarAnuncio(self.usuario.id_telegram, articulo, busqueda) print( f"[SCRAPER] Scrapeo de la búsqueda {busqueda.id_busqueda} del usuario {self.usuario.id_telegram} finalizado." )
def guardarBusqueda(self, id_telegram, update, context): gestorBBDD = GestorBBDD() try: exclusiones = ExclusionesBusqueda( list(context.user_data["lista_keywords_titulo_excluyentes"]), list(context. user_data["lista_keywords_descripcion_excluyentes"]), list(context. user_data["lista_keywords_descripcion_reincluyentes"]), float(context.user_data["multiplicador_maximo"]), float(context.user_data["multiplicador_minimo"]), float(context.user_data["porcentaje_considerado_chollo"])) busqueda = BusquedaWallapop( id_telegram, None, # Porque la id de búsqueda se asigna dentro de insertar búsqueda. exclusiones, str(context.user_data["keywords"]), bool(context.user_data["enviar_mensaje_auto"]), bool(context.user_data["comparar_automaticamente"]), float(context.user_data["precio_min"]), float(context.user_data["precio_max"]), int(context.user_data["radio_km"]), ) gestorBBDD.insertarBusqueda(busqueda) update.message.reply_text("¡Búsqueda guardada!") print(f"[TELEGRAM] Usuario {id_telegram} registra búsqueda: ") print( f"[TELEGRAM] {gestorBBDD.recuperarBusqueda(gestorBBDD.getMaxIdBusqueda())}" ) self.limpiarBusqueda(context) except: update.message.reply_text( "No se ha podido crear la búsqueda. ¿Seguro que has introducido bien los parámetros? Recuerda que los porcentajes se deben poner con un punto, por ej. 0.4." ) self.limpiarBusqueda(context)
def confirmar_borrar_cuenta(self, update, context): parametro = update.message.text.lower() gestorBBDD = GestorBBDD() id_telegram = update.message.from_user.id if (parametro == "si"): # Primero borro búsquedas y articulos contenidos busquedas = gestorBBDD.recuperarBusquedasUsuario(id_telegram) for busqueda in busquedas: gestorBBDD.borrarBusqueda(busqueda.id_busqueda) # Después, borro al usuario gestorBBDD.borrarUsuario(id_telegram) self.limpiar_datos(context) update.message.reply_text(f"Cuenta borrada.") print( f"[TELEGRAM] Usuario {id_telegram} borra su cuenta y búsquedas asociadas. " ) return ConversationHandler.END else: update.message.reply_text("Borrado de cuenta cancelado. ") return ConversationHandler.END
def borrar_busqueda_uno(self, update, context): # Extraigo el nº de búsqueda a borrar numero_busqueda_a_borrar = int(update.message.text.split(" ")[-1]) id_telegram = update.message.from_user.id gestor = GestorBBDD() try: busqueda = gestor.recuperarBusquedasUsuario(id_telegram)[numero_busqueda_a_borrar-1] id_busqueda = busqueda.id_busqueda if(gestor.existeBusqueda(id_busqueda)): gestor.borrarBusqueda(id_busqueda) print(f"[TELEGRAM] Búsqueda {id_busqueda} del usuario {id_telegram} borrada. ") update.message.reply_text(f"¡Busqueda '{busqueda.keywords}' borrada!") return ConversationHandler.END else: update.message.reply_text(f"Error, búsqueda no encontrada en la base de datos. ") return ConversationHandler.END except: update.message.reply_text(f"Error, búsqueda no encontrada en la base de datos. ") return ConversationHandler.END
def scrapeoInicial(self, busqueda): gestorBBDD = GestorBBDD() articulos = self.recuperarArticulosWallapop(busqueda) for articulo in articulos: if (not (articulo.estaExcluido(busqueda))): gestorBBDD.insertarArticulo(articulo)
def recoge_codigo_postal_probar_credenciales(self, update, context): codigo_postal = update.message.text id_telegram = update.message.from_user.id correcto = False print(f"[TELEGRAM] Usuario {id_telegram} mete codigo postal: {codigo_postal}.") try: ccaa = int(codigo_postal[:2]) if(ccaa in range(1,53) and len(codigo_postal) == 5): correcto = True except: pass if(not(correcto)): update.message.reply_text("Código postal incorrecto. Registro cancelado. ") return ConversationHandler.END else: context.user_data["codigo_postal"] = codigo_postal # Si introduce cuenta de wp, pruebo credenciales. if(context.user_data["tiene_cuenta"]): texto = "Código postal guardado. Vamos a probar tu cuenta. Esto puede durar unos segundos..." update.message.reply_text(texto) usuario = Usuario(update.message.from_user.id, context.user_data["email"], context.user_data["pass_wallapop"], context.user_data["codigo_postal"], context.user_data["mensaje_wallapop"]) bot = TestCredenciales(usuario, ejecucion_en_background=True) if(bot.probarCredenciales()): # Registro al usuario en la BBDD gestorBBDD = GestorBBDD() gestorBBDD.insertarUsuario(usuario) # Muestro datos guardados. texto = f"""Credenciales correctos. Cuenta guardada: - Email: {context.user_data["email"]} - Password: {context.user_data["pass_wallapop"]} - Mensaje automático: {context.user_data["mensaje_wallapop"]} - Código postal: {context.user_data["codigo_postal"]} """ update.message.reply_text(texto) # Logueo id_telegram = update.message.from_user.id if(gestorBBDD.existeUsuario(usuario.id_telegram)): print(f"[TELEGRAM] Usuario {id_telegram} registrado con éxito.") else: update.message.reply_text("Credenciales erróneos. Registro cancelado y datos borrados. ") self.limpiar_datos(context) # Si no tiene cuenta else: # Solo le inserto en la bbdd usuario = Usuario(update.message.from_user.id, None, None, context.user_data["codigo_postal"], None) gestorBBDD = GestorBBDD() gestorBBDD.insertarUsuario(usuario) update.message.reply_text("Registrado como usuario sin cuenta en la BBDD.") print(f"[TELEGRAM] Usuario {id_telegram} registrado como usuario sin cuenta con éxito.") return ConversationHandler.END