├── MVC Python ├── model.py ├── cotroller.py └── main.py ├── Monitoreo_red.py ├── packet_callback_wireshark.py ├── websockets.py ├── ExtractTextFromImage.py ├── GenerationQrCode.py ├── ScapyAllNetwork.py ├── API.py ├── SendWhatsapp.py ├── GeneratePassword.py ├── MySql-Connection ├── TkinterBasic.py ├── Discover-Host.py ├── PasswordWithToken.py ├── ProcessCPU ├── Translate.py ├── speech_recognition.py ├── Decode_QR_code.py ├── Tkinter-Print-HelloWorld.py ├── SQLITE ├── OpenIA.py ├── ArbolDecision-Suma.py ├── hash_sha256.py ├── Image-Cv2 ├── BinarySearch.py ├── ModelMachineLearningSum.py ├── WebSocket ├── chat_client.py └── chat_server.py ├── Remove-Background-IMG.py ├── BruteForceDecrypt.py ├── GetTextWeb.py ├── JSON-to-CSV.py ├── TextInPDF.py ├── comprimir_datos.py ├── crud.py ├── Scan-IP-MAC.py ├── Nmap_Scanner.py ├── ExtractTextInPDF.py ├── CursesTimes.py ├── FAT32-to-NTFS.py ├── face_recognition.py ├── DecisionTreeClassifier-About-Iris.py ├── FelizAnioNuevo2024 ├── Barcode.py ├── API-Consumption-JSON.py ├── firebase_notification.py ├── JWT-Datetime.py ├── MP4ConvertToMp3.py ├── API-HTTPS-SelfSigned.py ├── ExampleJSONforInsertDate.py ├── extractImageBackground.py ├── CanvaPDF ├── Request-scanner.py ├── SendMail.py ├── Puertos.py ├── WebSocket-Simple-ASYNC.py ├── Canva.py ├── SendingMail.py ├── Introduce-raddit-with-pika.py ├── keycloak_base_url.py ├── ReportDate-with-CSV-to-PDF.py ├── Tkinter-SearchPokemon.py ├── ChatBot.py ├── nfc.py ├── GeneratePDFwithText.py ├── SMTP-PY-GOOGLE.py ├── check_existing_mail.py ├── DataFrame-Query.py ├── Request-h1-p-web.py ├── CRUD-MongoDB ├── VerifiedPassword.py ├── API-ServiceQueue.py ├── Array.py ├── Caesar encryption.py ├── download-yt-audio-mp3-mp4.py ├── CRUD-MySql.py ├── CRUD-List.py ├── SearchText.py ├── JSON-to-PDF.py ├── Pika-Queue-API.py ├── Complex Calculator.py ├── Token Simulacion.py ├── Session-flask-login-basic.py ├── dijkstra-redis.py ├── A*Search.py ├── POO-CRUD.py ├── escanear_vulnerabilidades.py ├── API-RestFull.py ├── CRUD-Array.py ├── README.md ├── CRUD-POO-MongoDB.py ├── AlgoritmoGenetico.py ├── FLASK-API-JWT.py ├── OAuth2-google.py ├── CRUD-PostgreSQL.py ├── GameSnake.pt ├── API'REST-JSON-Flask.py ├── verifySecurePassword.py ├── POO-CRUD-Mongo.py ├── POO-NoSQL.py ├── Ahorcado.py ├── AlgoritmodeRegresionLogistica.ipynb ├── Introduce-Mininet-SDN.py ├── LICENSE └── PatiñoAngel_RedNeuronal (1).ipynb /MVC Python/model.py: -------------------------------------------------------------------------------- 1 | class TaskModel: 2 | def __init__(self): 3 | self.tasks = [] 4 | 5 | def add_task(self, task): 6 | self.tasks.append(task) 7 | 8 | def get_tasks(self): 9 | return self.tasks 10 | -------------------------------------------------------------------------------- /Monitoreo_red.py: -------------------------------------------------------------------------------- 1 | from scapy.all import sniff 2 | 3 | def packet_callback(packet): 4 | print(packet.summary()) 5 | 6 | # Captura paquetes en la interfaz especificada 7 | sniff(iface="Wi-Fi", prn=packet_callback, store=0) # Este es de mi adaptador Wifi 8 | -------------------------------------------------------------------------------- /packet_callback_wireshark.py: -------------------------------------------------------------------------------- 1 | from scapy.all import * 2 | 3 | def packet_callback(packet): 4 | if IP in packet: 5 | src_ip = packet[IP].src 6 | dst_ip = packet[IP].dst 7 | print(f"Source IP: {src_ip} --> Destination IP: {dst_ip}") 8 | 9 | # Filtra paquetes IPv4 10 | sniff(prn=packet_callback, filter="ip", store=0) 11 | -------------------------------------------------------------------------------- /websockets.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import websockets 3 | 4 | async def echo(websocket, path): 5 | async for message in websocket: 6 | await websocket.send(message) 7 | 8 | start_server = websockets.serve(echo, "localhost", 8765) 9 | 10 | asyncio.get_event_loop().run_until_complete(start_server) 11 | asyncio.get_event_loop().run_forever() 12 | -------------------------------------------------------------------------------- /ExtractTextFromImage.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | import pytesseract 3 | 4 | # Abre la imagen utilizando PIL (Python Imaging Library) 5 | imagen = Image.open('imagen.png') 6 | 7 | # Utiliza pytesseract para extraer el texto de la imagen 8 | texto_extraido = pytesseract.image_to_string(imagen) 9 | 10 | # Imprime el texto extraído 11 | print(texto_extraido) 12 | -------------------------------------------------------------------------------- /GenerationQrCode.py: -------------------------------------------------------------------------------- 1 | import qrcode 2 | 3 | data = "www.anyel.top" # 4 | qr = qrcode.QRCode( 5 | version=1, 6 | error_correction=qrcode.constants.ERROR_CORRECT_L, 7 | box_size=10, 8 | border=4, 9 | ) 10 | 11 | qr.add_data(data) 12 | qr.make(fit=True) 13 | 14 | img = qr.make_image(fill_color="blue", back_color="white") 15 | 16 | img.save("Anyel.png") 17 | -------------------------------------------------------------------------------- /ScapyAllNetwork.py: -------------------------------------------------------------------------------- 1 | from scapy.all import sniff, IP 2 | 3 | def packet_callback(packet): 4 | if IP in packet: 5 | src_ip = packet[IP].src 6 | dst_ip = packet[IP].dst 7 | protocol = packet[IP].proto 8 | 9 | print(f"Source IP: {src_ip}, Destination IP: {dst_ip}, Protocol: {protocol}") 10 | 11 | # Sniff all network traffic 12 | sniff(prn=packet_callback, store=0) 13 | -------------------------------------------------------------------------------- /MVC Python/cotroller.py: -------------------------------------------------------------------------------- 1 | from model import TaskModel 2 | from view import TaskView 3 | 4 | class TaskController: 5 | def __init__(self): 6 | self.model = TaskModel() 7 | self.view = TaskView() 8 | 9 | def add_task(self, task): 10 | self.model.add_task(task) 11 | 12 | def show_tasks(self): 13 | tasks = self.model.get_tasks() 14 | self.view.show_tasks(tasks) 15 | -------------------------------------------------------------------------------- /API.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify 2 | 3 | # Crea una instancia de la aplicación Flask 4 | app = Flask(__name__) 5 | 6 | # Define una ruta que responde a solicitudes GET 7 | @app.route('/saludo', methods=['GET']) 8 | def saludar(): 9 | mensaje = {'mensaje': '¡Hola, mundo! Esta es mi primera API en Python.'} 10 | return jsonify(mensaje) 11 | 12 | # Ejecuta la aplicación en el puerto 5000 13 | if __name__ == '__main__': 14 | app.run(debug=True) 15 | -------------------------------------------------------------------------------- /SendWhatsapp.py: -------------------------------------------------------------------------------- 1 | import pywhatkit as kit 2 | 3 | # Número de teléfono (debe incluir el código de país, por ejemplo, +1 para Estados Unidos) 4 | numero_destino = "+1234567890" 5 | 6 | # Mensaje a enviar 7 | mensaje = "Hola, este es un mensaje desde Python." 8 | 9 | # Hora en formato de 24 horas (por ejemplo, 15:30 para las 3:30 PM) 10 | hora_envio = 15 11 | minuto_envio = 30 12 | 13 | # Enviar el mensaje 14 | kit.sendwhatmsg(numero_destino, mensaje, hora_envio, minuto_envio) 15 | -------------------------------------------------------------------------------- /GeneratePassword.py: -------------------------------------------------------------------------------- 1 | import random 2 | import string 3 | 4 | def generar_contraseña(longitud): 5 | caracteres = string.ascii_letters + string.digits + string.punctuation 6 | contraseña = ''.join(random.choice(caracteres) for _ in range(longitud)) 7 | return contraseña 8 | 9 | if __name__ == "__main__": 10 | longitud = int(input("Ingresa la longitud de la contraseña: ")) 11 | contraseña_generada = generar_contraseña(longitud) 12 | print("Contraseña generada:", contraseña_generada) 13 | -------------------------------------------------------------------------------- /MySql-Connection: -------------------------------------------------------------------------------- 1 | import mysql.connector 2 | 3 | # Configura los parámetros de la conexión a la base de datos 4 | conexion = mysql.connector.connect( 5 | host="tu_host", 6 | user="tu_usuario", 7 | password="tu_contraseña", 8 | database="tu_base_de_datos" 9 | ) 10 | 11 | # Comprueba si la conexión se realizó con éxito 12 | if conexion.is_connected(): 13 | print("Conexión exitosa a la base de datos") 14 | else: 15 | print("Error en la conexión") 16 | 17 | # Cierra la conexión cuando hayas terminado 18 | conexion.close() 19 | -------------------------------------------------------------------------------- /TkinterBasic.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | # Función para imprimir "Hola Mundo" en la consola 4 | def imprimir_hola_mundo(): 5 | print("Hola Mundo") 6 | 7 | # Crear la ventana principal 8 | ventana = tk.Tk() 9 | ventana.title("Mi Aplicación") 10 | 11 | # Crear un botón que llama a la función imprimir_hola_mundo cuando se hace clic 12 | boton_hola = tk.Button(ventana, text="Imprimir Hola Mundo", command=imprimir_hola_mundo) 13 | boton_hola.pack() 14 | 15 | # Ejecutar el bucle principal de la interfaz gráfica 16 | ventana.mainloop() 17 | -------------------------------------------------------------------------------- /Discover-Host.py: -------------------------------------------------------------------------------- 1 | import nmap 2 | 3 | def discover_hosts(ip_range): 4 | nm = nmap.PortScanner() 5 | nm.scan(hosts=ip_range, arguments='-sn') 6 | 7 | hosts_list = [] 8 | for host in nm.all_hosts(): 9 | hosts_list.append(host) 10 | return hosts_list 11 | 12 | def main(): 13 | ip_range = input("Ingrese el rango de IP a escanear (Ejemplo: 192.168.1.0/24): ") 14 | hosts = discover_hosts(ip_range) 15 | 16 | print("Hosts descubiertos:") 17 | for host in hosts: 18 | print(host) 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /PasswordWithToken.py: -------------------------------------------------------------------------------- 1 | import secrets 2 | 3 | def generar_contrasena_con_token(longitud=12, token='MiTokenSecreto'): 4 | # Genera una cadena aleatoria de longitud especificada 5 | cadena_aleatoria = secrets.token_hex(longitud // 2) 6 | 7 | # Combina la cadena aleatoria con el token 8 | contrasena_con_token = f'{cadena_aleatoria}{token}' 9 | 10 | return contrasena_con_token 11 | 12 | # Ejemplo de uso con una longitud de 16 caracteres y un token personalizado 13 | contrasena_generada = generar_contrasena_con_token(longitud=16, token='MiTokenSecreto') 14 | print(f'Contraseña generada: {contrasena_generada}') 15 | -------------------------------------------------------------------------------- /ProcessCPU: -------------------------------------------------------------------------------- 1 | import psutil 2 | 3 | def listar_procesos(): 4 | # Obtener una lista de todos los procesos en ejecución 5 | procesos = psutil.process_iter() 6 | 7 | # Iterar sobre la lista de procesos y mostrar sus nombres 8 | for proceso in procesos: 9 | try: 10 | # Obtener el nombre del proceso 11 | nombre = proceso.name() 12 | 13 | # Imprimir el nombre del proceso 14 | print(f"Nombre del proceso: {nombre}") 15 | except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): 16 | pass 17 | listar_procesos() 18 | -------------------------------------------------------------------------------- /Translate.py: -------------------------------------------------------------------------------- 1 | from translate import Translator 2 | 3 | def traducir_texto(texto, idioma_origen, idioma_destino): 4 | try: 5 | translator = Translator(from_lang=idioma_origen, to_lang=idioma_destino) 6 | traduccion = translator.translate(texto) 7 | return traduccion 8 | except Exception as e: 9 | return str(e) 10 | 11 | # Ejemplo de uso 12 | texto_a_traducir = "Hola, ¿cómo estás?" 13 | idioma_origen = "es" 14 | idioma_destino = "en" 15 | 16 | traduccion = traducir_texto(texto_a_traducir, idioma_origen, idioma_destino) 17 | print("Texto original:", texto_a_traducir) 18 | print("Traducción:", traduccion) 19 | -------------------------------------------------------------------------------- /speech_recognition.py: -------------------------------------------------------------------------------- 1 | import speech_recognition as sr 2 | 3 | # Inicializa el reconocedor 4 | recognizer = sr.Recognizer() 5 | 6 | # Captura audio del micrófono 7 | with sr.Microphone() as source: 8 | print("Habla algo...") 9 | audio = recognizer.listen(source) 10 | 11 | # Intenta reconocer el audio 12 | try: 13 | # Reconoce el audio usando Google Web Speech API 14 | texto = recognizer.recognize_google(audio, language="es-ES") 15 | print(f"Texto reconocido: {texto}") 16 | except sr.UnknownValueError: 17 | print("No se pudo entender el audio") 18 | except sr.RequestError as e: 19 | print(f"Error en la solicitud: {e}") 20 | -------------------------------------------------------------------------------- /Decode_QR_code.py: -------------------------------------------------------------------------------- 1 | import qrcode 2 | from pyzbar.pyzbar import decode 3 | from PIL import Image 4 | 5 | # Decode a QR code from an image 6 | def decode_qr_code(image_path): 7 | # Open the image containing the QR code 8 | img = Image.open(image_path) 9 | 10 | # Decode the QR code 11 | decoded_objects = decode(img) 12 | 13 | if decoded_objects: 14 | # Display the decoded information 15 | for obj in decoded_objects: 16 | print(f"Type: {obj.type}") 17 | print(f"Content: {obj.data.decode('utf-8')}") 18 | 19 | # Call the function with the path to the QR code image 20 | decode_qr_code('image_path.png') 21 | -------------------------------------------------------------------------------- /Tkinter-Print-HelloWorld.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | 3 | def mostrar_hola_mundo(): 4 | etiqueta.config(text="¡Hola Mundo!") 5 | 6 | # Crear la ventana 7 | ventana = tk.Tk() 8 | ventana.title("Hola Mundo GUI") 9 | 10 | # Crear una etiqueta 11 | etiqueta = tk.Label(ventana, text="Presiona el botón para saludar") 12 | 13 | # Crear un botón que llama a la función mostrar_hola_mundo al hacer clic 14 | boton_saludar = tk.Button(ventana, text="Saludar", command=mostrar_hola_mundo) 15 | 16 | # Colocar la etiqueta y el botón en la ventana 17 | etiqueta.pack(pady=10) 18 | boton_saludar.pack(pady=10) 19 | 20 | # Iniciar el bucle principal 21 | ventana.mainloop() 22 | -------------------------------------------------------------------------------- /SQLITE: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | # Conectar a la base de datos (creará el archivo si no existe) 4 | conexion = sqlite3.connect('mi_base_de_datos.db') 5 | 6 | # Crear un cursor para ejecutar comandos SQL 7 | cursor = conexion.cursor() 8 | 9 | # Definir el comando SQL para crear la tabla 10 | comando_sql = ''' 11 | CREATE TABLE IF NOT EXISTS usuarios ( 12 | id INTEGER PRIMARY KEY, 13 | nombre TEXT, 14 | edad INTEGER 15 | ) 16 | ''' 17 | 18 | # Ejecutar el comando SQL para crear la tabla 19 | cursor.execute(comando_sql) 20 | 21 | # Guardar los cambios y cerrar la conexión 22 | conexion.commit() 23 | conexion.close() 24 | 25 | print("Tabla creada exitosamente.") 26 | -------------------------------------------------------------------------------- /OpenIA.py: -------------------------------------------------------------------------------- 1 | import openai 2 | 3 | # Configura tu clave de API de OpenAI 4 | openai.api_key = 'HJJEYU3232WEWEYUGDS67WETEREDFSGDCUYGD84GFYUEWDVSEXGD' #Utiliza tu clave real de la API 5 | 6 | def generar_descripcion_psicologia_color(color): 7 | prompt = f"Describe la psicología del color {color}." 8 | response = openai.Completion.create( 9 | engine="text-davinci-003", 10 | prompt=prompt, 11 | temperature=0.5, 12 | max_tokens=100 13 | ) 14 | return response.choices[0].text.strip() 15 | 16 | # Ejemplo de uso 17 | color = "rojo" 18 | descripcion = generar_descripcion_psicologia_color(color) 19 | print(f"Descripción de la psicología del color {color}:") 20 | print(descripcion) 21 | -------------------------------------------------------------------------------- /ArbolDecision-Suma.py: -------------------------------------------------------------------------------- 1 | from sklearn.tree import DecisionTreeRegressor 2 | import random 3 | 4 | # Generar 20 ejemplos aleatorios para aprender a sumar 5 | X_train = [[random.randint(1, 100), random.randint(1, 100)] for _ in range(10000)] 6 | y_train = [sum(numbers) for numbers in X_train] 7 | 8 | # Crear el modelo de árbol de decisiones 9 | model = DecisionTreeRegressor() 10 | 11 | # Entrenar el modelo 12 | model.fit(X_train, y_train) 13 | 14 | # Datos de prueba 15 | X_test = [[5, 4], [6, 8], [4, 6], [5, 6]] 16 | # Realizar predicciones 17 | predictions = model.predict(X_test) 18 | 19 | print("Predicciones:") 20 | for i in range(len(X_test)): 21 | print(f"{X_test[i][0]} + {X_test[i][1]} = {round(predictions[i])}") 22 | -------------------------------------------------------------------------------- /hash_sha256.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | def calcular_hash_sha256(mensaje): 4 | # Crear un objeto hashlib de tipo SHA-256 5 | sha256_hash = hashlib.sha256() 6 | 7 | # Convertir el mensaje a bytes antes de alimentarlo al objeto hash 8 | mensaje_bytes = mensaje.encode('utf-8') 9 | 10 | # Alimentar el mensaje en el objeto hash 11 | sha256_hash.update(mensaje_bytes) 12 | 13 | # Obtener el hash en formato hexadecimal 14 | hash_resultado = sha256_hash.hexdigest() 15 | 16 | return hash_resultado 17 | 18 | mensaje = "Hola, esto es un mensaje de prueba." 19 | hash_resultado = calcular_hash_sha256(mensaje) 20 | print("Mensaje:", mensaje) 21 | print("Hash SHA-256:", hash_resultado) 22 | -------------------------------------------------------------------------------- /Image-Cv2: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | # Inicializar la cámara 4 | cap = cv2.VideoCapture(0) # El argumento 0 representa la cámara predeterminada 5 | 6 | # Verificar si la cámara se abrió correctamente 7 | if not cap.isOpened(): 8 | print("No se pudo abrir la cámara") 9 | else: 10 | # Capturar un cuadro (imagen) de la cámara 11 | ret, frame = cap.read() 12 | 13 | if ret: 14 | # Guardar la imagen como un archivo JPG 15 | cv2.imwrite("imagen.jpg", frame) 16 | 17 | # Liberar la cámara 18 | cap.release() 19 | 20 | print("Imagen guardada como 'imagen.jpg'") 21 | else: 22 | print("No se pudo capturar una imagen") 23 | 24 | # Cerrar la ventana de la cámara 25 | cv2.destroyAllWindows() 26 | -------------------------------------------------------------------------------- /BinarySearch.py: -------------------------------------------------------------------------------- 1 | def binary_search(arr, target): 2 | left, right = 0, len(arr) - 1 3 | 4 | while left <= right: 5 | mid = left + (right - left) // 2 6 | 7 | if arr[mid] == target: 8 | return mid 9 | elif arr[mid] < target: 10 | left = mid + 1 11 | else: 12 | right = mid - 1 13 | 14 | return -1 # Si el elemento no se encuentra en el arreglo 15 | 16 | # Ejemplo de uso 17 | arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] 18 | target = 11 19 | result = binary_search(arr, target) 20 | 21 | if result != -1: 22 | print(f"El elemento {target} fue encontrado en la posición {result}.") 23 | else: 24 | print(f"El elemento {target} no fue encontrado en el arreglo.") 25 | -------------------------------------------------------------------------------- /MVC Python/main.py: -------------------------------------------------------------------------------- 1 | from controller import TaskController 2 | 3 | def main(): 4 | controller = TaskController() 5 | 6 | while True: 7 | print("\n1. Agregar tarea") 8 | print("2. Mostrar tareas") 9 | print("3. Salir") 10 | choice = input("Selecciona una opción: ") 11 | 12 | if choice == "1": 13 | task = input("Ingrese la tarea: ") 14 | controller.add_task(task) 15 | print("Tarea agregada.") 16 | elif choice == "2": 17 | controller.show_tasks() 18 | elif choice == "3": 19 | break 20 | else: 21 | print("Opción no válida. Intente nuevamente.") 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /ModelMachineLearningSum.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | 4 | # Generar datos de entrenamiento 5 | num_samples = 1000 6 | x_train = np.random.rand(num_samples, 2) # Dos números aleatorios 7 | y_train = np.sum(x_train, axis=1) # Suma de los dos números 8 | 9 | # Construir el modelo 10 | model = tf.keras.Sequential([ 11 | tf.keras.layers.Input(shape=(2,)), 12 | tf.keras.layers.Dense(1) 13 | ]) 14 | 15 | # Compilar el modelo 16 | model.compile(optimizer='adam', loss='mse') 17 | 18 | # Entrenar el modelo 19 | model.fit(x_train, y_train, epochs=50, batch_size=32) 20 | 21 | # Evaluar el modelo 22 | x_test = np.array([[0.3, 0.7], [0.5, 0.9]]) 23 | predictions = model.predict(x_test) 24 | print("Predicciones:", predictions.flatten()) 25 | -------------------------------------------------------------------------------- /WebSocket/chat_client.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import websockets 3 | 4 | async def receive_messages(): 5 | async with websockets.connect("ws://localhost:8765") as websocket: 6 | while True: 7 | # Espera y muestra mensajes recibidos 8 | message = await websocket.recv() 9 | print(f"Mensaje recibido: {message}") 10 | 11 | async def send_messages(): 12 | async with websockets.connect("ws://localhost:8765") as websocket: 13 | while True: 14 | # Lee el mensaje desde la entrada del usuario y lo envía 15 | message = input("Ingrese un mensaje: ") 16 | await websocket.send(message) 17 | 18 | # Ejecuta el cliente 19 | asyncio.gather(receive_messages(), send_messages()) 20 | -------------------------------------------------------------------------------- /Remove-Background-IMG.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | # Cargar la imagen 4 | image = cv2.imread('imagen.jpg') 5 | 6 | # Convertir la imagen a escala de grises 7 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 8 | 9 | # Crear un objeto BackgroundSubtractor 10 | bg_subtractor = cv2.createBackgroundSubtractorMOG2() 11 | 12 | # Aplicar la segmentación de fondo 13 | foreground_mask = bg_subtractor.apply(gray) 14 | 15 | # Invertir la máscara para obtener el primer plano 16 | foreground = cv2.bitwise_and(image, image, mask=foreground_mask) 17 | background = cv2.bitwise_and(image, image, mask=~foreground_mask) 18 | 19 | # Mostrar resultados 20 | cv2.imshow('Original', image) 21 | cv2.imshow('Foreground', foreground) 22 | cv2.imshow('Background', background) 23 | cv2.waitKey(0) 24 | cv2.destroyAllWindows() 25 | -------------------------------------------------------------------------------- /BruteForceDecrypt.py: -------------------------------------------------------------------------------- 1 | # Encrypted message 2 | encrypted_message = "Xlmw irgvctxih jmrhxl, csy xlmw mw qiwweki mr xli viwmhirx. Liv svok?" 3 | 4 | # Function for brute force decryption 5 | def brute_force_decrypt(ciphertext): 6 | for key in range(1, 26): 7 | decrypted_message = "" 8 | for char in ciphertext: 9 | if char.isalpha(): 10 | # Perform reverse shift 11 | new_char = chr(((ord(char) - key - 65) % 26) + 65) if char.isupper() else chr(((ord(char) - key - 97) % 26) + 97) 12 | decrypted_message += new_char 13 | else: 14 | decrypted_message += char 15 | print(f"Key {key}: {decrypted_message}") 16 | 17 | # Decrypt the message using brute force 18 | brute_force_decrypt(encrypted_message) 19 | -------------------------------------------------------------------------------- /GetTextWeb.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | 4 | # URL de la página que deseas analizar 5 | url = 'https://www.ejemplo.com' 6 | 7 | # Realiza una solicitud HTTP para obtener el contenido de la página 8 | response = requests.get(url) 9 | 10 | # Verifica si la solicitud fue exitosa (código de respuesta 200) 11 | if response.status_code == 200: 12 | # Parsea el contenido HTML de la página 13 | soup = BeautifulSoup(response.text, 'html.parser') 14 | 15 | # Encuentra y extrae todo el texto de la página 16 | texto_pagina = soup.get_text() 17 | 18 | # Imprime el texto 19 | print(texto_pagina) 20 | else: 21 | # Si la solicitud no fue exitosa, muestra un mensaje de error 22 | print(f'Error al obtener la página. Código de respuesta: {response.status_code}') 23 | -------------------------------------------------------------------------------- /JSON-to-CSV.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import json 3 | 4 | # Tu JSON de ejemplo (puedes reemplazarlo con tu propio JSON) 5 | json_data = '{"nombre": "Juan", "edad": 25, "ciudad": "Ejemplo"}' 6 | 7 | # Parsear el JSON 8 | data = json.loads(json_data) 9 | 10 | # Especificar el nombre del archivo CSV de salida 11 | csv_filename = 'salida.csv' 12 | 13 | # Abrir el archivo CSV en modo de escritura 14 | with open(csv_filename, 'w', newline='') as csvfile: 15 | # Crear un objeto escritor CSV 16 | csv_writer = csv.writer(csvfile) 17 | 18 | # Escribir las claves (encabezados) como la primera fila en el CSV 19 | csv_writer.writerow(data.keys()) 20 | 21 | # Escribir los valores como filas en el CSV 22 | csv_writer.writerow(data.values()) 23 | 24 | print(f'Se ha convertido el JSON a CSV en {csv_filename}') 25 | -------------------------------------------------------------------------------- /TextInPDF.py: -------------------------------------------------------------------------------- 1 | from reportlab.lib.pagesizes import letter 2 | from reportlab.pdfgen import canvas 3 | 4 | # Nombre del archivo de salida PDF 5 | nombre_archivo = "mi_documento.pdf" 6 | 7 | # Texto que deseas incluir en el PDF 8 | texto = """ 9 | Este es un ejemplo de cómo exportar texto a un archivo PDF utilizando la librería reportlab en Python. 10 | Puedes personalizar este texto según tus necesidades. 11 | """ 12 | 13 | # Crear un archivo PDF y configurar el tamaño de la página 14 | c = canvas.Canvas(nombre_archivo, pagesize=letter) 15 | 16 | # Definir la fuente y el tamaño del texto 17 | c.setFont("Helvetica", 12) 18 | 19 | # Insertar el texto en el PDF 20 | c.drawString(100, 700, texto) 21 | 22 | # Guardar el PDF 23 | c.save() 24 | 25 | print(f"El archivo PDF '{nombre_archivo}' ha sido creado con éxito.") 26 | -------------------------------------------------------------------------------- /comprimir_datos.py: -------------------------------------------------------------------------------- 1 | import zlib 2 | import base64 3 | 4 | def comprimir_dato(dato): 5 | dato_comprimido = zlib.compress(dato.encode('utf-8')) 6 | return base64.b64encode(dato_comprimido).decode('utf-8') 7 | 8 | def descomprimir_dato(dato_comprimido): 9 | dato_base64 = base64.b64decode(dato_comprimido.encode('utf-8')) 10 | dato_descomprimido = zlib.decompress(dato_base64).decode('utf-8') 11 | return dato_descomprimido 12 | 13 | # Ejemplo de uso 14 | dato_original = "Datos de ejemplo que queremos comprimir y luego descomprimir" 15 | 16 | # Comprimir los datos 17 | dato_comprimido = comprimir_dato(dato_original) 18 | print("Dato comprimido:", dato_comprimido) 19 | 20 | # Descomprimir los datos 21 | dato_descomprimido = descomprimir_dato(dato_comprimido) 22 | print("Dato descomprimido:", dato_descomprimido) 23 | -------------------------------------------------------------------------------- /WebSocket/chat_server.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import websockets 3 | 4 | async def handle_client(websocket, path): 5 | # Espera y procesa los mensajes del cliente 6 | async for message in websocket: 7 | # Reenvía el mensaje a todos los clientes conectados 8 | await asyncio.gather( 9 | *[client.send(message) for client in clients if client != websocket] 10 | ) 11 | 12 | # Lista para almacenar clientes conectados 13 | clients = set() 14 | 15 | async def main(): 16 | server = await websockets.serve(handle_client, "localhost", 8765) 17 | print(f"Servidor de chat iniciado en {server.sockets[0].getsockname()}") 18 | 19 | # Bucle principal 20 | async with server: 21 | await server.serve_forever() 22 | 23 | # Ejecuta el servidor 24 | asyncio.run(main()) 25 | -------------------------------------------------------------------------------- /crud.py: -------------------------------------------------------------------------------- 1 | import pyodbc # pip install pyodbc 2 | 3 | try: 4 | conn = pyodbc.connect('Driver={SQL Server};' 5 | 'Server=localhost;' 6 | 'Database=Estudiante;' 7 | 'UID: Hola;' 8 | 'PWD: Hola;' 9 | 'Trusted_Connection=yes;') 10 | print("Conexion exitosa") 11 | except Exception as e: 12 | print("Ocurrio un error al conectar a SQL Server: ", e) 13 | 14 | # Create 15 | def crear (id, nombre, apellido): 16 | cursor = conn.cursor() 17 | cursor.execute(' INSERT INTO ESTUDIANTE VALUES (?,?,?)', (id, nombre, apellido)) 18 | cursor.commit() 19 | print("Estudiante creado con exito") 20 | cursor.close() 21 | return 'Estudiante creado con exito HTML' 22 | -------------------------------------------------------------------------------- /Scan-IP-MAC.py: -------------------------------------------------------------------------------- 1 | import scapy.all as scapy 2 | 3 | def scan(ip): 4 | arp_request = scapy.ARP(pdst=ip) 5 | broadcast = scapy.Ether(dst="ff:ff:ff:ff:ff:ff") 6 | arp_request_broadcast = broadcast/arp_request 7 | answered_list = scapy.srp(arp_request_broadcast, timeout=1, verbose=False)[0] 8 | 9 | clients_list = [] 10 | for element in answered_list: 11 | client_dict = {"ip": element[1].psrc, "mac": element[1].hwsrc} 12 | clients_list.append(client_dict) 13 | return clients_list 14 | 15 | def print_result(results_list): 16 | print("IP Address\t\tMAC Address") 17 | print("----------------------------------------------------") 18 | for client in results_list: 19 | print(client["ip"] + "\t\t" + client["mac"]) 20 | 21 | scan_result = scan("192.168.1.1/24") 22 | print_result(scan_result) 23 | -------------------------------------------------------------------------------- /Nmap_Scanner.py: -------------------------------------------------------------------------------- 1 | import nmap 2 | 3 | def escanear_vulnerabilidades(ip): 4 | scanner = nmap.PortScanner() 5 | scanner.scan(ip, arguments='-p 1-65535 -T4 -A -v') 6 | 7 | for host in scanner.all_hosts(): 8 | print('Host : %s (%s)' % (host, scanner[host].hostname())) 9 | print('State : %s' % scanner[host].state()) 10 | 11 | for proto in scanner[host].all_protocols(): 12 | print('Protocolo : %s' % proto) 13 | 14 | lport = scanner[host][proto].keys() 15 | for port in lport: 16 | print('Puerto : %s\tEstado : %s' % (port, scanner[host][proto][port]['state'])) 17 | print('Servicio : %s' % scanner[host][proto][port]['name']) 18 | print('') 19 | 20 | if __name__ == '__main__': 21 | ip_a_escanear = '192.168.1.1' 22 | escanear_vulnerabilidades(ip_a_escanear) 23 | -------------------------------------------------------------------------------- /ExtractTextInPDF.py: -------------------------------------------------------------------------------- 1 | import PyPDF2 2 | 3 | def extraer_texto_pdf(archivo_pdf): 4 | texto = "" 5 | 6 | # Abre el archivo PDF en modo de lectura binaria 7 | with open(archivo_pdf, "rb") as pdf_file: 8 | # Crea un objeto PDFReader 9 | pdf_reader = PyPDF2.PdfFileReader(pdf_file) 10 | 11 | # Itera a través de cada página del PDF 12 | for pagina in range(pdf_reader.numPages): 13 | # Extrae el texto de la página actual 14 | pagina_actual = pdf_reader.getPage(pagina) 15 | texto += pagina_actual.extractText() 16 | 17 | return texto 18 | 19 | # Nombre del archivo PDF que deseas procesar 20 | archivo_pdf = "ejemplo.pdf" 21 | 22 | # Llama a la función para extraer el texto 23 | texto_extraido = extraer_texto_pdf(archivo_pdf) 24 | 25 | # Imprime el texto extraído 26 | print(texto_extraido) 27 | -------------------------------------------------------------------------------- /CursesTimes.py: -------------------------------------------------------------------------------- 1 | import curses 2 | import time 3 | 4 | def main(stdscr): 5 | # Configurar curses 6 | curses.curs_set(0) 7 | stdscr.nodelay(1) 8 | stdscr.timeout(1000) # Actualizar cada segundo 9 | 10 | while True: 11 | stdscr.clear() 12 | height, width = stdscr.getmaxyx() 13 | 14 | # Obtener la hora actual 15 | current_time = time.strftime("%H:%M:%S") 16 | 17 | # Centrar el reloj en la pantalla 18 | x = width // 2 - len(current_time) // 2 19 | y = height // 2 20 | 21 | # Imprimir la hora actual en el centro de la pantalla 22 | stdscr.addstr(y, x, current_time) 23 | 24 | # Refrescar la pantalla 25 | stdscr.refresh() 26 | 27 | # Salir si se presiona 'q' 28 | key = stdscr.getch() 29 | if key == ord('q'): 30 | break 31 | 32 | if __name__ == "__main__": 33 | curses.wrapper(main) 34 | -------------------------------------------------------------------------------- /FAT32-to-NTFS.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import os 3 | 4 | def change_filesystem_to_ntfs(drive_letter): 5 | # Obtener la ruta de la unidad 6 | drive_path = f"{drive_letter}:\\" 7 | 8 | # Comprobar si la unidad existe 9 | if not os.path.exists(drive_path): 10 | print(f"La unidad {drive_letter} no está disponible.") 11 | return 12 | 13 | # Cambiar el sistema de archivos de FAT32 a NTFS 14 | result = ctypes.windll.shell32.SHFormatDrive(0, 1, drive_letter + ":", 0) 15 | if result != 0: 16 | print("¡El cambio de sistema de archivos ha sido exitoso!") 17 | else: 18 | print("¡Ha ocurrido un error al intentar cambiar el sistema de archivos!") 19 | 20 | # Cambiar la letra de unidad según tu flash 21 | drive_letter = "F" # Cambia esto a la letra de unidad de tu flash 22 | 23 | # Llamar a la función para cambiar el sistema de archivos 24 | change_filesystem_to_ntfs(drive_letter) 25 | -------------------------------------------------------------------------------- /face_recognition.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import face_recognition 3 | 4 | def reconocer_caras(imagen_path): 5 | # Cargar la imagen 6 | imagen = face_recognition.load_image_file(imagen_path) 7 | 8 | # Encontrar todas las caras en la imagen 9 | ubicaciones = face_recognition.face_locations(imagen) 10 | 11 | # Dibujar un rectángulo alrededor de cada cara encontrada 12 | for ubicacion in ubicaciones: 13 | top, right, bottom, left = ubicacion 14 | cv2.rectangle(imagen, (left, top), (right, bottom), (0, 255, 0), 2) 15 | 16 | # Mostrar la imagen con las caras resaltadas 17 | cv2.imshow('Caras Reconocidas', imagen) 18 | cv2.waitKey(0) 19 | cv2.destroyAllWindows() 20 | 21 | if __name__ == "__main__": 22 | # Ruta de la imagen que deseas analizar 23 | ruta_imagen = 'ruta/a/tu/imagen.jpg' 24 | 25 | # Llamar a la función para reconocer caras 26 | reconocer_caras(ruta_imagen) 27 | -------------------------------------------------------------------------------- /DecisionTreeClassifier-About-Iris.py: -------------------------------------------------------------------------------- 1 | # Importar las bibliotecas necesarias 2 | from sklearn.datasets import load_iris 3 | from sklearn.tree import DecisionTreeClassifier 4 | from sklearn.model_selection import train_test_split 5 | from sklearn.metrics import accuracy_score 6 | 7 | # Cargar el conjunto de datos de Iris 8 | iris = load_iris() 9 | X = iris.data 10 | y = iris.target 11 | 12 | # Dividir los datos en conjuntos de entrenamiento y prueba 13 | X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) 14 | 15 | # Crear un clasificador de árbol de decisión 16 | clf = DecisionTreeClassifier() 17 | 18 | # Entrenar el clasificador 19 | clf.fit(X_train, y_train) 20 | 21 | # Hacer predicciones en el conjunto de prueba 22 | y_pred = clf.predict(X_test) 23 | 24 | # Calcular la precisión del clasificador 25 | accuracy = accuracy_score(y_test, y_pred) 26 | print("Precisión del clasificador:", accuracy) 27 | -------------------------------------------------------------------------------- /FelizAnioNuevo2024: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | def mensaje_epico(): 4 | print("****************************************************") 5 | print("* *") 6 | print("* ¡Feliz Año Nuevo! by Anyel EC *") 7 | print("* Que este año esté lleno de alegría y éxitos. *") 8 | print("* Que cada día sea una nueva aventura. *") 9 | print("* ¡Que todos tus sueños se hagan realidad! *") 10 | print("* Que la felicidad te acompañe siempre. *") 11 | print("* ¡Que tengas un año épico y lleno de logros! *") 12 | print("* *") 13 | print("****************************************************") 14 | 15 | def cuenta_regresiva(): 16 | for i in range(10, 0, -1): 17 | print(f"¡Cuenta regresiva: {i}!") 18 | time.sleep(1) 19 | 20 | 21 | cuenta_regresiva() 22 | mensaje_epico() 23 | -------------------------------------------------------------------------------- /Barcode.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | from pyzbar.pyzbar import decode 3 | 4 | # Inicializa la cámara 5 | cap = cv2.VideoCapture(0) 6 | 7 | while True: 8 | # Captura un fotograma de la cámara 9 | ret, frame = cap.read() 10 | 11 | # Decodifica los códigos de barras en el fotograma 12 | decoded_objects = decode(frame) 13 | 14 | for obj in decoded_objects: 15 | barcode_data = obj.data.decode('utf-8') 16 | barcode_type = obj.type 17 | 18 | # Muestra los resultados en la pantalla 19 | print(f'Tipo de código de barras: {barcode_type}') 20 | print(f'Dato del código de barras: {barcode_data}') 21 | 22 | # Muestra el fotograma en una ventana 23 | cv2.imshow('Codigo de Barras Scanner', frame) 24 | 25 | # Sale del bucle si se presiona la tecla 'q' 26 | if cv2.waitKey(1) & 0xFF == ord('q'): 27 | break 28 | 29 | # Libera la cámara y cierra la ventana 30 | cap.release() 31 | cv2.destroyAllWindows() 32 | -------------------------------------------------------------------------------- /API-Consumption-JSON.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | def consumir_servicio(url): 4 | try: 5 | # Realizar la solicitud HTTP 6 | response = requests.get(url) 7 | 8 | # Verificar si la solicitud fue exitosa (código de estado 200) 9 | if response.status_code == 200: 10 | # Analizar el JSON de la respuesta 11 | data = response.json() 12 | 13 | # Procesar los datos según tus necesidades 14 | for key, value in data.items(): 15 | print(f"{key}: {value}") 16 | 17 | else: 18 | print(f"Error en la solicitud. Código de estado: {response.status_code}") 19 | 20 | except Exception as e: 21 | print(f"Error en la solicitud: {e}") 22 | 23 | # URL del servicio que devuelve un archivo JSON (reemplázala con la URL correcta) 24 | url_servicio = "https://ejemplo.com/servicio_json" 25 | 26 | # Llamar a la función de consumo del servicio 27 | consumir_servicio(url_servicio) 28 | -------------------------------------------------------------------------------- /firebase_notification.py: -------------------------------------------------------------------------------- 1 | import firebase_admin 2 | from firebase_admin import credentials, messaging 3 | 4 | # Inicializa la app de Firebase con el archivo JSON de tu cuenta de servicio 5 | cred = credentials.Certificate("ruta/al/archivo/serviceAccountKey.json") 6 | firebase_admin.initialize_app(cred) 7 | 8 | def enviar_notificacion(token, titulo, cuerpo): 9 | # Construye el mensaje 10 | message = messaging.Message( 11 | notification=messaging.Notification( 12 | title=titulo, 13 | body=cuerpo, 14 | ), 15 | token=token, 16 | ) 17 | 18 | # Envía el mensaje 19 | response = messaging.send(message) 20 | print('Mensaje enviado:', response) 21 | 22 | # Reemplaza estos valores con los datos de tu cliente 23 | token = 'DEVICE_REGISTRATION_TOKEN' 24 | titulo = 'Título de la Notificación' 25 | cuerpo = 'Este es el cuerpo de la notificación' 26 | 27 | # Envía la notificación 28 | enviar_notificacion(token, titulo, cuerpo) 29 | -------------------------------------------------------------------------------- /JWT-Datetime.py: -------------------------------------------------------------------------------- 1 | import jwt 2 | from datetime import datetime, timedelta 3 | 4 | # Definir la clave secreta para firmar el token 5 | SECRET_KEY = 'tu_clave_secreta' 6 | 7 | # Función para generar un token JWT con una duración de 10 minutos 8 | def generar_token(): 9 | # Definir la fecha y hora de emisión del token 10 | ahora = datetime.utcnow() 11 | # Definir la fecha y hora de expiración del token (10 minutos después) 12 | expiracion = ahora + timedelta(minutes=10) 13 | 14 | # Crear los datos a incluir en el token (puedes agregar más datos si lo necesitas) 15 | datos_token = { 16 | 'usuario_id': 1234567890, 17 | 'exp': expiracion 18 | } 19 | 20 | # Generar el token JWT usando PyJWT 21 | token = jwt.encode(datos_token, SECRET_KEY, algorithm='HS256') 22 | 23 | return token 24 | 25 | # Ejemplo de cómo usar la función para generar un token 26 | token_generado = generar_token() 27 | print("Token JWT generado:", token_generado) 28 | -------------------------------------------------------------------------------- /MP4ConvertToMp3.py: -------------------------------------------------------------------------------- 1 | from pytube import YouTube 2 | from moviepy.editor import VideoFileClip 3 | 4 | def descargar_youtube_a_mp3(url, nombre_archivo): 5 | # Descargar el video de YouTube 6 | yt = YouTube(url) 7 | video_stream = yt.streams.filter(only_audio=True).first() 8 | video_stream.download(filename=nombre_archivo + ".mp4") 9 | 10 | # Convertir el video a formato MP3 11 | video_clip = VideoFileClip(nombre_archivo + ".mp4") 12 | video_clip.audio.write_audiofile(nombre_archivo + ".mp3") 13 | 14 | # Eliminar el archivo de video original 15 | video_clip.close() 16 | os.remove(nombre_archivo + ".mp4") 17 | 18 | if __name__ == "__main__": 19 | import os 20 | 21 | # Ingresa la URL del video de YouTube y el nombre deseado para el archivo de salida 22 | url_youtube = "https://www.youtube.com/watch?v=example" 23 | nombre_salida = "cancion" 24 | 25 | # Llamada a la función para descargar y convertir 26 | descargar_youtube_a_mp3(url_youtube, nombre_salida) 27 | -------------------------------------------------------------------------------- /API-HTTPS-SelfSigned.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, jsonify, request 2 | import ssl 3 | 4 | app = Flask(__name__) 5 | 6 | @app.route('/api/resource', methods=['GET']) 7 | def get_resource(): 8 | # Implementa la lógica para obtener un recurso 9 | return jsonify({'message': 'GET request to the resource'}) 10 | 11 | @app.route('/api/resource', methods=['POST']) 12 | def create_resource(): 13 | # Implementa la lógica para crear un recurso 14 | data = request.json 15 | # Procesa los datos recibidos en la solicitud POST 16 | return jsonify({'message': 'POST request to the resource', 'data': data}) 17 | 18 | # Configura el contexto SSL con los certificados generados 19 | if __name__ == '__main__': 20 | context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) 21 | context.load_cert_chain('cert.pem', 'key.pem') # se debe generar el certificado y la llave privada con este comando 22 | # openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365 23 | app.run(debug=True, ssl_context=context) 24 | -------------------------------------------------------------------------------- /ExampleJSONforInsertDate.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | def insert_book(): 4 | books = [] # List to store books 5 | 6 | # Ask the user for book details 7 | title = input("Enter the book title: ") 8 | author = input("Enter the author's name: ") 9 | year = input("Enter the publication year: ") 10 | 11 | # Create a dictionary with the book's information 12 | book = { 13 | 'Title': title, 14 | 'Author': author, 15 | 'Year': year 16 | } 17 | 18 | try: 19 | with open('books.json', 'r') as file: 20 | books = json.load(file) # Load existing data from the JSON file if any 21 | except FileNotFoundError: 22 | pass # If the file doesn't exist, create a new one 23 | 24 | books.append(book) # Add the new book to the list 25 | 26 | # Save the updated list to the JSON file 27 | with open('books.json', 'w') as file: 28 | json.dump(books, file, indent=4) 29 | 30 | print("Book inserted successfully.") 31 | 32 | if __name__ == "__main__": 33 | insert_book() 34 | -------------------------------------------------------------------------------- /extractImageBackground.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # Cargar la imagen 5 | image = cv2.imread('imagen.jpg') 6 | 7 | # Convertir la imagen a escala de grises 8 | gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 9 | 10 | # Aplicar umbralización para separar el objeto del fondo 11 | _, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY) 12 | 13 | # Encontrar contornos en la imagen umbralizada 14 | contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 15 | 16 | # Crear una máscara en blanco del mismo tamaño que la imagen 17 | mask = np.zeros_like(image) 18 | 19 | # Dibujar los contornos en la máscara 20 | cv2.drawContours(mask, contours, -1, (255, 255, 255), thickness=cv2.FILLED) 21 | 22 | # Extraer el objeto en primer plano usando la máscara 23 | foreground = cv2.bitwise_and(image, mask) 24 | 25 | # Mostrar la imagen original, la máscara y el objeto en primer plano 26 | cv2.imshow('Original', image) 27 | cv2.imshow('Mask', mask) 28 | cv2.imshow('Foreground', foreground) 29 | cv2.waitKey(0) 30 | cv2.destroyAllWindows() 31 | -------------------------------------------------------------------------------- /CanvaPDF: -------------------------------------------------------------------------------- 1 | from reportlab.pdfgen import canvas 2 | 3 | # Solicitar datos de una persona 4 | nombre = input("Ingrese el nombre: ") 5 | edad = input("Ingrese la edad: ") 6 | ciudad = input("Ingrese la ciudad: ") 7 | 8 | # Imprimir los datos ingresados 9 | print("\nDatos de la persona:") 10 | print("Nombre:", nombre) 11 | print("Edad:", edad) 12 | print("Ciudad:", ciudad) 13 | 14 | # Generar PDF con los datos 15 | pdf_filename = "datos_persona.pdf" 16 | 17 | # Crear el documento PDF 18 | pdf_canvas = canvas.Canvas(pdf_filename) 19 | 20 | # Configurar el formato y la posición para mostrar los datos 21 | text_object = pdf_canvas.beginText(100, 700) 22 | text_object.setFont("Helvetica", 12) 23 | text_object.textLine("Datos de la persona:") 24 | text_object.textLine("Nombre: " + nombre) 25 | text_object.textLine("Edad: " + edad) 26 | text_object.textLine("Ciudad: " + ciudad) 27 | 28 | # Agregar los datos al PDF 29 | pdf_canvas.drawText(text_object) 30 | 31 | # Guardar el PDF 32 | pdf_canvas.save() 33 | 34 | print(f"\nLos datos se han guardado en el archivo PDF: {pdf_filename}") 35 | -------------------------------------------------------------------------------- /Request-scanner.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | def scan_website(url): 4 | api_key = 'tu_api_key_aqui' # Reemplaza 'tu_api_key_aqui' con tu API key de SecurityTrails 5 | endpoint = f'https://api.securitytrails.com/v1/website/{url}/security' 6 | 7 | headers = { 8 | 'APIKEY': api_key 9 | } 10 | 11 | try: 12 | response = requests.get(endpoint, headers=headers) 13 | data = response.json() 14 | 15 | if 'status' in data and data['status'] == 'error': 16 | print(f"Error: {data['message']}") 17 | else: 18 | vulnerabilities = data['data']['vulnerabilities'] 19 | print("Vulnerabilidades encontradas:") 20 | for vuln in vulnerabilities: 21 | print(f"- {vuln['title']}: {vuln['description']}") 22 | print(f" Solución: {vuln['solution']}") 23 | 24 | except Exception as e: 25 | print(f"Error: {str(e)}") 26 | 27 | if __name__ == "__main__": 28 | url = input("Ingrese la URL del sitio web que desea escanear: ") 29 | scan_website(url) 30 | -------------------------------------------------------------------------------- /SendMail.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | from email.mime.text import MIMEText 3 | from email.mime.multipart import MIMEMultipart 4 | 5 | # Configuración de los datos del remitente 6 | remitente = 'tu_correo@gmail.com' 7 | password = 'tu_contraseña' 8 | 9 | # Datos del destinatario 10 | destinatario = 'appatino@espe.edu.ec' 11 | 12 | # Crear el objeto del correo 13 | mensaje = MIMEMultipart() 14 | mensaje['From'] = remitente 15 | mensaje['To'] = destinatario 16 | mensaje['Subject'] = 'Asunto del correo' 17 | 18 | # Cuerpo del correo 19 | cuerpo = 'Hola, este es un correo de prueba enviado desde Python.' 20 | mensaje.attach(MIMEText(cuerpo, 'plain')) 21 | 22 | # Conectar al servidor de correo de Gmail 23 | server = smtplib.SMTP('smtp.gmail.com', 587) 24 | server.starttls() 25 | 26 | # Iniciar sesión en el servidor 27 | server.login(remitente, password) 28 | 29 | # Enviar el correo 30 | texto_del_correo = mensaje.as_string() 31 | server.sendmail(remitente, destinatario, texto_del_correo) 32 | 33 | # Cerrar la conexión 34 | server.quit() 35 | 36 | print("Correo enviado exitosamente.") 37 | -------------------------------------------------------------------------------- /Puertos.py: -------------------------------------------------------------------------------- 1 | import socket 2 | 3 | def scan_ports(target_host, start_port, end_port): 4 | open_ports = [] 5 | for port in range(start_port, end_port + 1): 6 | print(f"Escaneando puerto {port}...") 7 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 8 | sock.settimeout(1) # Timeout para la conexión, en segundos 9 | result = sock.connect_ex((target_host, port)) 10 | if result == 0: 11 | open_ports.append(port) 12 | sock.close() 13 | return open_ports 14 | 15 | 16 | target_host = input("Ingresa la dirección IP o el nombre de dominio del computador a escanear: ") 17 | start_port = int(input("Ingresa el número del primer puerto del rango a escanear: ")) 18 | end_port = int(input("Ingresa el número del último puerto del rango a escanear: ")) 19 | 20 | open_ports = scan_ports(target_host, start_port, end_port) 21 | 22 | if open_ports: 23 | print(f"Los siguientes puertos están abiertos en {target_host}:") 24 | print(open_ports) 25 | else: 26 | print(f"No se encontraron puertos abiertos en {target_host}.") 27 | -------------------------------------------------------------------------------- /WebSocket-Simple-ASYNC.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import websockets 3 | 4 | # Lista para almacenar las conexiones de los clientes 5 | clientes = set() 6 | 7 | async def manejar_mensaje(mensaje, cliente): 8 | # Enviar el mensaje a todos los clientes conectados 9 | for cliente_conectado in clientes: 10 | if cliente_conectado != cliente: 11 | await cliente_conectado.send(mensaje) 12 | 13 | async def servidor(websocket, path): 14 | # Agregar nuevo cliente a la lista 15 | clientes.add(websocket) 16 | try: 17 | # Bucle para manejar los mensajes del cliente 18 | async for mensaje in websocket: 19 | # Procesar el mensaje recibido del cliente 20 | await manejar_mensaje(mensaje, websocket) 21 | finally: 22 | # Eliminar cliente cuando se desconecte 23 | clientes.remove(websocket) 24 | 25 | # Iniciar el servidor WebSocket en el puerto 8765 26 | start_server = websockets.serve(servidor, "localhost", 8765) 27 | 28 | # Correr el servidor 29 | asyncio.get_event_loop().run_until_complete(start_server) 30 | asyncio.get_event_loop().run_forever() 31 | -------------------------------------------------------------------------------- /Canva.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | # Cargamos la imagen 5 | imagen = cv2.imread('anyel-ec.jpg') 6 | 7 | # Convertimos la imagen a escala de grises 8 | gris = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY) 9 | 10 | # Aplicamos un desenfoque para reducir el ruido 11 | gris = cv2.GaussianBlur(gris, (5, 5), 0) 12 | 13 | # Detectamos los bordes en la imagen 14 | bordes = cv2.Canny(gris, 50, 150, apertureSize=3) 15 | 16 | # Buscamos contornos en la imagen 17 | contornos, _ = cv2.findContours(bordes.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 18 | 19 | # Iteramos a través de los contornos encontrados 20 | for contorno in contornos: 21 | # Aproximamos el contorno a una forma más simple (en este caso, un polígono) 22 | epsilon = 0.04 * cv2.arcLength(contorno, True) 23 | approx = cv2.approxPolyDP(contorno, epsilon, True) 24 | 25 | # Si el polígono tiene 4 vértices, es un cuadrado 26 | if len(approx) == 4: 27 | cv2.drawContours(imagen, [approx], 0, (0, 255, 0), 2) 28 | 29 | # Mostramos la imagen con los cuadrados detectados 30 | cv2.imshow('Imagen con cuadrados', imagen) 31 | cv2.waitKey(0) 32 | cv2.destroyAllWindows() 33 | -------------------------------------------------------------------------------- /SendingMail.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | from email.mime.multipart import MIMEMultipart 3 | from email.mime.text import MIMEText 4 | 5 | # Configuración 6 | smtp_server = 'smtp.example.com' # Cambia esto al servidor SMTP que estés utilizando 7 | smtp_port = 587 # Puerto para conexión TLS (puede variar según el proveedor) 8 | 9 | sender_email = 'tu_correo@example.com' 10 | sender_password = 'tu_contraseña' 11 | receiver_email = 'destinatario@example.com' 12 | 13 | subject = 'Asunto del correo' 14 | message = 'Hola, esto es un ejemplo de correo electrónico enviado desde Python.' 15 | 16 | # Crear objeto de mensaje MIME 17 | msg = MIMEMultipart() 18 | msg['From'] = sender_email 19 | msg['To'] = receiver_email 20 | msg['Subject'] = subject 21 | msg.attach(MIMEText(message, 'plain')) 22 | 23 | # Establecer conexión SMTP 24 | with smtplib.SMTP(smtp_server, smtp_port) as server: 25 | server.starttls() # Iniciar conexión TLS 26 | server.login(sender_email, sender_password) # Iniciar sesión 27 | 28 | # Enviar correo electrónico 29 | server.sendmail(sender_email, receiver_email, msg.as_string()) 30 | 31 | print("Correo electrónico enviado correctamente.") 32 | -------------------------------------------------------------------------------- /Introduce-raddit-with-pika.py: -------------------------------------------------------------------------------- 1 | import pika 2 | 3 | # Establecer conexión con RabbitMQ 4 | connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) 5 | channel = connection.channel() 6 | 7 | # Crear una cola llamada 'hello' 8 | channel.queue_declare(queue='hello') 9 | 10 | # Función para enviar un mensaje a la cola 11 | def send_message(message): 12 | channel.basic_publish(exchange='', 13 | routing_key='hello', 14 | body=message) 15 | print(" [x] Sent '%s'" % message) 16 | 17 | # Función para recibir un mensaje de la cola 18 | def receive_message(): 19 | def callback(ch, method, properties, body): 20 | print(" [x] Received %r" % body) 21 | 22 | channel.basic_consume(queue='hello', 23 | on_message_callback=callback, 24 | auto_ack=True) 25 | 26 | print(' [*] Waiting for messages. To exit press CTRL+C') 27 | channel.start_consuming() 28 | 29 | # Enviar un mensaje a la cola 30 | send_message("Hello, RabbitMQ!") 31 | 32 | # Recibir un mensaje de la cola 33 | receive_message() 34 | 35 | # Cerrar la conexión 36 | connection.close() 37 | -------------------------------------------------------------------------------- /keycloak_base_url.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | # Configuración 4 | keycloak_base_url = 'http://localhost:8080/auth/realms/your_realm' 5 | client_id = 'your_client_id' 6 | client_secret = 'your_client_secret' 7 | username = 'your_username' 8 | password = 'your_password' 9 | 10 | # Obtener el token de acceso utilizando el flujo de contraseña 11 | token_url = f'{keycloak_base_url}/protocol/openid-connect/token' 12 | payload = { 13 | 'grant_type': 'password', 14 | 'client_id': client_id, 15 | 'client_secret': client_secret, 16 | 'username': username, 17 | 'password': password 18 | } 19 | 20 | response = requests.post(token_url, data=payload) 21 | token_data = response.json() 22 | access_token = token_data['access_token'] 23 | 24 | # Hacer una solicitud utilizando el token de acceso 25 | api_url = 'http://your_api_endpoint' 26 | headers = {'Authorization': f'Bearer {access_token}'} 27 | 28 | response = requests.get(api_url, headers=headers) 29 | 30 | # Procesar la respuesta 31 | if response.status_code == 200: 32 | print('Respuesta exitosa:') 33 | print(response.json()) 34 | else: 35 | print('Error al hacer la solicitud:') 36 | print(response.text) 37 | -------------------------------------------------------------------------------- /ReportDate-with-CSV-to-PDF.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | from reportlab.lib.pagesizes import letter 3 | from reportlab.pdfgen import canvas 4 | 5 | def leer_csv(nombre_archivo): 6 | # Leer el archivo CSV y devolver un DataFrame de pandas 7 | return pd.read_csv(nombre_archivo) 8 | 9 | def generar_pdf(datos): 10 | # Configurar el tamaño del PDF 11 | c = canvas.Canvas("datos.pdf", pagesize=letter) 12 | 13 | # Configurar el tamaño de la fuente y el espacio entre líneas 14 | c.setFont("Helvetica", 12) 15 | espacio_linea = 15 16 | 17 | # Iterar sobre los datos y escribirlos en el PDF 18 | for fila, (_, datos_fila) in enumerate(datos.iterrows()): 19 | # Escribir cada campo de la fila en una nueva línea 20 | for columna, valor in datos_fila.iteritems(): 21 | texto = f"{columna}: {valor}" 22 | c.drawString(100, 800 - (espacio_linea * (fila + 1)), texto) 23 | 24 | # Guardar el PDF generado 25 | c.save() 26 | 27 | if __name__ == "__main__": 28 | nombre_archivo = "datos.csv" 29 | 30 | # Leer datos del archivo CSV 31 | datos = leer_csv(nombre_archivo) 32 | 33 | # Generar PDF con los datos 34 | generar_pdf(datos) 35 | -------------------------------------------------------------------------------- /Tkinter-SearchPokemon.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tkinter import messagebox 3 | 4 | # Arreglo de Pokémon 5 | pokemons = { 6 | "Bulbasaur": "Planta", 7 | "Charmander": "Fuego", 8 | "Squirtle": "Agua", 9 | "Pikachu": "Eléctrico", 10 | "Jigglypuff": "Normal", 11 | "Eevee": "Normal", 12 | "Snorlax": "Normal", 13 | "Mewtwo": "Psíquico", 14 | "Gengar": "Fantasma", 15 | "Dragonite": "Dragón" 16 | } 17 | 18 | def buscar_pokemon(): 19 | nombre = entry.get() 20 | if nombre in pokemons: 21 | tipo = pokemons[nombre] 22 | messagebox.showinfo("Resultado", f"{nombre} es de tipo {tipo}.") 23 | else: 24 | messagebox.showerror("Error", f"No se encontró el Pokémon {nombre}.") 25 | 26 | # Configuración de la ventana 27 | ventana = tk.Tk() 28 | ventana.title("Buscar Pokémon") 29 | 30 | # Etiqueta y entrada para ingresar el nombre del Pokémon 31 | label = tk.Label(ventana, text="Nombre del Pokémon:") 32 | label.pack(pady=10) 33 | entry = tk.Entry(ventana) 34 | entry.pack() 35 | 36 | # Botón para buscar el Pokémon 37 | boton_buscar = tk.Button(ventana, text="Buscar", command=buscar_pokemon) 38 | boton_buscar.pack(pady=5) 39 | 40 | # Ejecutar la ventana 41 | ventana.mainloop() 42 | -------------------------------------------------------------------------------- /ChatBot.py: -------------------------------------------------------------------------------- 1 | import nltk 2 | import random 3 | from nltk.chat.util import Chat, reflections 4 | 5 | nltk.download('punkt') 6 | 7 | # Pares de patrones y respuestas 8 | pares = [ 9 | ["¿Cómo está el clima hoy?", ["El clima es soleado y cálido."]], 10 | ["¿Cuál es la temperatura actual?", ["La temperatura actual es de 25 grados Celsius."]], 11 | ["¿Qué tiempo hará mañana?", ["Mañana se espera un clima soleado con una temperatura máxima de 28 grados."]], 12 | ["Hola", ["¡Hola!", "Hola, ¿en qué puedo ayudarte?"]], 13 | ["Adiós", ["Hasta luego.", "Adiós."]], 14 | ] 15 | 16 | # Crea un chatbot 17 | chatbot = Chat(pares, reflections) 18 | 19 | # Función principal para interactuar con el chatbot 20 | def chat(): 21 | print("Hola, soy un chatbot de clima hecho por Anyel EC . Puedes preguntarme sobre el clima o simplemente saludar.") 22 | print("Escribe 'salir' para finalizar la conversación.") 23 | while True: 24 | user_input = input("Tú: ") 25 | if user_input.lower() == 'salir': 26 | print("Chatbot: Hasta luego.") 27 | break 28 | else: 29 | response = chatbot.respond(user_input) 30 | print("Chatbot:", response) 31 | 32 | if __name__ == "__main__": 33 | chat() 34 | -------------------------------------------------------------------------------- /nfc.py: -------------------------------------------------------------------------------- 1 | import nfc 2 | 3 | def leer_nfc(): 4 | clf = nfc.ContactlessFrontend('usb') 5 | print("Acerca la etiqueta NFC al lector...") 6 | try: 7 | while True: 8 | tag = clf.connect(rdwr={'on-connect': lambda tag: False}) 9 | if tag: 10 | print("ID de la etiqueta NFC:", tag.identifier.hex()) 11 | break 12 | finally: 13 | clf.close() 14 | 15 | def escribir_nfc(data): 16 | clf = nfc.ContactlessFrontend('usb') 17 | print("Acerca la etiqueta NFC al lector para escribir...") 18 | try: 19 | while True: 20 | tag = clf.connect(rdwr={'on-connect': lambda tag: False}) 21 | if tag: 22 | tag.write(data) 23 | print("Datos escritos en la etiqueta NFC.") 24 | break 25 | finally: 26 | clf.close() 27 | 28 | # Ejemplo de uso 29 | if __name__ == "__main__": 30 | opcion = input("¿Qué deseas hacer? (leer/escribir): ").lower() 31 | if opcion == "leer": 32 | leer_nfc() 33 | elif opcion == "escribir": 34 | data = input("Introduce los datos que deseas escribir en la etiqueta NFC: ") 35 | escribir_nfc(data.encode()) 36 | else: 37 | print("Opción no válida.") 38 | -------------------------------------------------------------------------------- /GeneratePDFwithText.py: -------------------------------------------------------------------------------- 1 | from reportlab.pdfgen import canvas 2 | 3 | def generate_pdf(text, file_name='output.pdf'): 4 | # Create a PDF canvas 5 | pdf = canvas.Canvas(file_name) 6 | 7 | # Set page size 8 | page_width, page_height = 400, 600 # You can adjust these values as needed 9 | pdf.setPageSize((page_width, page_height)) 10 | 11 | # Coordinates to start writing text 12 | x, y = 50, page_height - 100 13 | 14 | # Maximum characters per line 15 | max_characters_per_line = 50 16 | 17 | # Split the text into lines 18 | lines = [text[i:i + max_characters_per_line] for i in range(0, len(text), max_characters_per_line)] 19 | 20 | # Write each line to the PDF canvas 21 | for line in lines: 22 | pdf.drawString(x, y, line) 23 | y -= 20 # Adjust the line spacing as needed 24 | 25 | # Save the PDF 26 | pdf.save() 27 | 28 | print(f"PDF file created: {file_name}") 29 | 30 | if __name__ == "__main__": 31 | # You can change the text as per your preference 32 | text_for_pdf = """ 33 | This is an example text for the PDF. 34 | You can provide your own text when running the script. 35 | """ 36 | 37 | # Generate the PDF with the provided text 38 | generate_pdf(text_for_pdf) 39 | -------------------------------------------------------------------------------- /SMTP-PY-GOOGLE.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | from email.mime.multipart import MIMEMultipart 3 | from email.mime.text import MIMEText 4 | 5 | # Configura los detalles del servidor SMTP de Google 6 | smtp_server = 'smtp.gmail.com' 7 | smtp_port = 587 # El puerto de TLS para Gmail 8 | 9 | # Tu dirección de correo electrónico y contraseña 10 | email_address = 'tucorreo@gmail.com' 11 | password = 'tucontraseña' 12 | 13 | # La dirección de correo electrónico del destinatario 14 | recipient_email = 'destinatario@example.com' 15 | 16 | # Crea el mensaje 17 | message = MIMEMultipart() 18 | message['From'] = email_address 19 | message['To'] = recipient_email 20 | message['Subject'] = '¡Hola desde Python!' 21 | 22 | # El cuerpo del correo electrónico 23 | body = 'Este es un correo electrónico enviado desde Python usando SMTP.' 24 | message.attach(MIMEText(body, 'plain')) 25 | 26 | # Inicia una conexión SMTP con el servidor de Google 27 | with smtplib.SMTP(smtp_server, smtp_port) as server: 28 | # Inicia el modo TLS (Transport Layer Security) 29 | server.starttls() 30 | 31 | # Inicia sesión en tu cuenta de Google 32 | server.login(email_address, password) 33 | 34 | # Envía el mensaje 35 | server.send_message(message) 36 | 37 | print('Correo electrónico enviado exitosamente.') 38 | -------------------------------------------------------------------------------- /check_existing_mail.py: -------------------------------------------------------------------------------- 1 | import smtplib 2 | 3 | def verificar_correo_existente(correo): 4 | try: 5 | dominio = correo.split('@')[1] 6 | # Conectarse al servidor SMTP del dominio 7 | servidor_smtp = smtplib.SMTP(dominio) 8 | servidor_smtp.set_debuglevel(0) 9 | # Intente enviar un correo al usuario sin enviar realmente el correo 10 | servidor_smtp.verify(correo) 11 | servidor_smtp.quit() 12 | return True 13 | except smtplib.SMTPConnectError: 14 | return False 15 | except smtplib.SMTPHeloError: 16 | return False 17 | except smtplib.SMTPAuthenticationError: 18 | return False 19 | except smtplib.SMTPSenderRefused: 20 | return False 21 | except smtplib.SMTPRecipientsRefused: 22 | return False 23 | except smtplib.SMTPDataError: 24 | return False 25 | except Exception as e: 26 | print("Error inesperado:", str(e)) 27 | return False 28 | 29 | # Ejemplo de uso 30 | correo = "correo_que_existe@gmail.com" 31 | if verificar_correo_existente(correo): 32 | print(f"{correo} es una dirección de correo electrónico válida y existe en el servidor.") 33 | else: 34 | print(f"{correo} no es una dirección de correo electrónico válida o no existe en el servidor.") 35 | -------------------------------------------------------------------------------- /DataFrame-Query.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | # Crear un DataFrame de empleados 4 | data = { 5 | 'Nombre': ['Juan', 'Ana', 'Luis', 'María', 'Pedro'], 6 | 'Edad': [30, 28, 35, 25, 32], 7 | 'Salario': [50000, 48000, 60000, 45000, 55000], 8 | 'Departamento': ['Ventas', 'Recursos Humanos', 'Ventas', 'Tecnología', 'Tecnología'] 9 | } 10 | 11 | df_empleados = pd.DataFrame(data) 12 | 13 | # Operaciones en el DataFrame 14 | 15 | # 1. Calcular el salario promedio de los empleados: 16 | salario_promedio = df_empleados['Salario'].mean() 17 | print(f"Salario promedio: ${salario_promedio:.2f}") 18 | 19 | # 2. Encontrar al empleado más joven: 20 | empleado_mas_joven = df_empleados[df_empleados['Edad'] == df_empleados['Edad'].min()] 21 | print("Empleado más joven:") 22 | print(empleado_mas_joven) 23 | 24 | # Consultas en el DataFrame 25 | 26 | # 1. Filtrar empleados del departamento de Tecnología: 27 | empleados_tecnologia = df_empleados[df_empleados['Departamento'] == 'Tecnología'] 28 | print("Empleados del departamento de Tecnología:") 29 | print(empleados_tecnologia) 30 | 31 | # 2. Ordenar los empleados por salario de forma descendente: 32 | empleados_ordenados = df_empleados.sort_values(by='Salario', ascending=False) 33 | print("Empleados ordenados por salario descendente:") 34 | print(empleados_ordenados) 35 | -------------------------------------------------------------------------------- /Request-h1-p-web.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | 4 | # URL de la página web a analizar 5 | url = 'https://example.com' 6 | 7 | # Realizar la solicitud GET para obtener el contenido de la página 8 | response = requests.get(url) 9 | 10 | # Verificar que la solicitud fue exitosa (código de estado 200) 11 | if response.status_code == 200: 12 | # Parsear el contenido HTML utilizando BeautifulSoup 13 | soup = BeautifulSoup(response.content, 'html.parser') 14 | 15 | # Encontrar todos los elementos

y

16 | h1_elements = soup.find_all('h1') 17 | p_elements = soup.find_all('p') 18 | 19 | # Filtrar los elementos relacionados con temas de seguridad 20 | security_related_h1 = [h1.text.strip() for h1 in h1_elements if 'seguridad' in h1.text.lower()] 21 | security_related_p = [p.text.strip() for p in p_elements if 'seguridad' in p.text.lower()] 22 | 23 | # Imprimir los resultados 24 | print("Elementos

relacionados con seguridad:") 25 | for title in security_related_h1: 26 | print("- ", title) 27 | 28 | print("\nElementos

relacionados con seguridad:") 29 | for paragraph in security_related_p: 30 | print("- ", paragraph) 31 | else: 32 | print("Error al realizar la solicitud GET:", response.status_code) 33 | -------------------------------------------------------------------------------- /CRUD-MongoDB: -------------------------------------------------------------------------------- 1 | import pymongo 2 | 3 | # Connect to the database 4 | client = pymongo.MongoClient("mongodb://localhost:27017/") 5 | database = client["my_database"] 6 | collection = database["my_collection"] 7 | 8 | def create_document(data): 9 | # Create a document in the collection 10 | result = collection.insert_one(data) 11 | print(f"Document created with ID: {result.inserted_id}") 12 | 13 | def read_documents(): 14 | # Read all documents in the collection 15 | cursor = collection.find() 16 | for document in cursor: 17 | print(document) 18 | 19 | def update_document(query, new_data): 20 | # Update a document in the collection 21 | result = collection.update_one(query, {"$set": new_data}) 22 | print(f"{result.modified_count} document(s) updated") 23 | 24 | def delete_document(query): 25 | # Delete a document from the collection 26 | result = collection.delete_one(query) 27 | print(f"{result.deleted_count} document(s) deleted") 28 | 29 | if __name__ == "__main__": 30 | # Examples of usage 31 | create_document({"name": "Example", "age": 25, "city": "Example City"}) 32 | read_documents() 33 | 34 | update_document({"name": "Example"}, {"$set": {"age": 26}}) 35 | read_documents() 36 | 37 | delete_document({"name": "Example"}) 38 | read_documents() 39 | -------------------------------------------------------------------------------- /VerifiedPassword.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def verificar_contraseña(password): 4 | # Verificar que la contraseña tenga al menos 8 caracteres 5 | if len(password) < 8: 6 | return "La contraseña debe tener al menos 8 caracteres." 7 | 8 | # Verificar que la contraseña contenga al menos una letra mayúscula 9 | if not any(c.isupper() for c in password): 10 | return "La contraseña debe contener al menos una letra mayúscula." 11 | 12 | # Verificar que la contraseña contenga al menos una letra minúscula 13 | if not any(c.islower() for c in password): 14 | return "La contraseña debe contener al menos una letra minúscula." 15 | 16 | # Verificar que la contraseña contenga al menos un número 17 | if not any(c.isdigit() for c in password): 18 | return "La contraseña debe contener al menos un número." 19 | 20 | # Verificar que la contraseña contenga al menos un carácter especial 21 | if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password): 22 | return "La contraseña debe contener al menos un carácter especial." 23 | 24 | # La contraseña parece segura 25 | return "La contraseña es segura." 26 | 27 | if __name__ == "__main__": 28 | contraseña = input("Ingrese una contraseña: ") 29 | resultado = verificar_contraseña(contraseña) 30 | print(resultado) 31 | -------------------------------------------------------------------------------- /API-ServiceQueue.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify 2 | import requests 3 | import queue 4 | 5 | app = Flask(__name__) 6 | product_queue = queue.Queue() 7 | 8 | # Ruta para agregar productos al servidor de colas 9 | @app.route('/agregar_producto', methods=['POST']) 10 | def agregar_producto(): 11 | producto = request.json 12 | product_queue.put(producto) 13 | return jsonify({"message": "Producto agregado a la cola"}), 200 14 | 15 | # Ruta para enviar productos a otra API 16 | @app.route('/enviar_productos', methods=['POST']) 17 | def enviar_productos(): 18 | try: 19 | while not product_queue.empty(): 20 | producto = product_queue.get() 21 | # Envía el producto a la otra API en la ruta /ruta/productos 22 | response = requests.post("http://anyel.top/ruta/productos", json=producto) # Cambiar a la ruta del producto de la API 23 | if response.status_code == 200: 24 | print("Producto enviado exitosamente a la otra API:", producto) 25 | else: 26 | print("Error al enviar el producto a la otra API:", producto) 27 | except Exception as e: 28 | print("Error al enviar productos:", e) 29 | return jsonify({"error": str(e)}), 500 30 | 31 | return jsonify({"message": "Productos enviados correctamente"}), 200 32 | 33 | if __name__ == '__main__': 34 | app.run(debug=True) 35 | -------------------------------------------------------------------------------- /Array.py: -------------------------------------------------------------------------------- 1 | # Declaración de un array con valores iniciales 2 | nombres = ["Juan", "María", "Carlos", "Ana"] 3 | 4 | # Acceso a un elemento específico por índice 5 | primer_nombre = nombres[0] 6 | print("Primer nombre:", primer_nombre) 7 | 8 | # Modificación de un elemento 9 | nombres[1] = "Luis" 10 | 11 | # Iteración usando un bucle for 12 | print("Iteración con for:") 13 | for nombre in nombres: 14 | print(nombre) 15 | 16 | # Iteración usando un bucle while 17 | print("Iteración con while:") 18 | i = 0 19 | while i < len(nombres): 20 | print(nombres[i]) 21 | i += 1 22 | 23 | # Añadir un elemento al final del array 24 | nombres.append("Elena") 25 | 26 | # Insertar un elemento en una posición específica 27 | nombres.insert(2, "Pedro") 28 | 29 | # Eliminar un elemento por valor 30 | nombres.remove("Carlos") 31 | 32 | # Eliminar un elemento por índice 33 | del nombres[0] 34 | 35 | # Eliminar y obtener el último elemento 36 | ultimo_nombre = nombres.pop() 37 | print("Último nombre eliminado:", ultimo_nombre) 38 | 39 | # Obtener la longitud del array 40 | cantidad_de_nombres = len(nombres) 41 | print("Cantidad de nombres:", cantidad_de_nombres) 42 | 43 | # Ordenar el array alfabéticamente 44 | nombres.sort() 45 | 46 | # Ordenar el array en orden inverso 47 | nombres.reverse() 48 | 49 | # Buscar un elemento en el array 50 | if "María" in nombres: 51 | print("María está en la lista.") 52 | else: 53 | print("María no está en la lista.") 54 | -------------------------------------------------------------------------------- /Caesar encryption.py: -------------------------------------------------------------------------------- 1 | def encrypt(message, key): 2 | encrypted_message = "" 3 | for char in message: 4 | if char.isalpha(): 5 | shifted = ord(char) + key 6 | if char.islower(): 7 | if shifted > ord('z'): 8 | shifted -= 26 9 | elif char.isupper(): 10 | if shifted > ord('Z'): 11 | shifted -= 26 12 | encrypted_message += chr(shifted) 13 | else: 14 | encrypted_message += char 15 | return encrypted_message 16 | 17 | def decrypt(encrypted_message, key): 18 | return encrypt(encrypted_message, -key) 19 | 20 | def main(): 21 | choice = input("¿Quieres encriptar (E) o desencriptar (D) un mensaje? ").upper() 22 | if choice == "E": 23 | message = input("Ingrese el mensaje a encriptar: ") 24 | key = int(input("Ingrese el valor de la clave: ")) 25 | encrypted_message = encrypt(message, key) 26 | print("Mensaje encriptado:", encrypted_message) 27 | elif choice == "D": 28 | encrypted_message = input("Ingrese el mensaje a desencriptar: ") 29 | key = int(input("Ingrese el valor de la clave: ")) 30 | decrypted_message = decrypt(encrypted_message, key) 31 | print("Mensaje desencriptado:", decrypted_message) 32 | else: 33 | print("Opción no válida. Por favor, elige 'E' o 'D'.") 34 | 35 | if __name__ == "__main__": 36 | main() 37 | -------------------------------------------------------------------------------- /download-yt-audio-mp3-mp4.py: -------------------------------------------------------------------------------- 1 | from pytube import YouTube 2 | from moviepy.editor import VideoFileClip 3 | 4 | def download_video(url): 5 | try: 6 | yt = YouTube(url) 7 | yt.streams.filter(progressive=True, file_extension='mp4').order_by('resolution').desc().first().download() 8 | return True 9 | except Exception as e: 10 | return False 11 | 12 | def download_audio(url): 13 | try: 14 | yt = YouTube(url) 15 | audio_stream = yt.streams.filter(only_audio=True, file_extension="mp4").first() 16 | audio_stream.download(output_path=".", filename="audio") 17 | 18 | # Convertir el archivo de audio de mp4 a mp3 19 | video_clip = VideoFileClip("audio.mp4") 20 | video_clip.audio.write_audiofile("audio.mp3") 21 | video_clip.close() 22 | return True 23 | except Exception as e: 24 | return False 25 | 26 | # Escoger el video y audio a descargar 27 | opcion = int(input('1. Descargar video\n2. Descargar audio\nOpción: ')) 28 | if opcion == 1: 29 | url = input('Enter the video URL: ') 30 | if download_video(url): 31 | print('Video downloaded successfully') 32 | else: 33 | print('Error downloading the video') 34 | elif opcion == 2: 35 | url = input('Enter the audio URL: ') 36 | if download_audio(url): 37 | print('Audio downloaded successfully') 38 | else: 39 | print('Error downloading the audio') 40 | -------------------------------------------------------------------------------- /CRUD-MySql.py: -------------------------------------------------------------------------------- 1 | import mysql.connector 2 | 3 | # Establecer la conexión con la base de datos 4 | conexion = mysql.connector.connect( 5 | host='tu_host', 6 | user='tu_usuario', 7 | password='tu_contraseña', 8 | database='nombre_de_tu_base_de_datos' 9 | ) 10 | 11 | # Crear un cursor para ejecutar consultas 12 | cursor = conexion.cursor() 13 | 14 | # Operación de creación (CREATE) 15 | def insertar_datos(nombre, edad, correo): 16 | consulta = "INSERT INTO tabla (nombre, edad, correo) VALUES (%s, %s, %s)" 17 | datos = (nombre, edad, correo) 18 | cursor.execute(consulta, datos) 19 | conexion.commit() 20 | 21 | # Operación de lectura (READ) 22 | def obtener_datos(): 23 | consulta = "SELECT * FROM tabla" 24 | cursor.execute(consulta) 25 | resultados = cursor.fetchall() 26 | return resultados 27 | 28 | # Operación de actualización (UPDATE) 29 | def actualizar_datos(id, nuevo_nombre, nueva_edad, nuevo_correo): 30 | consulta = "UPDATE tabla SET nombre=%s, edad=%s, correo=%s WHERE id=%s" 31 | datos = (nuevo_nombre, nueva_edad, nuevo_correo, id) 32 | cursor.execute(consulta, datos) 33 | conexion.commit() 34 | 35 | # Operación de eliminación (DELETE) 36 | def eliminar_datos(id): 37 | consulta = "DELETE FROM tabla WHERE id=%s" 38 | datos = (id,) 39 | cursor.execute(consulta, datos) 40 | conexion.commit() 41 | 42 | # Cerrar el cursor y la conexión al terminar 43 | def cerrar_conexion(): 44 | cursor.close() 45 | conexion.close() 46 | -------------------------------------------------------------------------------- /CRUD-List.py: -------------------------------------------------------------------------------- 1 | # Inicializar una lista vacía para almacenar los datos 2 | lista_de_elementos = [] 3 | 4 | # Función para crear un nuevo elemento 5 | def crear_elemento(nombre, edad): 6 | nuevo_elemento = {'nombre': nombre, 'edad': edad} 7 | lista_de_elementos.append(nuevo_elemento) 8 | print(f'Se ha creado un nuevo elemento: {nuevo_elemento}') 9 | 10 | # Función para leer todos los elementos 11 | def leer_elementos(): 12 | for elemento in lista_de_elementos: 13 | print(f'Nombre: {elemento["nombre"]}, Edad: {elemento["edad"]}') 14 | 15 | # Función para actualizar un elemento existente 16 | def actualizar_elemento(nombre, nueva_edad): 17 | for elemento in lista_de_elementos: 18 | if elemento['nombre'] == nombre: 19 | elemento['edad'] = nueva_edad 20 | print(f'Se ha actualizado el elemento: {elemento}') 21 | return 22 | print(f'Elemento con nombre "{nombre}" no encontrado.') 23 | 24 | # Función para eliminar un elemento existente 25 | def eliminar_elemento(nombre): 26 | for elemento in lista_de_elementos: 27 | if elemento['nombre'] == nombre: 28 | lista_de_elementos.remove(elemento) 29 | print(f'Se ha eliminado el elemento: {elemento}') 30 | return 31 | print(f'Elemento con nombre "{nombre}" no encontrado.') 32 | 33 | # Ejemplos de uso 34 | crear_elemento('Alice', 30) 35 | crear_elemento('Bob', 25) 36 | leer_elementos() 37 | actualizar_elemento('Alice', 35) 38 | eliminar_elemento('Bob') 39 | leer_elementos() 40 | -------------------------------------------------------------------------------- /SearchText.py: -------------------------------------------------------------------------------- 1 | import requests 2 | from bs4 import BeautifulSoup 3 | 4 | # URL de la página que deseas analizar 5 | url = 'https://www.ejemplo.com' 6 | 7 | # Lista de palabras clave que deseas buscar 8 | palabras_clave = ["IA", "machine learning", "inteligencia artificial", "algoritmo"] 9 | 10 | # Realiza una solicitud HTTP para obtener el contenido de la página 11 | response = requests.get(url) 12 | 13 | # Verifica si la solicitud fue exitosa (código de respuesta 200) 14 | if response.status_code == 200: 15 | # Parsea el contenido HTML de la página 16 | soup = BeautifulSoup(response.text, 'html.parser') 17 | 18 | # Encuentra y extrae todo el texto de la página 19 | texto_pagina = soup.get_text() 20 | 21 | # Inicializa un contador para cada palabra clave 22 | contador_palabras = {palabra: 0 for palabra in palabras_clave} 23 | 24 | # Convierte el texto de la página en minúsculas para una búsqueda insensible a mayúsculas 25 | texto_pagina = texto_pagina.lower() 26 | 27 | # Itera a través de las palabras clave y cuenta sus ocurrencias 28 | for palabra in palabras_clave: 29 | contador_palabras[palabra] = texto_pagina.count(palabra.lower()) 30 | 31 | # Imprime los resultados 32 | for palabra, contador in contador_palabras.items(): 33 | print(f'La palabra "{palabra}" aparece {contador} veces en la página.') 34 | else: 35 | # Si la solicitud no fue exitosa, muestra un mensaje de error 36 | print(f'Error al obtener la página. Código de respuesta: {response.status_code}') 37 | -------------------------------------------------------------------------------- /JSON-to-PDF.py: -------------------------------------------------------------------------------- 1 | from reportlab.lib import colors 2 | from reportlab.lib.pagesizes import letter 3 | from reportlab.platypus import SimpleDocTemplate, Table, TableStyle 4 | import json 5 | 6 | def json_to_pdf(json_data, pdf_path): 7 | # Abre el archivo JSON y carga los datos 8 | with open(json_data, 'r') as file: 9 | data = json.load(file) 10 | 11 | # Crea el documento PDF 12 | pdf = SimpleDocTemplate(pdf_path, pagesize=letter) 13 | 14 | # Convierte los datos JSON a una lista de listas para la tabla 15 | table_data = [list(data[0].keys())] # Encabezados de la tabla 16 | for item in data: 17 | table_data.append(list(item.values())) 18 | 19 | # Crea la tabla y establece el estilo 20 | table = Table(table_data) 21 | style = TableStyle([('BACKGROUND', (0, 0), (-1, 0), colors.grey), 22 | ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), 23 | ('ALIGN', (0, 0), (-1, -1), 'CENTER'), 24 | ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), 25 | ('BOTTOMPADDING', (0, 0), (-1, 0), 12), 26 | ('BACKGROUND', (0, 1), (-1, -1), colors.beige), 27 | ('GRID', (0, 0), (-1, -1), 1, colors.black)]) 28 | 29 | table.setStyle(style) 30 | 31 | # Agrega la tabla al documento PDF 32 | pdf.build([table]) 33 | 34 | # Ejemplo de uso 35 | json_file_path = 'ejemplo.json' # Reemplaza con la ruta de tu archivo JSON 36 | pdf_output_path = 'output.pdf' # Ruta de salida para el PDF 37 | 38 | json_to_pdf(json_file_path, pdf_output_path) 39 | -------------------------------------------------------------------------------- /Pika-Queue-API.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify 2 | import pika 3 | import threading 4 | 5 | app = Flask(__name__) 6 | 7 | # Conexión con RabbitMQ 8 | connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) 9 | channel = connection.channel() 10 | 11 | # Declaramos la cola 12 | channel.queue_declare(queue='api_queue', durable=True) 13 | 14 | 15 | def process_request(ch, method, properties, body): 16 | print("Received message:", body) 17 | # Simulamos un proceso que toma tiempo 18 | import time 19 | time.sleep(5) 20 | print("Request processed") 21 | ch.basic_ack(delivery_tag=method.delivery_tag) 22 | 23 | 24 | @app.route('/api', methods=['POST']) 25 | def api(): 26 | # Enviamos el mensaje a RabbitMQ 27 | channel.basic_publish(exchange='', 28 | routing_key='api_queue', 29 | body=request.get_data(), 30 | properties=pika.BasicProperties( 31 | delivery_mode=2 # make message persistent 32 | )) 33 | return jsonify({'message': 'Request received and queued'}) 34 | 35 | 36 | def start_consuming(): 37 | channel.basic_qos(prefetch_count=3) # Permitir solo 3 mensajes sin confirmar 38 | channel.basic_consume(queue='api_queue', on_message_callback=process_request) 39 | channel.start_consuming() 40 | 41 | 42 | if __name__ == '__main__': 43 | # Iniciamos un hilo para consumir los mensajes de RabbitMQ 44 | threading.Thread(target=start_consuming, daemon=True).start() 45 | 46 | # Iniciamos el servidor Flask 47 | app.run(debug=True) 48 | -------------------------------------------------------------------------------- /Complex Calculator.py: -------------------------------------------------------------------------------- 1 | class CalculadoraCompleja: 2 | def __init__(self, real, imaginaria): 3 | self.real = real 4 | self.imaginaria = imaginaria 5 | 6 | def __str__(self): 7 | return f"{self.real} + {self.imaginaria}i" 8 | 9 | def suma(self, otro): 10 | nueva_real = self.real + otro.real 11 | nueva_imaginaria = self.imaginaria + otro.imaginaria 12 | return CalculadoraCompleja(nueva_real, nueva_imaginaria) 13 | 14 | def resta(self, otro): 15 | nueva_real = self.real - otro.real 16 | nueva_imaginaria = self.imaginaria - otro.imaginaria 17 | return CalculadoraCompleja(nueva_real, nueva_imaginaria) 18 | 19 | def multiplicacion(self, otro): 20 | nueva_real = (self.real * otro.real) - (self.imaginaria * otro.imaginaria) 21 | nueva_imaginaria = (self.real * otro.imaginaria) + (self.imaginaria * otro.real) 22 | return CalculadoraCompleja(nueva_real, nueva_imaginaria) 23 | 24 | def division(self, otro): 25 | denominador = otro.real**2 + otro.imaginaria**2 26 | nueva_real = (self.real * otro.real + self.imaginaria * otro.imaginaria) / denominador 27 | nueva_imaginaria = (self.imaginaria * otro.real - self.real * otro.imaginaria) / denominador 28 | return CalculadoraCompleja(nueva_real, nueva_imaginaria) 29 | 30 | # Ejemplo de uso 31 | num1 = CalculadoraCompleja(3, 4) 32 | num2 = CalculadoraCompleja(1, 2) 33 | 34 | resultado_suma = num1.suma(num2) 35 | resultado_resta = num1.resta(num2) 36 | resultado_multiplicacion = num1.multiplicacion(num2) 37 | resultado_division = num1.division(num2) 38 | 39 | print(f"Suma: {resultado_suma}") 40 | print(f"Resta: {resultado_resta}") 41 | print(f"Multiplicación: {resultado_multiplicacion}") 42 | print(f"División: {resultado_division}") 43 | -------------------------------------------------------------------------------- /Token Simulacion.py: -------------------------------------------------------------------------------- 1 | import secrets 2 | import time 3 | 4 | # Función para generar un token aleatorio con tiempo de expiración de 30 segundos 5 | def generar_token_con_expiracion(): 6 | token = secrets.token_hex(16) # Genera un token hexadecimal de 16 bytes (32 caracteres) 7 | tiempo_expiracion = int(time.time()) + 30 # Tiempo actual + 30 segundos 8 | return token, tiempo_expiracion 9 | 10 | # Simulación de inicio de sesión 11 | def iniciar_sesion(): 12 | usuario = input("Ingresa tu nombre de usuario: ") 13 | contrasena = input("Ingresa tu contraseña: ") 14 | 15 | # Verificar las credenciales (simulación básica) 16 | if usuario == "anyel" and contrasena == "anyel": 17 | print("¡Inicio de sesión exitoso!") 18 | 19 | while True: 20 | token_esperado, tiempo_expiracion = generar_token_con_expiracion() 21 | print(f"Tu token de sesión es válido por 30 segundos: {token_esperado}") 22 | 23 | for i in range(5, 0, -1): 24 | print(f"Ingresa el token en {i} segundos: ", end="") 25 | time.sleep(1) 26 | print("\r", end="") # Borra la línea actual en la consola 27 | 28 | # Simulación de uso del token en la sesión 29 | token_ingresado = input("\nIngresa tu token de sesión para continuar: ") 30 | tiempo_actual = int(time.time()) 31 | 32 | if tiempo_actual <= tiempo_expiracion and token_ingresado == token_esperado: 33 | print("Token válido. ¡Sesión iniciada correctamente!") 34 | break 35 | else: 36 | print("Token inválido o expirado. Intenta de nuevo.") 37 | else: 38 | print("Credenciales incorrectas. Inicio de sesión fallido.") 39 | 40 | if __name__ == "__main__": 41 | iniciar_sesion() 42 | -------------------------------------------------------------------------------- /Session-flask-login-basic.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify, session, redirect, url_for 2 | 3 | app = Flask(__name__) 4 | app.secret_key = 'anyel_ec' 5 | 6 | # Datos de usuario de ejemplo (se deben almacenar de manera segura en un entorno de producción) 7 | usuarios = { 8 | 'usuario1': {'password': 'contraseña1'}, 9 | 'usuario2': {'password': 'contraseña2'} 10 | } 11 | 12 | def verificar_credenciales(usuario, contraseña): 13 | """Verifica las credenciales del usuario.""" 14 | if usuario in usuarios and usuarios[usuario]['password'] == contraseña: 15 | return True 16 | return False 17 | 18 | @app.route('/login', methods=['POST']) 19 | def login(): 20 | """Ruta para iniciar sesión.""" 21 | datos = request.get_json() 22 | 23 | usuario = datos.get('usuario') 24 | contraseña = datos.get('contraseña') 25 | 26 | if verificar_credenciales(usuario, contraseña): 27 | # Inicia sesión y devuelve un mensaje de éxito 28 | session['usuario'] = usuario 29 | return jsonify({'mensaje': 'Inicio de sesión exitoso'}), 200 30 | else: 31 | return jsonify({'error': 'Credenciales inválidas'}), 401 32 | 33 | @app.route('/logout', methods=['POST']) 34 | def logout(): 35 | """Ruta para cerrar sesión.""" 36 | # Cierra la sesión y devuelve un mensaje de éxito 37 | session.pop('usuario', None) 38 | return jsonify({'mensaje': 'Cierre de sesión exitoso'}), 200 39 | 40 | @app.route('/perfil', methods=['GET']) 41 | def obtener_perfil(): 42 | """Ruta para obtener el perfil del usuario.""" 43 | usuario_actual = session.get('usuario') 44 | 45 | if usuario_actual: 46 | return jsonify({'usuario': usuario_actual}), 200 47 | else: 48 | return jsonify({'error': 'No hay sesión activa'}), 401 49 | 50 | if __name__ == '__main__': 51 | app.run(debug=True) 52 | -------------------------------------------------------------------------------- /dijkstra-redis.py: -------------------------------------------------------------------------------- 1 | import redis 2 | import heapq 3 | 4 | class Graph: 5 | def __init__(self): 6 | self.redis_conn = redis.StrictRedis(host='localhost', port=6379, db=0) 7 | 8 | def add_edge(self, start, end, weight): 9 | self.redis_conn.hset('graph', f'{start}-{end}', weight) 10 | 11 | def dijkstra(self, start, end): 12 | queue = [(0, start)] 13 | visited = set() 14 | distances = {node: float('inf') for node in self.redis_conn.hkeys('graph')} 15 | distances[start] = 0 16 | while queue: 17 | current_distance, current_node = heapq.heappop(queue) 18 | if current_node == end: 19 | return distances[end] 20 | if current_node in visited: 21 | continue 22 | visited.add(current_node) 23 | for neighbor in self.get_neighbors(current_node): 24 | distance = current_distance + self.get_weight(current_node, neighbor) 25 | if distance < distances[neighbor]: 26 | distances[neighbor] = distance 27 | heapq.heappush(queue, (distance, neighbor)) 28 | return float('inf') 29 | 30 | def get_neighbors(self, node): 31 | return [key.decode().split('-')[1] for key in self.redis_conn.hkeys('graph') if key.decode().split('-')[0] == node] 32 | 33 | def get_weight(self, start, end): 34 | return int(self.redis_conn.hget('graph', f'{start}-{end}')) 35 | 36 | # Ejemplo de uso 37 | if __name__ == "__main__": 38 | g = Graph() 39 | g.add_edge('A', 'B', 1) 40 | g.add_edge('A', 'C', 4) 41 | g.add_edge('B', 'C', 2) 42 | g.add_edge('B', 'D', 5) 43 | g.add_edge('C', 'D', 1) 44 | 45 | shortest_distance = g.dijkstra('A', 'D') 46 | print(f"La ruta más corta entre A y D es de longitud: {shortest_distance}") 47 | -------------------------------------------------------------------------------- /A*Search.py: -------------------------------------------------------------------------------- 1 | from queue import PriorityQueue 2 | 3 | def a_star(start, goal, graph, heuristic): 4 | open_set = PriorityQueue() 5 | open_set.put((0, start)) 6 | 7 | came_from = {} 8 | g_score = {start: 0} 9 | 10 | while not open_set.empty(): 11 | _, current = open_set.get() 12 | 13 | if current == goal: 14 | path = reconstruct_path(came_from, goal) 15 | return path 16 | 17 | for neighbor, cost in graph[current]: 18 | tentative_g_score = g_score[current] + cost 19 | if neighbor not in g_score or tentative_g_score < g_score[neighbor]: 20 | g_score[neighbor] = tentative_g_score 21 | f_score = tentative_g_score + heuristic[neighbor] 22 | open_set.put((f_score, neighbor)) 23 | came_from[neighbor] = current 24 | 25 | return None 26 | 27 | def reconstruct_path(came_from, current): 28 | path = [current] 29 | while current in came_from: 30 | current = came_from[current] 31 | path.insert(0, current) 32 | return path 33 | 34 | # Crear el grafo y las heurísticas 35 | graph = { 36 | 1: [(2, 200)], 37 | 2: [(1, 200), (3, 150)], 38 | 3: [(2, 150), (6, 225)], 39 | 4: [(3, 350), (5, 300)], 40 | 5: [(4, 300), (6, 400), (7, 250)], 41 | 6: [(3, 225), (5, 400)], 42 | 7: [(5, 250), (8, 125)], 43 | 8: [(7, 125)] 44 | } 45 | 46 | heuristic = {1: 650, 2: 500, 3: 650, 4: 325, 5: 375, 6: 12, 7: 0, 8: 0} 47 | 48 | # Aplicar A* para encontrar el camino óptimo 49 | start_city = 1 50 | goal_city = 8 51 | path = a_star(start_city, goal_city, graph, heuristic) 52 | 53 | if path: 54 | print(f"El mejor camino entre las ciudades {start_city} y {goal_city} es: {path}") 55 | else: 56 | print(f"No hay camino posible entre las ciudades {start_city} y {goal_city}.") 57 | -------------------------------------------------------------------------------- /POO-CRUD.py: -------------------------------------------------------------------------------- 1 | class Estudiante: 2 | def __init__(self, id, nombre, edad): 3 | self.id = id 4 | self.nombre = nombre 5 | self.edad = edad 6 | 7 | class RegistroEstudiantes: 8 | def __init__(self): 9 | self.estudiantes = [] 10 | 11 | def crear_estudiante(self, id, nombre, edad): 12 | estudiante = Estudiante(id, nombre, edad) 13 | self.estudiantes.append(estudiante) 14 | print(f"Estudiante {nombre} creado satisfactoriamente.") 15 | 16 | def mostrar_estudiantes(self): 17 | if not self.estudiantes: 18 | print("No hay estudiantes registrados.") 19 | else: 20 | print("Lista de Estudiantes:") 21 | for estudiante in self.estudiantes: 22 | print(f"ID: {estudiante.id}, Nombre: {estudiante.nombre}, Edad: {estudiante.edad}") 23 | 24 | def actualizar_estudiante(self, id, nombre, edad): 25 | for estudiante in self.estudiantes: 26 | if estudiante.id == id: 27 | estudiante.nombre = nombre 28 | estudiante.edad = edad 29 | print(f"Estudiante {nombre} actualizado satisfactoriamente.") 30 | return 31 | print(f"No se encontró un estudiante con ID {id}.") 32 | 33 | def eliminar_estudiante(self, id): 34 | for estudiante in self.estudiantes: 35 | if estudiante.id == id: 36 | self.estudiantes.remove(estudiante) 37 | print(f"Estudiante con ID {id} eliminado satisfactoriamente.") 38 | return 39 | print(f"No se encontró un estudiante con ID {id}.") 40 | 41 | # Ejemplo de uso del proyecto 42 | registro = RegistroEstudiantes() 43 | 44 | registro.crear_estudiante(1, "Juan Perez", 20) 45 | registro.crear_estudiante(2, "Ana Gomez", 22) 46 | registro.mostrar_estudiantes() 47 | 48 | registro.actualizar_estudiante(1, "Juanita Perez", 21) 49 | registro.mostrar_estudiantes() 50 | 51 | registro.eliminar_estudiante(2) 52 | registro.mostrar_estudiantes() 53 | -------------------------------------------------------------------------------- /escanear_vulnerabilidades.py: -------------------------------------------------------------------------------- 1 | import nmap 2 | from vulners import Vulners 3 | 4 | def obtener_info_servicio(service_name): 5 | vulners = Vulners() 6 | 7 | # Buscar información sobre la vulnerabilidad utilizando Vulners API 8 | results = vulners.softwareVulnerabilities(service_name) 9 | 10 | if not results: 11 | return "No se encontraron vulnerabilidades conocidas." 12 | 13 | # Imprimir las vulnerabilidades encontradas y sus recomendaciones 14 | for result in results: 15 | print(f"Vulnerabilidad: {result['title']}") 16 | print(f"Descripción: {result['description']}") 17 | print(f"Recomendación: {result['recommendation']}") 18 | print("") 19 | 20 | def escanear_vulnerabilidades(ip): 21 | scanner = nmap.PortScanner() 22 | scanner.scan(ip, arguments='-p 1-65535 -T4 -A -v') 23 | 24 | for host in scanner.all_hosts(): 25 | print('Host : %s (%s)' % (host, scanner[host].hostname())) 26 | print('State : %s' % scanner[host].state()) 27 | 28 | for proto in scanner[host].all_protocols(): 29 | print('Protocolo : %s' % proto) 30 | 31 | lport = scanner[host][proto].keys() 32 | for port in lport: 33 | port_info = scanner[host][proto][port] 34 | print('Puerto : %s\tEstado : %s' % (port, port_info['state'])) 35 | print('Servicio : %s' % port_info['name']) 36 | 37 | # Verificar si hay información de vulnerabilidad disponible 38 | if 'product' in port_info and 'version' in port_info: 39 | servicio = f"{port_info['product']} {port_info['version']}" 40 | print('Servicio detectado: ', servicio) 41 | obtener_info_servicio(servicio) 42 | print('') 43 | 44 | 45 | if __name__ == '__main__': 46 | ip_a_escanear = '127.0.0.1' # Cambia esta IP por la dirección de tu red que deseas escanear 47 | escanear_vulnerabilidades(ip_a_escanear) 48 | -------------------------------------------------------------------------------- /API-RestFull.py: -------------------------------------------------------------------------------- 1 | # Developer by Anyel EC 2 | # Whatsapp: +593 99 167 5490 3 | # Linkedln: Anyel EC 4 | 5 | from flask import Flask, request, jsonify 6 | 7 | app = Flask(__name__) 8 | 9 | # Sample data to simulate a database 10 | todos = [ 11 | {"id": 1, "task": "Buy milk"}, 12 | {"id": 2, "task": "Exercise"}, 13 | {"id": 3, "task": "Code in Python"}, 14 | ] 15 | 16 | # Route to get all items 17 | @app.route('/todos', methods=['GET']) 18 | def get_todos(): 19 | return jsonify({'todos': todos}) 20 | 21 | # Route to get an item by ID 22 | @app.route('/todos/', methods=['GET']) 23 | def get_todo(todo_id): 24 | todo = next((item for item in todos if item["id"] == todo_id), None) 25 | if todo is not None: 26 | return jsonify({'todo': todo}) 27 | else: 28 | return jsonify({'error': 'Item not found'}), 404 29 | 30 | # Route to create a new item 31 | @app.route('/todos', methods=['POST']) 32 | def create_todo(): 33 | if not request.json or 'task' not in request.json: 34 | return jsonify({'error': 'Task is required'}), 400 35 | 36 | new_todo = { 37 | 'id': len(todos) + 1, 38 | 'task': request.json['task'] 39 | } 40 | 41 | todos.append(new_todo) 42 | return jsonify({'todo': new_todo}), 201 43 | 44 | # Route to update an item by ID 45 | @app.route('/todos/', methods=['PUT']) 46 | def update_todo(todo_id): 47 | todo = next((item for item in todos if item["id"] == todo_id), None) 48 | if todo is None: 49 | return jsonify({'error': 'Item not found'}), 404 50 | 51 | if 'task' in request.json: 52 | todo['task'] = request.json['task'] 53 | 54 | return jsonify({'todo': todo}) 55 | 56 | # Route to delete an item by ID 57 | @app.route('/todos/', methods=['DELETE']) 58 | def delete_todo(todo_id): 59 | global todos 60 | todos = [item for item in todos if item["id"] != todo_id] 61 | return jsonify({'result': True}) 62 | 63 | if __name__ == '__main__': 64 | app.run(debug=True) 65 | -------------------------------------------------------------------------------- /CRUD-Array.py: -------------------------------------------------------------------------------- 1 | class Empleado: 2 | def __init__(self, id, nombre, salario): 3 | self.id = id 4 | self.nombre = nombre 5 | self.salario = salario 6 | 7 | class GestionEmpleados: 8 | def __init__(self): 9 | self.empleados = [] 10 | 11 | def agregar_empleado(self, empleado): 12 | self.empleados.append(empleado) 13 | 14 | def buscar_empleado(self, id): 15 | for empleado in self.empleados: 16 | if empleado.id == id: 17 | return empleado 18 | return None 19 | 20 | def listar_empleados(self): 21 | for empleado in self.empleados: 22 | print(f"ID: {empleado.id}, Nombre: {empleado.nombre}, Salario: {empleado.salario}") 23 | 24 | def actualizar_empleado(self, id, nombre, salario): 25 | empleado = self.buscar_empleado(id) 26 | if empleado: 27 | empleado.nombre = nombre 28 | empleado.salario = salario 29 | print("Empleado actualizado con éxito.") 30 | else: 31 | print("Empleado no encontrado.") 32 | 33 | def eliminar_empleado(self, id): 34 | empleado = self.buscar_empleado(id) 35 | if empleado: 36 | self.empleados.remove(empleado) 37 | print("Empleado eliminado con éxito.") 38 | else: 39 | print("Empleado no encontrado.") 40 | 41 | # Crear una instancia de la clase GestionEmpleados 42 | gestion_empleados = GestionEmpleados() 43 | 44 | # Agregar empleados 45 | empleado1 = Empleado(1, "Juan", 50000) 46 | empleado2 = Empleado(2, "Ana", 60000) 47 | gestion_empleados.agregar_empleado(empleado1) 48 | gestion_empleados.agregar_empleado(empleado2) 49 | 50 | # Listar empleados 51 | print("Lista de empleados:") 52 | gestion_empleados.listar_empleados() 53 | 54 | # Actualizar empleado 55 | gestion_empleados.actualizar_empleado(1, "Juan Pérez", 55000) 56 | 57 | # Eliminar empleado 58 | gestion_empleados.eliminar_empleado(2) 59 | 60 | # Listar empleados actualizados 61 | print("\nLista de empleados después de actualizar y eliminar:") 62 | gestion_empleados.listar_empleados() 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Examples for Implementation in Applications 2 | 3 | This repository contains several simple Python examples that you can use as a reference or implement in your own applications. These examples cover a variety of topics and functionalities. Below is a list of the available examples: 4 | 5 | - **MVC Python:** Implementation of the Model-View-Controller (MVC) pattern in Python. 6 | 7 | - **API.py:** Creating a Python API for web services. 8 | 9 | - **Ahorcado.py:** Implementation of the Hangman game in Python. 10 | 11 | - **ArbolDecision-Suma.py:** An example of a decision tree for adding numbers. 12 | 13 | - **Array.py:** An example of handling arrays in Python. 14 | 15 | - **BinarySearch.py:** Implementation of binary search in Python. 16 | 17 | - **CRUD-MySql.py:** CRUD operations with MySQL in Python. 18 | 19 | - **CRUD-PostgreSQL.py:** CRUD operations with PostgreSQL in Python. 20 | 21 | - **Caesar encryption.py:** Implementation of Caesar encryption in Python. 22 | 23 | - **GameSnake.pt:** Snake Game implemented in Python. 24 | 25 | - **GeneratePassword.py:** Password generator in Python. 26 | 27 | - **ModelMachineLearningSum.py:** Machine learning model for summing numbers. 28 | 29 | - **Puertos.py:** Port scanning in Python. 30 | 31 | - **SQLITE:** Examples of using the SQLite database in Python. 32 | 33 | - **SendMail.py:** Sending emails in Python. 34 | 35 | - **SendingMail.py:** An example of sending emails with Python. 36 | 37 | - **TextInPDF.py:** Creating PDF files with text in Python. 38 | 39 | - **Token Simulacion.py:** Token simulation in Python. 40 | 41 | - **check_existing_mail.py:** Verification of existing email addresses in Python. 42 | 43 | - **extractImageBackground.py:** Background removal from an image in Python. 44 | 45 | - **hash_sha256.py:** Using the SHA-256 hash function in Python. 46 | 47 | - **verifySecurePassword.py:** Verification of secure passwords in Python. 48 | 49 | Each example includes an individual file with its corresponding code. Feel free to explore, modify, and use these examples as needed for your projects in Python. 50 | 51 | We hope these examples prove to be useful for your Python projects! 52 | -------------------------------------------------------------------------------- /CRUD-POO-MongoDB.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | 3 | class MongoDB: 4 | def __init__(self, host='localhost', port=27017, database='mydb'): 5 | self.client = MongoClient(host, port) 6 | self.db = self.client[database] 7 | 8 | def create_document(self, collection_name, data): 9 | collection = self.db[collection_name] 10 | result = collection.insert_one(data) 11 | return result.inserted_id 12 | 13 | def read_document(self, collection_name, query={}): 14 | collection = self.db[collection_name] 15 | return collection.find_one(query) 16 | 17 | def update_document(self, collection_name, query, data): 18 | collection = self.db[collection_name] 19 | result = collection.update_one(query, {'$set': data}) 20 | return result.modified_count 21 | 22 | def delete_document(self, collection_name, query): 23 | collection = self.db[collection_name] 24 | result = collection.delete_one(query) 25 | return result.deleted_count 26 | 27 | if __name__ == '__main__': 28 | # Crear una instancia de MongoDB 29 | db = MongoDB() 30 | 31 | # Ejemplo de uso: 32 | 33 | # Crear un documento 34 | data_to_insert = {'name': 'Anyel EC', 'age': 30} 35 | inserted_id = db.create_document('users', data_to_insert) 36 | print(f'Nuevo documento creado con ID: {inserted_id}') 37 | 38 | # Leer un documento 39 | user = db.read_document('users', {'name': 'Anyel EC'}) 40 | print('Documento encontrado:') 41 | print(user) 42 | 43 | # Actualizar un documento 44 | update_query = {'name': 'Anyel EC'} 45 | new_data = {'age': 31} 46 | updated_count = db.update_document('users', update_query, new_data) 47 | print(f'Número de documentos actualizados: {updated_count}') 48 | 49 | # Leer el documento actualizado 50 | updated_user = db.read_document('users', {'name': 'Anyel EC'}) 51 | print('Documento actualizado:') 52 | print(updated_user) 53 | 54 | # Eliminar un documento 55 | delete_query = {'name': 'Anyel EC'} 56 | deleted_count = db.delete_document('users', delete_query) 57 | print(f'Número de documentos eliminados: {deleted_count}') 58 | -------------------------------------------------------------------------------- /AlgoritmoGenetico.py: -------------------------------------------------------------------------------- 1 | # importar librerias 2 | import pygad # libreria para algoritmos geneticos 3 | import numpy # libreria para operaciones matematicas 4 | 5 | 6 | inputs = [0.4, 1, 0.7, 8] # arreglo de entradas para la red neuronal 7 | desired_output = 32 # salida deseada para la red neuronal 8 | 9 | 10 | # funcion de fitness con dos parametros de entrada 11 | def fitness_func(solution, solution_idx): 12 | # salida de la red neuronal en donde se multiplica la solucion por las entradas 13 | output = numpy.sum(solution*inputs) 14 | # calculo de la funcion de fitness con la salida de la red neuronal 15 | fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001) 16 | return fitness # retorno de la funcion de fitness 17 | 18 | 19 | # configuracion del algoritmo genetico 20 | ga_instance = pygad.GA(num_generations=100, # numero de generaciones 21 | sol_per_pop=10, # numero de soluciones por poblacion 22 | num_genes=len(inputs), # numero de genes por solucion 23 | num_parents_mating=2, # numero de padres por generacion 24 | fitness_func=fitness_func, # funcion de fitness 25 | mutation_type="random", # tipo de mutacion 26 | mutation_probability=0.6) # probabilidad de mutacion 27 | ga_instance.run() # ejecucion del algoritmo genetico 28 | ga_instance.plot_fitness() # grafica de la funcion de fitness 29 | 30 | # 1. ¿Si ejecuto el código varias veces se obtiene la misma respuesta? 31 | # No, debido a que el algoritmo genetico es un algoritmo probabilistico 32 | # 2. ¿La función fitness_func() declarada sirve problemas generales o específico(s)? 33 | # Sirve para problemas especificos, ya que la funcion de fitness se calcula con la salida de la red neuronal 34 | #3. ¿Qué representa en el código la variable fitness? 35 | # Representa el valor de la funcion de fitness 36 | # 4. ¿Qué podemos observar en el gráfico generado por plot_fitness? 37 | # Podemos observar la evolucion de la funcion de fitness en cada generacion 38 | #5. ¿Aproximadamente en cuantas generaciones deja de mejorar el fitness? 39 | # En la generacion 50 40 | -------------------------------------------------------------------------------- /FLASK-API-JWT.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify 2 | from jwt import encode, decode # Agrega decode aquí 3 | import datetime 4 | 5 | app = Flask(__name__) 6 | 7 | # Clave secreta para firmar el token 8 | SECRET_KEY = 'anyel_ec' 9 | 10 | # Ruta para la autenticación y generación del token 11 | @app.route('/login', methods=['POST']) 12 | def login(): 13 | # Verifica las credenciales (en este ejemplo, se usa un usuario y contraseña fijos) 14 | if request.json and request.json['usuario'] == 'anyel' and request.json['contraseña'] == 'ec': 15 | # Genera un token con un payload que incluye el usuario y la fecha de expiración 16 | payload = {'usuario': request.json['usuario'], 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)} 17 | token = encode(payload, SECRET_KEY, algorithm='HS256') 18 | return jsonify({'token': token}) 19 | else: 20 | return jsonify({'mensaje': 'Credenciales inválidas'}), 401 21 | 22 | # Decorador para requerir autenticación JWT 23 | def requerir_autenticacion(f): 24 | def decorador(*args, **kwargs): 25 | token = request.headers.get('Authorization') 26 | 27 | if not token: 28 | return jsonify({'mensaje': 'Token de autenticación faltante'}), 401 29 | 30 | try: 31 | # Verifica y decodifica el token 32 | payload = decode(token, SECRET_KEY, algorithms=['HS256']) 33 | # Agrega el usuario al contexto de la solicitud 34 | request.usuario = payload['usuario'] 35 | except: 36 | return jsonify({'mensaje': 'Token de autenticación inválido'}), 401 37 | 38 | # Llama a la función original con el usuario autenticado 39 | return f(*args, **kwargs) 40 | 41 | # Cambia el nombre de la función decorada por conveniencia en depuración 42 | decorador.__name__ = f.__name__ 43 | return decorador 44 | 45 | # Ruta protegida que requiere autenticación mediante JWT 46 | @app.route('/recurso_protegido', methods=['GET']) 47 | @requerir_autenticacion 48 | def recurso_protegido(): 49 | return jsonify({'mensaje': 'Bienvenido, {}! Este es un recurso protegido.'.format(request.usuario)}) 50 | 51 | if __name__ == '__main__': 52 | app.run(debug=True) 53 | -------------------------------------------------------------------------------- /OAuth2-google.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, redirect, url_for, jsonify 2 | from oauthlib.oauth2 import WebApplicationClient 3 | import requests 4 | 5 | app = Flask(__name__) 6 | 7 | # Configura las credenciales de OAuth2 de Google 8 | GOOGLE_CLIENT_ID = 'tu-client-id-de-google' 9 | GOOGLE_CLIENT_SECRET = 'tu-client-secret-de-google' 10 | GOOGLE_DISCOVERY_URL = 'https://accounts.google.com/.well-known/openid-configuration' 11 | 12 | client = WebApplicationClient(GOOGLE_CLIENT_ID) 13 | 14 | # Función de ayuda para obtener la URL de autorización de Google 15 | def get_google_provider_cfg(): 16 | return requests.get(GOOGLE_DISCOVERY_URL).json() 17 | 18 | # Ruta para iniciar sesión 19 | @app.route('/login') 20 | def login(): 21 | google_provider_cfg = get_google_provider_cfg() 22 | authorization_endpoint = google_provider_cfg["authorization_endpoint"] 23 | 24 | # Construye la URL de autorización de Google 25 | request_uri = client.prepare_request_uri( 26 | authorization_endpoint, 27 | redirect_uri=request.base_url + "/callback", 28 | scope=["openid", "email", "profile"] 29 | ) 30 | return redirect(request_uri) 31 | 32 | # Ruta de callback después de la autorización 33 | @app.route('/login/callback') 34 | def callback(): 35 | code = request.args.get("code") 36 | 37 | # Intercambio de código de autorización por tokens de acceso 38 | google_provider_cfg = get_google_provider_cfg() 39 | token_endpoint = google_provider_cfg["token_endpoint"] 40 | 41 | token_url, headers, body = client.prepare_token_request( 42 | token_endpoint, 43 | authorization_response=request.url, 44 | redirect_url=request.base_url, 45 | code=code 46 | ) 47 | token_response = requests.post( 48 | token_url, 49 | headers=headers, 50 | data=body, 51 | auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET), 52 | ) 53 | 54 | # Verifica la validez del token de acceso 55 | client.parse_request_body_response(json.dumps(token_response.json())) 56 | 57 | userinfo_endpoint = google_provider_cfg["userinfo_endpoint"] 58 | uri, headers, body = client.add_token(userinfo_endpoint) 59 | userinfo_response = requests.get(uri, headers=headers, data=body) 60 | 61 | # Extrae los datos del usuario 62 | userinfo_data = userinfo_response.json() 63 | return jsonify(userinfo_data) 64 | 65 | if __name__ == '__main__': 66 | app.run(debug=True) 67 | -------------------------------------------------------------------------------- /CRUD-PostgreSQL.py: -------------------------------------------------------------------------------- 1 | import psycopg2 2 | from psycopg2 import Error 3 | 4 | # Configura la información de conexión a la base de datos 5 | db_params = { 6 | 'host': 'tu_host', 7 | 'database': 'tu_base_de_datos', 8 | 'user': 'tu_usuario', 9 | 'password': 'tu_contraseña' 10 | } 11 | 12 | # Función para insertar un nuevo registro 13 | def insert_record(connection, cursor, name, age): 14 | try: 15 | query = "INSERT INTO personas (nombre, edad) VALUES (%s, %s);" 16 | cursor.execute(query, (name, age)) 17 | connection.commit() 18 | print("Registro insertado correctamente.") 19 | except Error as e: 20 | print("Error al insertar el registro:", e) 21 | 22 | # Función para leer todos los registros 23 | def read_records(connection, cursor): 24 | try: 25 | query = "SELECT * FROM personas;" 26 | cursor.execute(query) 27 | records = cursor.fetchall() 28 | for record in records: 29 | print(record) 30 | except Error as e: 31 | print("Error al leer los registros:", e) 32 | 33 | # Función para actualizar un registro 34 | def update_record(connection, cursor, record_id, new_age): 35 | try: 36 | query = "UPDATE personas SET edad = %s WHERE id = %s;" 37 | cursor.execute(query, (new_age, record_id)) 38 | connection.commit() 39 | print("Registro actualizado correctamente.") 40 | except Error as e: 41 | print("Error al actualizar el registro:", e) 42 | 43 | # Función para eliminar un registro 44 | def delete_record(connection, cursor, record_id): 45 | try: 46 | query = "DELETE FROM personas WHERE id = %s;" 47 | cursor.execute(query, (record_id,)) 48 | connection.commit() 49 | print("Registro eliminado correctamente.") 50 | except Error as e: 51 | print("Error al eliminar el registro:", e) 52 | 53 | # Función principal 54 | def main(): 55 | try: 56 | connection = psycopg2.connect(**db_params) 57 | cursor = connection.cursor() 58 | 59 | # Ejemplos de uso de las funciones 60 | insert_record(connection, cursor, "Ejemplo 1", 25) 61 | insert_record(connection, cursor, "Ejemplo 2", 30) 62 | read_records(connection, cursor) 63 | update_record(connection, cursor, 1, 26) 64 | delete_record(connection, cursor, 2) 65 | 66 | cursor.close() 67 | connection.close() 68 | except Error as e: 69 | print("Error de conexión:", e) 70 | 71 | 72 | main() 73 | -------------------------------------------------------------------------------- /GameSnake.pt: -------------------------------------------------------------------------------- 1 | import random 2 | import curses 3 | 4 | # Inicializar la pantalla de la consola para la interfaz de curses 5 | stdscr = curses.initscr() 6 | curses.curs_set(0) # Ocultar el cursor en la pantalla 7 | sh, sw = stdscr.getmaxyx() # Obtener las dimensiones de la pantalla (altura y ancho) 8 | w = stdscr.subwin(sh, sw, 0, 0) # Crear una ventana subordinada en toda la pantalla 9 | w.keypad(1) # Habilitar el procesamiento de teclas especiales 10 | w.timeout(100) # Establecer el tiempo de espera para la actualización de la ventana 11 | 12 | # Posición inicial de la serpiente y su longitud inicial 13 | snk_x = sw // 4 14 | snk_y = sh // 2 15 | snake = [ 16 | [snk_y, snk_x], 17 | [snk_y, snk_x - 1], 18 | [snk_y, snk_x - 2] 19 | ] 20 | 21 | # Posición inicial de la comida 22 | food = [sh // 2, sw // 2] 23 | w.addch(food[0], food[1], curses.ACS_PI) # Dibujar la comida en la pantalla 24 | 25 | key = curses.KEY_RIGHT # Tecla inicial para mover la serpiente hacia la derecha 26 | 27 | # Bucle principal del juego 28 | while True: 29 | next_key = w.getch() # Obtener la siguiente tecla presionada 30 | key = key if next_key == -1 else next_key # Cambiar la dirección solo si se presionó una tecla 31 | 32 | # Verificar si la serpiente choca contra las paredes o contra sí misma 33 | if ( 34 | snake[0][0] in [0, sh] or 35 | snake[0][1] in [0, sw] or 36 | snake[0] in snake[1:] 37 | ): 38 | curses.endwin() # Finalizar la pantalla curses 39 | quit() 40 | 41 | new_head = [snake[0][0], snake[0][1]] # Crear la nueva posición de la cabeza de la serpiente 42 | 43 | # Actualizar la posición de la cabeza según la tecla presionada 44 | if key == curses.KEY_DOWN: 45 | new_head[0] += 1 46 | if key == curses.KEY_UP: 47 | new_head[0] -= 1 48 | if key == curses.KEY_LEFT: 49 | new_head[1] -= 1 50 | if key == curses.KEY_RIGHT: 51 | new_head[1] += 1 52 | 53 | snake.insert(0, new_head) # Agregar la nueva posición de la cabeza a la serpiente 54 | 55 | # Verificar si la serpiente come la comida 56 | if snake[0] == food: 57 | food = None 58 | while food is None: 59 | nf = [ 60 | random.randint(1, sh - 1), 61 | random.randint(1, sw - 1) 62 | ] 63 | food = nf if nf not in snake else None 64 | w.addch(food[0], food[1], curses.ACS_PI) # Dibujar nueva comida en la pantalla 65 | else: 66 | tail = snake.pop() # Quitar la cola de la serpiente 67 | w.addch(tail[0], tail[1], ' ') # Borrar la posición de la cola de la pantalla 68 | 69 | w.addch(snake[0][0], snake[0][1], curses.ACS_CKBOARD) # Dibujar la cabeza de la serpiente 70 | -------------------------------------------------------------------------------- /API'REST-JSON-Flask.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify 2 | import json 3 | import os 4 | 5 | app = Flask(__name__) 6 | 7 | # Definir el nombre del archivo JSON para almacenar los datos 8 | json_file_path = "mantenimiento_vias_data.json" 9 | 10 | # Función para cargar datos desde el archivo JSON 11 | def cargar_datos_desde_json(): 12 | if os.path.exists(json_file_path): 13 | with open(json_file_path, 'r') as json_file: 14 | return json.load(json_file) 15 | else: 16 | return [] 17 | 18 | # Función para guardar datos en el archivo JSON 19 | def guardar_datos_en_json(data): 20 | with open(json_file_path, 'w') as json_file: 21 | json.dump(data, json_file, indent=2) 22 | 23 | # Datos de inicio con un ID autoincremental 24 | mantenimiento_vias_data = cargar_datos_desde_json() 25 | id_counter = 1 if not mantenimiento_vias_data else max(m['id'] for m in mantenimiento_vias_data) + 1 26 | 27 | # Rutas CRUD 28 | @app.route('/api/v1/mantenimiento_vias', methods=['GET']) 29 | def obtener_mantenimientos(): 30 | return jsonify(mantenimiento_vias_data) 31 | 32 | @app.route('/api/v1/mantenimiento_vias', methods=['POST']) 33 | def agregar_mantenimiento(): 34 | global id_counter 35 | nuevo_mantenimiento = request.json 36 | nuevo_mantenimiento["id"] = id_counter 37 | id_counter += 1 38 | mantenimiento_vias_data.append(nuevo_mantenimiento) 39 | guardar_datos_en_json(mantenimiento_vias_data) 40 | return jsonify({"mensaje": "Mantenimiento agregado exitosamente"}) 41 | 42 | @app.route('/api/v1/mantenimiento_vias/', methods=['GET']) 43 | def obtener_mantenimiento(mantenimiento_id): 44 | mantenimiento = next((m for m in mantenimiento_vias_data if m['id'] == mantenimiento_id), None) 45 | return jsonify(mantenimiento) 46 | 47 | @app.route('/api/v1/mantenimiento_vias/', methods=['PUT']) 48 | def actualizar_mantenimiento(mantenimiento_id): 49 | nuevo_mantenimiento = request.json 50 | for mantenimiento in mantenimiento_vias_data: 51 | if mantenimiento['id'] == mantenimiento_id: 52 | mantenimiento.update(nuevo_mantenimiento) 53 | guardar_datos_en_json(mantenimiento_vias_data) 54 | return jsonify({"mensaje": "Mantenimiento actualizado exitosamente"}) 55 | return jsonify({"error": "Mantenimiento no encontrado"}), 404 56 | 57 | @app.route('/api/v1/mantenimiento_vias/', methods=['DELETE']) 58 | def eliminar_mantenimiento(mantenimiento_id): 59 | global mantenimiento_vias_data 60 | mantenimiento_vias_data = [m for m in mantenimiento_vias_data if m['id'] != mantenimiento_id] 61 | guardar_datos_en_json(mantenimiento_vias_data) 62 | return jsonify({"mensaje": "Mantenimiento eliminado exitosamente"}) 63 | 64 | # Punto de entrada 65 | if __name__ == '__main__': 66 | app.run(debug=True) 67 | -------------------------------------------------------------------------------- /verifySecurePassword.py: -------------------------------------------------------------------------------- 1 | # importar la biblioteca hashlib 2 | import hashlib 3 | 4 | # función para verificar la fortaleza de la contraseña 5 | def verificar_contrasena(contrasena): 6 | # convertir la contraseña a una cadena de bytes 7 | contrasena_bytes = contrasena.encode('utf-8') 8 | 9 | # calcular el hash de la contraseña utilizando la función SHA-256 10 | hash_contrasena = hashlib.sha256(contrasena_bytes) 11 | 12 | # convertir el hash a una cadena hexadecimal 13 | hash_contrasena_hex = hash_contrasena.hexdigest() 14 | 15 | # verificar la longitud de la contraseña 16 | if len(contrasena) < 8: 17 | print("La contraseña es demasiado corta.") 18 | return False 19 | 20 | # verificar si la contraseña contiene números 21 | if not any(char.isdigit() for char in contrasena): 22 | print("La contraseña debe contener al menos un número.") 23 | return False 24 | 25 | # verificar si la contraseña contiene letras mayúsculas 26 | if not any(char.isupper() for char in contrasena): 27 | print("La contraseña debe contener al menos una letra mayúscula.") 28 | return False 29 | 30 | # verificar si la contraseña contiene letras minúsculas 31 | if not any(char.islower() for char in contrasena): 32 | print("La contraseña debe contener al menos una letra minúscula.") 33 | return False 34 | 35 | # verificar si la contraseña contiene caracteres especiales 36 | caracteres_especiales = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" 37 | if not any(char in caracteres_especiales for char in contrasena): 38 | print("La contraseña debe contener al menos un caracter especial.") 39 | return False 40 | 41 | # verificar si la contraseña es segura (no se encuentra en una lista de contraseñas comunes) 42 | contrasenas_comunes = ["123456", "password", "123456789", "12345678", "12345", "1234567", "1234567890", "qwerty", "abc123", "111111", "123123", "admin", "letmein", "welcome", "monkey", "password1", "123qwe", "shadow", "sunshine", "master", "football", "baseball", "chelsea", "qwertyuiop", "ashley", "superman", "696969", "dragon", "654321", "mustang", "trustno1", "michael", "jesus", "password2", "jordan", "liverpool", "buster", "loveme", "babygirl", "jennifer", "computer", "iloveyou", "princess", "hello", "freedom", "whatever", "solo", "maggie", "harley", "hannah", "password3", "cowboy", "samsung", "cookie", "summer", "killer", "charlie", "password4", "sweety", "snoopy", "jessica", "pepper", "daniel", "starwars", "1q2w3e4r", "ferrari", "george", "blablabla", "a1b2c3", "222222", "tigger", "rabbit", "7777777", "abcd1234", "123abc", "pokemon", "jason", "zxcvbnm", "security"] 43 | if contrasena in contrasenas_comunes: 44 | print("Esta contraseña es muy común y no es segura.") 45 | return False 46 | 47 | # si la contraseña pasa todas las verificaciones, se considera segura 48 | print("La contraseña es segura.") 49 | return True 50 | 51 | 52 | 53 | contrasena = input("Introduzca su contraseña: ") 54 | verificar_contrasena(contrasena) 55 | -------------------------------------------------------------------------------- /POO-CRUD-Mongo.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | 3 | class Student: 4 | def __init__(self, name, age, grade): 5 | self.name = name 6 | self.age = age 7 | self.grade = grade 8 | 9 | def to_dict(self): 10 | return {"name": self.name, "age": self.age, "grade": self.grade} 11 | 12 | class MongoDBCRUD: 13 | def __init__(self, connection_string, database_name, collection_name): 14 | self.client = MongoClient(connection_string) 15 | self.db = self.client[database_name] 16 | self.collection = self.db[collection_name] 17 | 18 | def create(self, obj): 19 | data = obj.to_dict() 20 | result = self.collection.insert_one(data) 21 | return result.inserted_id 22 | 23 | def read(self, query=None): 24 | if query is None: 25 | query = {} 26 | return list(self.collection.find(query)) 27 | 28 | def update(self, query, update_data): 29 | result = self.collection.update_many(query, {"$set": update_data}) 30 | return result.modified_count 31 | 32 | def delete(self, query): 33 | result = self.collection.delete_many(query) 34 | return result.deleted_count 35 | 36 | # Ejemplo de uso 37 | if __name__ == "__main__": 38 | # Conéctate a la base de datos MongoDB (asegúrate de tener MongoDB en ejecución) 39 | connection_string = "mongodb://localhost:27017/" 40 | database_name = "school" 41 | collection_name = "students" 42 | 43 | # Crea instancias de la clase Student 44 | student1 = Student("John Doe", 20, "A") 45 | student2 = Student("Jane Smith", 22, "B") 46 | 47 | # Crea una instancia de MongoDBCRUD 48 | crud = MongoDBCRUD(connection_string, database_name, collection_name) 49 | 50 | # Crea estudiantes en la base de datos 51 | student1_id = crud.create(student1) 52 | student2_id = crud.create(student2) 53 | 54 | print(f"Estudiantes creados con IDs: {student1_id}, {student2_id}") 55 | 56 | # Lee todos los estudiantes 57 | all_students = crud.read() 58 | print("Todos los estudiantes:") 59 | for student in all_students: 60 | print(student) 61 | 62 | # Actualiza la edad del estudiante John Doe 63 | update_query = {"name": "John Doe"} 64 | update_data = {"age": 21} 65 | updated_count = crud.update(update_query, update_data) 66 | print(f"Estudiantes actualizados: {updated_count}") 67 | 68 | # Lee nuevamente todos los estudiantes después de la actualización 69 | updated_students = crud.read() 70 | print("Estudiantes después de la actualización:") 71 | for student in updated_students: 72 | print(student) 73 | 74 | # Elimina a Jane Smith de la base de datos 75 | delete_query = {"name": "Jane Smith"} 76 | deleted_count = crud.delete(delete_query) 77 | print(f"Estudiantes eliminados: {deleted_count}") 78 | 79 | # Lee nuevamente todos los estudiantes después de la eliminación 80 | remaining_students = crud.read() 81 | print("Estudiantes restantes después de la eliminación:") 82 | for student in remaining_students: 83 | print(student) 84 | -------------------------------------------------------------------------------- /POO-NoSQL.py: -------------------------------------------------------------------------------- 1 | # Author: Anyel EC 2 | import pymongo 3 | 4 | class Person: 5 | def __init__(self, name, age, occupation): 6 | # Constructor for the Person class 7 | self.name = name 8 | self.age = age 9 | self.occupation = occupation 10 | 11 | def __str__(self): 12 | # String representation of a Person object 13 | return f"Name: {self.name}, Age: {self.age}, Occupation: {self.occupation}" 14 | 15 | class DatabaseManager: 16 | def __init__(self): 17 | # Constructor for the DatabaseManager class 18 | # Connect to the MongoDB server 19 | self.client = pymongo.MongoClient("mongodb://localhost:27017/") 20 | # Access the "crud_db" database 21 | self.database = self.client["crud_db"] 22 | # Access the "personas" collection within the database 23 | self.collection = self.database["personas"] 24 | 25 | def create_person(self, person): 26 | # Method to create a new person in the database 27 | person_dict = {"nombre": person.name, "edad": person.age, "ocupacion": person.occupation} 28 | # Insert the person's data into the collection 29 | result = self.collection.insert_one(person_dict) 30 | print(f"Person created with ID: {result.inserted_id}") 31 | 32 | def read_people(self): 33 | # Method to read all people from the database 34 | people = self.collection.find() 35 | # Display information about each person 36 | for person in people: 37 | print(f"ID: {person['_id']}, {person['nombre']}, {person['edad']} years old, Occupation: {person['ocupacion']}") 38 | 39 | def update_person(self, person_id, new_data): 40 | # Method to update a person's data in the database 41 | result = self.collection.update_one({"_id": person_id}, {"$set": new_data}) 42 | if result.modified_count > 0: 43 | print(f"Person updated successfully.") 44 | else: 45 | print(f"Person with ID {person_id} not found.") 46 | 47 | def delete_person(self, person_id): 48 | # Method to delete a person from the database 49 | result = self.collection.delete_one({"_id": person_id}) 50 | if result.deleted_count > 0: 51 | print(f"Person deleted successfully.") 52 | else: 53 | print(f"Person with ID {person_id} not found.") 54 | 55 | # Example of usage 56 | db_manager = DatabaseManager() 57 | 58 | # Create persons 59 | person1 = Person("Juan", 25, "Student") 60 | person2 = Person("Ana", 30, "Engineer") 61 | db_manager.create_person(person1) 62 | db_manager.create_person(person2) 63 | 64 | # Read persons 65 | print("\nPersons in the database:") 66 | db_manager.read_people() 67 | 68 | # Update person 69 | updated_person_data = {"nombre": "Juan Pérez", "edad": 26, "ocupacion": "Developer"} 70 | db_manager.update_person(1, updated_person_data) 71 | 72 | # Read persons after the update 73 | print("\nPersons after the update:") 74 | db_manager.read_people() 75 | 76 | # Delete person 77 | db_manager.delete_person(2) 78 | 79 | # Read persons after the deletion 80 | print("\nPersons after the deletion:") 81 | db_manager.read_people() 82 | 83 | -------------------------------------------------------------------------------- /Ahorcado.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | def seleccionar_palabra(): 4 | palabras = ["python", "programacion", "computadora", "tecnologia", "inteligencia", "robotica"] 5 | return random.choice(palabras) 6 | def mostrar_ahorcado(intentos): 7 | graficos_ahorcado = [ 8 | """ 9 | +---+ 10 | | | 11 | | 12 | | 13 | | 14 | | 15 | ============ 16 | """, 17 | """ 18 | +---+ 19 | | | 20 | O | 21 | | 22 | | 23 | | 24 | ============ 25 | """, 26 | """ 27 | +---+ 28 | | | 29 | O | 30 | | | 31 | | 32 | | 33 | ============ 34 | """, 35 | """ 36 | +---+ 37 | | | 38 | O | 39 | /| | 40 | | 41 | | 42 | ============ 43 | """, 44 | """ 45 | +---+ 46 | | | 47 | O | 48 | /|\ | 49 | | 50 | | 51 | ============ 52 | """, 53 | """ 54 | +---+ 55 | | | 56 | O | 57 | /|\ | 58 | / | 59 | | 60 | ============ 61 | """, 62 | """ 63 | +---+ 64 | | | 65 | O | 66 | /|\ | 67 | / \ | 68 | | 69 | ============ 70 | """ 71 | ] 72 | return graficos_ahorcado[intentos] 73 | def jugar_ahorcado(): 74 | palabra = seleccionar_palabra() 75 | palabra = palabra.lower() #M m 76 | palabra_adivinada = ['_' if letra.isalpha() else letra for letra in palabra] 77 | intentos = 6 78 | letras_adivinadas = [] # A A 79 | palabra_adivinada[0] = palabra[0] # a__-__ 80 | palabra_adivinada[-1] = palabra[-1] #_______d 81 | print(f"La palabra es: {' '.join(palabra_adivinada)}") 82 | 83 | while intentos > 0 and "_" in palabra_adivinada: 84 | letra = input("Adivina una letra: ").lower() 85 | 86 | if letra in letras_adivinadas: 87 | print("Ya has adivinado esa letra.") 88 | continue 89 | 90 | letras_adivinadas.append(letra) 91 | 92 | if letra in palabra: 93 | for idx, l in enumerate(palabra): 94 | if l == letra: 95 | palabra_adivinada[idx] = letra 96 | # A 97 | else: 98 | intentos -= 1 99 | print(f"La letra '{letra}' no está en la palabra. Te quedan {intentos} intentos.") 100 | print(mostrar_ahorcado(6 - intentos)) 101 | 102 | print(f"Palabra: {' '.join(palabra_adivinada)}") 103 | print(f"Letras adivinadas: {', '.join(letras_adivinadas)}") 104 | 105 | if "_" not in palabra_adivinada: 106 | print("¡Felicidades! Has adivinado la palabra.") 107 | else: 108 | print(f"Perdiste. La palabra era '{palabra}'.") 109 | 110 | print("Juego del Ahorcado") 111 | jugar_ahorcado() 112 | -------------------------------------------------------------------------------- /AlgoritmodeRegresionLogistica.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "**Regresion logistica **" 21 | ], 22 | "metadata": { 23 | "id": "GJ-qCLKgvvmH" 24 | } 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "source": [ 29 | "**PROBAR LA LEÍDA DE LOS DATOS DEL CSV**" 30 | ], 31 | "metadata": { 32 | "id": "_x0xabiR2oH2" 33 | } 34 | }, 35 | { 36 | "cell_type": "code", 37 | "source": [ 38 | "import pandas as pd\n", 39 | "\n", 40 | "# Ruta al archivo CSV\n", 41 | "archivo_csv = \"datos.csv\"\n", 42 | "\n", 43 | "# Leer el archivo CSV en un DataFrame de pandas\n", 44 | "df = pd.read_csv(archivo_csv)\n", 45 | "\n", 46 | "# Mostrar las primeras filas del DataFrame para verificar que se haya leído correctamente\n", 47 | "print(df.head())\n" 48 | ], 49 | "metadata": { 50 | "id": "_-9r92Sbvzut" 51 | }, 52 | "execution_count": null, 53 | "outputs": [] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "source": [ 58 | "import pandas as pd\n", 59 | "from sklearn.model_selection import train_test_split\n", 60 | "from sklearn.feature_extraction.text import TfidfVectorizer\n", 61 | "from sklearn.linear_model import LogisticRegression\n", 62 | "from sklearn.metrics import classification_report, confusion_matrix\n", 63 | "\n", 64 | "# Leer el archivo CSV\n", 65 | "data = pd.read_csv(\"datos.csv\")\n", 66 | "\n", 67 | "# Eliminar filas con valores NaN en la columna 'reviews.text'\n", 68 | "data = data.dropna(subset=['reviews.text'])\n", 69 | "\n", 70 | "# Convertir las calificaciones de las reseñas en una variable binaria (0: negativa, 1: positiva)\n", 71 | "data['sentimiento'] = data['reviews.rating'].apply(lambda x: 1 if x >= 3 else 0)\n", 72 | "\n", 73 | "# Dividir los datos en conjunto de entrenamiento y conjunto de prueba\n", 74 | "X_train, X_test, y_train, y_test = train_test_split(data['reviews.text'], data['sentimiento'], test_size=0.2, random_state=42)\n", 75 | "\n", 76 | "# Vectorización de texto usando TF-IDF\n", 77 | "tfidf_vectorizer = TfidfVectorizer(stop_words='english')\n", 78 | "X_train_tfidf = tfidf_vectorizer.fit_transform(X_train)\n", 79 | "X_test_tfidf = tfidf_vectorizer.transform(X_test)\n", 80 | "\n", 81 | "# Entrenamiento del modelo de regresión logística\n", 82 | "model = LogisticRegression()\n", 83 | "model.fit(X_train_tfidf, y_train)\n", 84 | "\n", 85 | "# Evaluación del modelo\n", 86 | "predictions = model.predict(X_test_tfidf)\n", 87 | "print(\"Reporte de clasificación:\")\n", 88 | "print(classification_report(y_test, predictions))\n", 89 | "print(\"Matriz de confusión:\")\n", 90 | "print(confusion_matrix(y_test, predictions))\n" 91 | ], 92 | "metadata": { 93 | "colab": { 94 | "base_uri": "https://localhost:8080/" 95 | }, 96 | "id": "2XY24WXh1XAE", 97 | "outputId": "19d9fc8b-0cc0-4ed6-e86f-c1806f4658d7" 98 | }, 99 | "execution_count": 4, 100 | "outputs": [ 101 | { 102 | "output_type": "stream", 103 | "name": "stderr", 104 | "text": [ 105 | ":8: DtypeWarning: Columns (1,10) have mixed types. Specify dtype option on import or set low_memory=False.\n", 106 | " data = pd.read_csv(\"datos.csv\")\n" 107 | ] 108 | }, 109 | { 110 | "output_type": "stream", 111 | "name": "stdout", 112 | "text": [ 113 | "Reporte de clasificación:\n", 114 | " precision recall f1-score support\n", 115 | "\n", 116 | " 0 0.67 0.02 0.04 175\n", 117 | " 1 0.98 1.00 0.99 6757\n", 118 | "\n", 119 | " accuracy 0.98 6932\n", 120 | " macro avg 0.82 0.51 0.52 6932\n", 121 | "weighted avg 0.97 0.98 0.96 6932\n", 122 | "\n", 123 | "Matriz de confusión:\n", 124 | "[[ 4 171]\n", 125 | " [ 2 6755]]\n" 126 | ] 127 | } 128 | ] 129 | } 130 | ] 131 | } -------------------------------------------------------------------------------- /Introduce-Mininet-SDN.py: -------------------------------------------------------------------------------- 1 | from mininet.topo import Topo 2 | from mininet.net import Mininet 3 | from mininet.node import Node 4 | from mininet.log import setLogLevel, info 5 | from mininet.cli import CLI 6 | 7 | class LinuxRouter(Node): 8 | def config(self, **params): 9 | super(LinuxRouter, self).config(**params) 10 | self.cmd('sysctl net.ipv4.ip_forward=1') 11 | 12 | def terminate(self): 13 | self.cmd('sysctl net.ipv4.ip_forward=0') 14 | super(LinuxRouter, self).terminate() 15 | 16 | class NetworkTopo(Topo): 17 | def build(self, **_opts): 18 | # ROUTERS 19 | r1 = self.addHost('r1', cls=LinuxRouter, ip='192.168.0.1/24') 20 | r2 = self.addHost('r2', cls=LinuxRouter, ip='192.168.1.1/24') 21 | r3 = self.addHost('r3', cls=LinuxRouter, ip='192.168.2.1/24') 22 | 23 | # SWITCHES para el R1 24 | s1 = self.addSwitch('s1') 25 | s2 = self.addSwitch('s2') 26 | s3 = self.addSwitch('s3') 27 | s4 = self.addSwitch('s4') 28 | s5 = self.addSwitch('s5') 29 | s6 = self.addSwitch('s6') 30 | 31 | # SWITCHES para el R2 32 | s7 = self.addSwitch('s7') 33 | s8 = self.addSwitch('s8') 34 | s9 = self.addSwitch('s9') 35 | s10 = self.addSwitch('s10') 36 | 37 | # SWITCHES para el R3 38 | s11 = self.addSwitch('s11') 39 | s12 = self.addSwitch('s12') 40 | s13 = self.addSwitch('s13') 41 | s14 = self.addSwitch('s14') 42 | s15 = self.addSwitch('s15') 43 | s16 = self.addSwitch('s16') 44 | s17 = self.addSwitch('s17') 45 | s18 = self.addSwitch('s18') 46 | 47 | # ENLACES de los SWITCHES a los ROUTERS 48 | self.addLink(s1, r1, intfName2='r1-eth1', params2={'ip': '192.168.0.1/24'}) 49 | self.addLink(s1, s2) 50 | self.addLink(s1, s3) 51 | self.addLink(s1, s4) 52 | self.addLink(s2, s5) 53 | self.addLink(s3, s6) 54 | 55 | self.addLink(s7, r2, intfName2='r2-eth1', params2={'ip': '192.168.1.1/24'}) 56 | self.addLink(s7, s8) 57 | self.addLink(s7, s9) 58 | self.addLink(s8, s10) 59 | self.addLink(s9, s11) 60 | 61 | self.addLink(s12, r3, intfName2='r3-eth1', params2={'ip': '192.168.2.1/24'}) 62 | self.addLink(s12, s13) 63 | self.addLink(s12, s14) 64 | self.addLink(s12, s15) 65 | self.addLink(s13, s16) 66 | self.addLink(s14, s17) 67 | self.addLink(s15, s18) 68 | 69 | # ENLACES de los ROUTERS entre sí 70 | self.addLink(r1, r2, intfName1='r1-eth2', intfName2='r2-eth2', params1={'ip': '10.0.0.1/24'}, params2={'ip': '10.0.0.2/24'}) 71 | self.addLink(r2, r3, intfName1='r2-eth3', intfName2='r3-eth2', params1={'ip': '11.0.0.1/24'}, params2={'ip': '11.0.0.2/24'}) 72 | 73 | # CREAR LOS HOSTS PARA CADA ROUTER O SUCURSAL 74 | # ROUTER 1 75 | h1 = self.addHost(name='h1', ip='192.168.0.10/24', defaultRoute='via 192.168.0.1') 76 | h2 = self.addHost(name='h2', ip='192.168.0.11/24', defaultRoute='via 192.168.0.1') 77 | h3 = self.addHost(name='h3', ip='192.168.0.12/24', defaultRoute='via 192.168.0.1') 78 | 79 | # ROUTER 2 80 | h4 = self.addHost(name='h4', ip='192.168.1.10/24', defaultRoute='via 192.168.1.1') 81 | h5 = self.addHost(name='h5', ip='192.168.1.11/24', defaultRoute='via 192.168.1.1') 82 | h6 = self.addHost(name='h6', ip='192.168.1.12/24', defaultRoute='via 192.168.1.1') 83 | h7 = self.addHost(name='h7', ip='192.168.1.13/24', defaultRoute='via 192.168.1.1') 84 | 85 | # ROUTER 3 86 | h8 = self.addHost(name='h8', ip='192.168.2.10/24', defaultRoute='via 192.168.2.1') 87 | h9 = self.addHost(name='h9', ip='192.168.2.11/24', defaultRoute='via 192.168.2.1') 88 | h10 = self.addHost(name='h10', ip='192.168.2.12/24', defaultRoute='via 192.168.2.1') 89 | h11 = self.addHost(name='h11', ip='192.168.2.13/24', defaultRoute='via 192.168.2.1') 90 | h12 = self.addHost(name='h12', ip='192.168.2.14/24', defaultRoute='via 192.168.2.1') 91 | h13 = self.addHost(name='h13', ip='192.168.2.15/24', defaultRoute='via 192.168.2.1') 92 | 93 | # ASIGNAR LOS HOSTS A LOS SWITCH 94 | # ROUTER A 95 | self.addLink(h1, s5, intfName2='s5-eth3') 96 | self.addLink(h2, s6, intfName2='s6-eth3') 97 | self.addLink(h3, s4, intfName2='s4-eth3') 98 | 99 | # ROUTER B 100 | self.addLink(h4, s10, intfName2='s10-eth3') 101 | self.addLink(h5, s10, intfName2='s10-eth4') 102 | self.addLink(h6, s11, intfName2='s11-eth3') 103 | self.addLink(h7, s11, intfName2='s11-eth4') 104 | 105 | # ROUTER C 106 | self.addLink(h8, s16, intfName2='s16-eth3') 107 | self.addLink(h9, s16, intfName2='s16-eth4') 108 | self.addLink(h10, s17, intfName2='s17-eth3') 109 | self.addLink(h11, s17, intfName2='s17-eth4') 110 | self.addLink(h12, s18, intfName2='s18-eth3') 111 | self.addLink(h13, s18, intfName2='s18-eth4') 112 | 113 | def run(): 114 | topo = NetworkTopo() 115 | net = Mininet(topo=topo) 116 | 117 | net['r1'].cmd("ip route add 192.168.1.0/24 via 10.0.0.2 dev r1-eth2") 118 | net['r1'].cmd("ip route add 192.168.2.0/24 via 11.0.0.2 dev r1-eth3") 119 | 120 | # Configurar el enrutamiento para el Router B (r2) 121 | net['r2'].cmd("ip route add 192.168.0.0/24 via 10.0.0.1 dev r2-eth2") 122 | net['r2'].cmd("ip route add 192.168.2.0/24 via 11.0.0.2 dev r2-eth3") 123 | 124 | # Configurar el enrutamiento para el Router C (r3) 125 | net['r3'].cmd("ip route add 192.168.0.0/24 via 10.0.0.1 dev r3-eth2") 126 | net['r3'].cmd("ip route add 192.168.1.0/24 via 11.0.0.1 dev r3-eth3") 127 | 128 | net.start() 129 | CLI(net) 130 | net.stop() 131 | 132 | if _name_ == '_main_': 133 | setLogLevel('info') 134 | run() 135 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [2023] [Anyel EC] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /PatiñoAngel_RedNeuronal (1).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "**EJERCICIO UNO CON UNA SOLA CAPA POR ANGEL PATIÑO**" 21 | ], 22 | "metadata": { 23 | "id": "CPqxuHI4H08R" 24 | } 25 | }, 26 | { 27 | "cell_type": "code", 28 | "metadata": { 29 | "id": "Hy_pAhzDZ4gy" 30 | }, 31 | "source": [ 32 | "#importamos las librerias\n", 33 | "import tensorflow as tf # libreria de IA\n", 34 | "import numpy as np #libreria para manejar arreglos\n", 35 | "import matplotlib.pyplot as plt #graficar" 36 | ], 37 | "execution_count": 1, 38 | "outputs": [] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "metadata": { 43 | "id": "MIrfX72vaL1z" 44 | }, 45 | "source": [ 46 | "#Ejemplos para aprender\n", 47 | "celsius = np.array([-40, -10, 0, 8, 15, 22, 38], dtype=float) #entrada de grados celsius\n", 48 | "fahrenheit = np.array([-40, 14, 32, 46, 59, 72, 100], dtype=float) #entrada de grados celsius" 49 | ], 50 | "execution_count": 2, 51 | "outputs": [] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "metadata": { 56 | "id": "RIG6Y5jEafFL" 57 | }, 58 | "source": [ 59 | "capa = tf.keras.layers.Dense(units=1, input_shape=[1]) # UNA NEURONA DENSA\n", 60 | "modelo = tf.keras.Sequential([capa]) #MODELO SECUENCIAL" 61 | ], 62 | "execution_count": 3, 63 | "outputs": [] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "metadata": { 68 | "id": "1_WHzWidbN_8" 69 | }, 70 | "source": [ 71 | "modelo.compile(\n", 72 | " optimizer=tf.keras.optimizers.Adam(0.1), #Optimizador ADAM (Ajusta sesgo y peso automaticamente eficientemente, el parametro es la tasa de aprendizaje)\n", 73 | " loss='mean_squared_error' #error cuadrado medio\n", 74 | ")" 75 | ], 76 | "execution_count": 4, 77 | "outputs": [] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "metadata": { 82 | "colab": { 83 | "base_uri": "https://localhost:8080/" 84 | }, 85 | "id": "4D-NuUTnbabR", 86 | "outputId": "cdb75818-2e92-4770-c442-4c49bcad34d9" 87 | }, 88 | "source": [ 89 | "print(\"Comenzando entrenamiento...\")\n", 90 | "historial = modelo.fit(celsius, fahrenheit, epochs=1000, verbose=False) #fit entrena, pasamos los datos de celsius y fahrenheit, y las vueltas\n", 91 | "print(\"Modelo entrenado!\")" 92 | ], 93 | "execution_count": 5, 94 | "outputs": [ 95 | { 96 | "output_type": "stream", 97 | "name": "stdout", 98 | "text": [ 99 | "Comenzando entrenamiento...\n", 100 | "Modelo entrenado!\n" 101 | ] 102 | } 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "metadata": { 108 | "colab": { 109 | "base_uri": "https://localhost:8080/", 110 | "height": 466 111 | }, 112 | "id": "px43cF3Nb3mG", 113 | "outputId": "54fde9cd-4db0-4c38-fe40-0c1c5c6c8959" 114 | }, 115 | "source": [ 116 | "# funcion de perdidad\n", 117 | "plt.xlabel(\"# Epoca\")\n", 118 | "plt.ylabel(\"Magnitud de pérdida\")\n", 119 | "plt.plot(historial.history[\"loss\"])" 120 | ], 121 | "execution_count": 6, 122 | "outputs": [ 123 | { 124 | "output_type": "execute_result", 125 | "data": { 126 | "text/plain": [ 127 | "[]" 128 | ] 129 | }, 130 | "metadata": {}, 131 | "execution_count": 6 132 | }, 133 | { 134 | "output_type": "display_data", 135 | "data": { 136 | "text/plain": [ 137 | "

" 138 | ], 139 | "image/png": "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qlWr8Mwzz1y1/emnn8Y333zjkKI8FWeZERERScPuQOTr64sdO3ZctX3Hjh3w8fFxSFGeivcyIyIikobdK1VPnDgR48aNw759+9C7d28AQHZ2Nv7zn/9g+vTpDi/Qk6gaLMwoCEKTB7ITERHRrbE7EL366qto06YN5s2bhy+//BIAEB8fjyVLluDvf/+7wwv0JNaVqgFLL5GPt5eE1RAREXkOuwKR0WjE22+/jVGjRjH8OIF1DBHAQERERORKdo0hUigUmDNnDoxGo1OKmT17NmQyGSZOnChuq62tRVpaGkJDQxEQEIBhw4ahtLTU5n1FRUVISUmBn58fwsPD8corr1xV45YtW9C9e3eoVCq0bdsWS5cudcp3uBXeXjJYr5JxphkREZHr2D2oesCAAdi6davDC9mzZw8++eQTdOnSxWb7pEmTsGbNGqxatQpbt27FmTNnbG4wazKZkJKSgvr6euzcuRNffPEFli5dihkzZohtCgsLkZKSgvvuuw+5ubmYOHEixowZg02bNjn8e9wKmUzGO94TERFJwO4xRA8++CBeffVV5OXloUePHvD397fZ/+ijj9pdRHV1NVJTU/Hpp5/izTffFLdXVlbi888/x/Lly/HXv/4VgOVeavHx8di1axf69OmDH3/8EYcPH8ZPP/0ErVaLrl27YtasWZg6dSpmzpwJpVKJRYsWIS4uDu+++y4Ay5in7du34/3330dycnKjNdXV1aGurk58rdfr7f5eN8PH2wu1BjNqDewhIiIichW7e4jGjx+P0tJSvPfee0hNTcXgwYPFx5AhQ26qiLS0NKSkpCApKclme05ODgwGg832Dh06ICYmBllZWQCArKwsdO7cGVqtVmyTnJwMvV6P/Px8sc2fj52cnCweozHp6enQaDTiIzo6+qa+m718L48bqmUPERERkcvYHYjMZvM1HyaT/b0aK1euxL59+5Cenn7VvpKSEiiVSgQFBdls12q1KCkpEds0DEPW/dZ912uj1+tx6dKlRuuaNm0aKisrxYerVuG2DqSu5RgiIiIil7H7kllDtbW1t7QY48mTJ/HSSy8hIyPD7RZ1VKlUUKlUrv/cy2OIeMmMiIjIdezuITKZTJg1axZatWqFgIAAnDhxAgAwffp0fP7553YdKycnB2VlZejevTsUCgUUCgW2bt2K+fPnQ6FQQKvVor6+HhUVFTbv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wubNm4W9e/cKOp1O0Ol04n7rdPCBAwcKubm5wsaNG4UWLVpwOvgNNJxlJgg8z46we/duQaFQCG+99ZZw/PhxYdmyZYKfn5/w5Zdfim1mz54tBAUFCd9//71w8OBBYdCgQY1OW+7WrZuQnZ0tbN++XWjXrp3HTwdvaMSIEUKrVq3EaffffvutEBYWJkyZMkVsw/N8c6qqqoT9+/cL+/fvFwAI7733nrB//37hjz/+EATBMee1oqJC0Gq1wvDhw4VDhw4JK1euFPz8/Djtvrn78MMPhZiYGEGpVAq9e/cWdu3aJXVJzQqARh9LliwR21y6dEkYP368EBwcLPj5+QlDhgwRiouLbY7z+++/Cw8++KDg6+srhIWFCS+//LJgMBhc/G2alz8HIp5nx1izZo3QqVMnQaVSCR06dBAWL15ss99sNgvTp08XtFqtoFKphAEDBggFBQU2bc6fPy88+eSTQkBAgKBWq4WRI0cKVVVVrvwabk2v1wsvvfSSEBMTI/j4+Aht2rQR/vWvf9lM4+Z5vjk///xzo/8mjxgxQhAEx53XAwcOCH379hVUKpXQqlUrYfbs2bdcu0wQGizNSUREROSBOIaIiIiIPB4DEREREXk8BiIiIiLyeAxERERE5PEYiIiIiMjjMRARERGRx2MgIiIiIo/HQEREREQej4GIiIiIPB4DERG5vbNnz0KpVKKmpgYGgwH+/v7iHeCvZebMmZDJZFc9OnTo4KKqiag5UUhdABHRjWRlZeGuu+6Cv78/srOzERISgpiYmBu+r2PHjvjpp59stikU/GePiK7GHiIicns7d+7EPffcAwDYvn27+PxGFAoFIiIibB5hYWHi/tatW2PWrFl48skn4e/vj1atWmHBggU2xygqKsKgQYMQEBAAtVqNv//97ygtLbVps2bNGvTq1Qs+Pj4ICwvDkCFDxH3/7//9P/Ts2ROBgYGIiIjAU089hbKysps9FUTkJAxEROSWioqKEBQUhKCgILz33nv45JNPEBQUhH/+85/47rvvEBQUhPHjx9/y58ydOxd33XUX9u/fj1dffRUvvfQSMjIyAABmsxmDBg1CeXk5tm7dioyMDJw4cQKPP/64+P5169ZhyJAheOihh7B//35kZmaid+/e4n6DwYBZs2bhwIED+O677/D777/j2WefveW6icixeLd7InJLRqMRp06dgl6vR8+ePbF37174+/uja9euWLduHWJiYhAQEGDT49PQzJkzMWvWLPj6+tpsf/rpp7Fo0SIAlh6i+Ph4bNiwQdz/xBNPQK/XY/369cjIyMCDDz6IwsJCREdHAwAOHz6Mjh07Yvfu3ejVqxfuvvtutGnTBl9++WWTvtfevXvRq1cvVFVVISAg4GZODRE5AXuIiMgtKRQKtG7dGkePHkWvXr3QpUsXlJSUQKvVon///mjduvU1w5BV+/btkZuba/N44403bNrodLqrXh85cgQAcOTIEURHR4thCAASEhIQFBQktsnNzcWAAQOuWUNOTg4eeeQRxMTEIDAwEPfeey8A3HBQOBG5FkcXEpFb6tixI/744w8YDAaYzWYEBATAaDTCaDQiICAAsbGxyM/Pv+4xlEol2rZt69Q6/9wD1VBNTQ2Sk5ORnJyMZcuWoUWLFigqKkJycjLq6+udWhcR2Yc9RETkltavX4/c3FxERETgyy+/RG5uLjp16oQPPvgAubm5WL9+vUM+Z9euXVe9jo+PBwDEx8fj5MmTOHnypLj/8OHDqKioQEJCAgCgS5cuyMzMbPTYR48exfnz5zF79mz069cPHTp04IBqIjfFHiIickuxsbEoKSlBaWkpBg0aBJlMhvz8fAwbNgyRkZFNOobRaERJSYnNNplMBq1WK77esWMH5syZg8GDByMjIwOrVq3CunXrAABJSUno3LkzUlNT8cEHH8BoNGL8+PG499570bNnTwDA66+/jgEDBuCOO+7AE088AaPRiPXr12Pq1KmIiYmBUqnEhx9+iLFjx+LQoUOYNWuWg84QETkSe4iIyG1t2bJFnM6+e/duREVFNTkMAUB+fj4iIyNtHrGxsTZtXn75ZezduxfdunXDm2++iffeew/JyckALOHp+++/R3BwMPr374+kpCS0adMGX331lfj+v/zlL1i1ahV++OEHdO3aFX/961+xe/duAECLFi2wdOlSrFq1CgkJCZg9ezbeeecdB5wZInI0zjIjIo/VunVrTJw4ERMnTpS6FCKSGHuIiIiIyOMxEBEREZHH4yUzIiIi8njsISIiIiKPx0BEREREHo+BiIiIiDweAxERERF5PAYiIiIi8ngMREREROTxGIiIiIjI4zEQERERkcf7/w6svOznHrXSAAAAAElFTkSuQmCC\n" 140 | }, 141 | "metadata": {} 142 | } 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "metadata": { 148 | "colab": { 149 | "base_uri": "https://localhost:8080/" 150 | }, 151 | "id": "esVvhzjMcV9f", 152 | "outputId": "b13e0662-e03a-4b16-af74-5dbbb6de23f0" 153 | }, 154 | "source": [ 155 | "print(\"Prediccion\")\n", 156 | "resultado = modelo.predict([100.0])\n", 157 | "print(\"El resultado es: \" + str(resultado) + \" fahrenheit!\")" 158 | ], 159 | "execution_count": 7, 160 | "outputs": [ 161 | { 162 | "output_type": "stream", 163 | "name": "stdout", 164 | "text": [ 165 | "Prediccion\n", 166 | "1/1 [==============================] - 0s 180ms/step\n", 167 | "El resultado es: [[211.74113]] fahrenheit!\n" 168 | ] 169 | } 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "metadata": { 175 | "colab": { 176 | "base_uri": "https://localhost:8080/" 177 | }, 178 | "id": "FVDejrBgcokc", 179 | "outputId": "ba849530-91bc-45fb-a7f9-488ef4a036de" 180 | }, 181 | "source": [ 182 | "print(\"Variables internas del modelo\")\n", 183 | "print(capa.get_weights()) #obtener el peso, sesgo" 184 | ], 185 | "execution_count": 8, 186 | "outputs": [ 187 | { 188 | "output_type": "stream", 189 | "name": "stdout", 190 | "text": [ 191 | "Variables internas del modelo\n", 192 | "[array([[1.798352]], dtype=float32), array([31.905926], dtype=float32)]\n" 193 | ] 194 | } 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "source": [ 200 | "**SEGUNDO EJERCICIO DONDE ENTRENAMOS CON 3 CAPAS**" 201 | ], 202 | "metadata": { 203 | "id": "Nt3zEj1LH_-R" 204 | } 205 | }, 206 | { 207 | "cell_type": "code", 208 | "source": [ 209 | "# AUMENTAR CAPAS\n", 210 | "oculta1 = tf.keras.layers.Dense(units=3, input_shape=[1]) # PRIMERA CAPA\n", 211 | "oculta2 = tf.keras.layers.Dense(units=3) #SEGUNDA CAPA\n", 212 | "salida = tf.keras.layers.Dense(units=1) # CAPA DE SALIDA\n", 213 | "modelo = tf.keras.Sequential([oculta1, oculta2, salida]) # MODELO SECUENCIAL" 214 | ], 215 | "metadata": { 216 | "id": "kwZ3d-14IQ2r" 217 | }, 218 | "execution_count": 9, 219 | "outputs": [] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "source": [ 224 | "modelo.compile(\n", 225 | " optimizer=tf.keras.optimizers.Adam(0.1), #Optimizador ADAM (Ajusta sesgo y peso automaticamente eficientemente, el parametro es la tasa de aprendizaje)\n", 226 | " loss='mean_squared_error' #error cuadrado medio\n", 227 | ")" 228 | ], 229 | "metadata": { 230 | "id": "JMK8YOwUJJPe" 231 | }, 232 | "execution_count": 10, 233 | "outputs": [] 234 | }, 235 | { 236 | "cell_type": "code", 237 | "source": [ 238 | "print(\"Comenzando entrenamiento...\")\n", 239 | "historial = modelo.fit(celsius, fahrenheit, epochs=1000, verbose=False) #fit entrena, pasamos los datos de celsius y fahrenheit, y las vueltas\n", 240 | "print(\"Modelo entrenado!\")" 241 | ], 242 | "metadata": { 243 | "id": "5GxBVfk2JMYS", 244 | "outputId": "2af62b9f-3d67-47dc-e95b-256a92839a56", 245 | "colab": { 246 | "base_uri": "https://localhost:8080/" 247 | } 248 | }, 249 | "execution_count": 11, 250 | "outputs": [ 251 | { 252 | "output_type": "stream", 253 | "name": "stdout", 254 | "text": [ 255 | "Comenzando entrenamiento...\n", 256 | "Modelo entrenado!\n" 257 | ] 258 | } 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "source": [ 264 | "# funcion de perdidad\n", 265 | "plt.xlabel(\"# Epoca\")\n", 266 | "plt.ylabel(\"Magnitud de pérdida\")\n", 267 | "plt.title(\"Mayor capas\")\n", 268 | "plt.plot(historial.history[\"loss\"])" 269 | ], 270 | "metadata": { 271 | "id": "8PqIIxTnJO6Q", 272 | "outputId": "cdf9ebdd-b83c-42fa-f45e-c03e73164635", 273 | "colab": { 274 | "base_uri": "https://localhost:8080/", 275 | "height": 489 276 | } 277 | }, 278 | "execution_count": 12, 279 | "outputs": [ 280 | { 281 | "output_type": "execute_result", 282 | "data": { 283 | "text/plain": [ 284 | "[]" 285 | ] 286 | }, 287 | "metadata": {}, 288 | "execution_count": 12 289 | }, 290 | { 291 | "output_type": "display_data", 292 | "data": { 293 | "text/plain": [ 294 | "
" 295 | ], 296 | "image/png": "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WbNm4fDhw5g+fTq2bNmCrVu32nu4RG6PgYiIZOHn54f58+dj8uTJ6NWr123beXh4QKVSWfVinDp1CqtWraq0/eDBg3H58mX885//RGFhoXR3mUWPHj1gMpnw6aefWm3/+OOPoVKp0L1793s6nieffBL+/v5ITEy8Za4iS0+NJZjd2HMjhMDs2bNv+7o31imEwKeffgovLy907dpVek1bzk9ubu4tr92yZUsAQElJiQ1HSEQ38lS6ACJ6cMTHx9+1Tc+ePTFr1ix069YNAwcORE5ODj777DM88sgjOHDgwC3tW7VqhaZNm2LFihWIiIjAo48+arW/V69e6NKlC959912cOnUKLVq0wE8//YTVq1dj5MiRUk+PvfR6PT7++GO8/PLLaNOmDQYOHIhq1aph//79uHLlCr766is0atQI9evXx7/+9S+cO3cOer0e33//PS5fvlzpa+p0OmzcuBHx8fGIiorChg0bsG7dOrzzzjuoWbOmXednypQp2L59O3r27Im6desiJycH8+bNQ506ddChQ4d7OmYit6bY/W1E5NJuvO3+Tiq77f6LL74QDRo0EFqtVjRq1EgsWrRITJo0SdzuT1JSUpIAID744INK9xcUFIhRo0aJkJAQ4eXlJRo0aCBmzpxpdXu8EBW33Y8YMcKOoxRizZo1on379sLb21vo9XrRtm1bsWzZMmn/4cOHRUxMjPDz8xM1atQQr7zyiti/f78AIBYtWiS1i4+PF76+vuJ///ufePLJJ4WPj48wGAxi0qRJwmQy2X1+UlJSRJ8+fURISIjQaDQiJCREDBgwQBw/ftyu4yOiCiohbhrFSERUxcyePRujRo3CqVOnEBYWpnQ592TIkCH47rvvUFhYqHQpRFQJjiEioipNCIEvvvgCnTt3dtkwRERVH8cQEVGVVFRUhDVr1mDr1q04ePAgVq9erXRJRPQAYyAioirp4sWLGDhwIAIDA/HOO++gd+/eSpdERA8wjiEiIiIit8cxREREROT2GIiIiIjI7XEMkY3MZjPOnz8Pf39/q5WuiYiIqOoSQqCgoAAhISFQq2/fD8RAZKPz588jNDRU6TKIiIjoHpw5cwZ16tS57X4GIhv5+/sDqDiher1e4WqIiIjIFkajEaGhodL3+O0wENnIcplMr9czEBEREbmYuw134aBqIiIicnsMREREROT2GIiIiIjI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\n" 297 | }, 298 | "metadata": {} 299 | } 300 | ] 301 | }, 302 | { 303 | "cell_type": "markdown", 304 | "source": [ 305 | "Si comparamos el modelo entranado de una capa (Ejercio Uno), con el modelo con tres capaz, observamos que obtenemos mejores resultados con este ultimo." 306 | ], 307 | "metadata": { 308 | "id": "fJ-tEjG6JpVJ" 309 | } 310 | }, 311 | { 312 | "cell_type": "code", 313 | "source": [ 314 | "# imprimir el sesgo y peso\n", 315 | "print(oculta1.get_weights())\n", 316 | "print(oculta2.get_weights())\n", 317 | "print(salida.get_weights())" 318 | ], 319 | "metadata": { 320 | "id": "R7UFI_nqItTx", 321 | "colab": { 322 | "base_uri": "https://localhost:8080/" 323 | }, 324 | "outputId": "3ab16fd0-722c-4ce8-bf8e-f45d22a9b4e3" 325 | }, 326 | "execution_count": 13, 327 | "outputs": [ 328 | { 329 | "output_type": "stream", 330 | "name": "stdout", 331 | "text": [ 332 | "[array([[-0.05232973, 0.6475969 , 0.21419732]], dtype=float32), array([2.4080932, 3.6836836, 3.4332693], dtype=float32)]\n", 333 | "[array([[ 0.59000593, 0.30340979, -0.25689414],\n", 334 | " [ 0.9909865 , -0.12906489, -0.6849438 ],\n", 335 | " [ 1.3118681 , -0.18349655, 0.5865532 ]], dtype=float32), array([ 3.7126238, -3.1693513, -3.6881018], dtype=float32)]\n", 336 | "[array([[ 1.4149656],\n", 337 | " [-0.7831404],\n", 338 | " [-1.4033202]], dtype=float32), array([3.6166015], dtype=float32)]\n" 339 | ] 340 | } 341 | ] 342 | } 343 | ] 344 | } --------------------------------------------------------------------------------