├── 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": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAGwCAYAAABIC3rIAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABMsElEQVR4nO3deXhTVf4/8HfSNOmadKNpoQtFEFoW2UsUcBwqVauyjeNSEVn0AYoKOILMCDKili+4gYKIOuD8ZFFGUdmtRUCgFCgUSoGCUi1LF6C0aQtts9zfHyGXRgo0kOSm5P16njxN7j25+eR2pO8595xzZYIgCCAiIiLyYHKpCyAiIiKSGgMREREReTwGIiIiIvJ4DERERETk8RiIiIiIyOMxEBEREZHHYyAiIiIij6eQuoDmwmw248yZMwgMDIRMJpO6HCIiImoCQRBQVVWFli1bQi6/dj8QA1ETnTlzBtHR0VKXQURERDfh5MmTiIqKuuZ+BqImCgwMBGA5oWq1WuJqiIiIqCn0ej2io6PFv+PXwkDURNbLZGq1moGIiIiombnRcBcOqiYiIiKPx0BEREREHo+BiIiIiDweAxERERF5PAYiIiIi8ngMREREROTxGIiIiIjI4zEQERERkcdjICIiIiKPx0BEREREHo+BiIiIiDweAxERERF5PN7cVWKVFw3Q1xqg9vGGxs9b6nKIiIg8EnuIJPb2+iPoN+dnfJn9h9SlEBEReSwGIokpFZZfQZ3RLHElREREnouBSGLeXpZfgcHEQERERCQVBiKJWXuI6tlDREREJBkGIokxEBEREUmPgUhiSi8ZAF4yIyIikhIDkcTYQ0RERCQ9BiKJKS8Pqq5jDxEREZFkGIgk5n25h8jAHiIiIiLJMBBJzNpDVM8eIiIiIskwEEmMY4iIiIikx0AkMSUXZiQiIpIcA5HE2ENEREQkPQYiifFeZkRERNJjIJKYNwdVExERSY6BSGLWHiKOISIiIpIOA5HExGn3vGRGREQkGQYiiXFQNRERkfQYiCR2Zdq9IHElREREnouBSGLsISIiIpIeA5HEGs4yEwT2EhEREUmBgUhi1h4igJfNiIiIpMJAJDFVg0DEtYiIiIikwUAkMeslM4DjiIiIiKTCQCQxL7kMXnIZAC7OSEREJBUGIjfg7WUJROwhIiIikobkgej06dN4+umnERoaCl9fX3Tu3Bl79+4V9wuCgBkzZiAyMhK+vr5ISkrC8ePHbY5RXl6O1NRUqNVqBAUFYfTo0aiurrZpc/DgQfTr1w8+Pj6Ijo7GnDlzXPL9msK6FhFv8EpERCQNSQPRhQsXcM8998Db2xsbNmzA4cOH8e677yI4OFhsM2fOHMyfPx+LFi1CdnY2/P39kZycjNraWrFNamoq8vPzkZGRgbVr12Lbtm14/vnnxf16vR4DBw5EbGwscnJyMHfuXMycOROLFy926fe9FqXCCwAvmREREUlGkNDUqVOFvn37XnO/2WwWIiIihLlz54rbKioqBJVKJaxYsUIQBEE4fPiwAEDYs2eP2GbDhg2CTCYTTp8+LQiCICxcuFAIDg4W6urqbD67ffv2Ta61srJSACBUVlY2+T1NpXv7JyF26loht+iCw49NRETkyZr691vSHqIffvgBPXv2xGOPPYbw8HB069YNn376qbi/sLAQJSUlSEpKErdpNBokJiYiKysLAJCVlYWgoCD07NlTbJOUlAS5XI7s7GyxTf/+/aFUKsU2ycnJKCgowIULFxqtra6uDnq93ubhLOJq1ewhIiIikoSkgejEiRP4+OOP0a5dO2zatAnjxo3Diy++iC+++AIAUFJSAgDQarU279NqteK+kpIShIeH2+xXKBQICQmxadPYMRp+xp+lp6dDo9GIj+jo6Fv8ttdmDUQGjiEiIiKShKSByGw2o3v37nj77bfRrVs3PP/883juueewaNEiKcsCAEybNg2VlZXi4+TJk077LOtaRHXsISIiIpKEpIEoMjISCQkJNtvi4+NRVFQEAIiIiAAAlJaW2rQpLS0V90VERKCsrMxmv9FoRHl5uU2bxo7R8DP+TKVSQa1W2zychTd4JSIikpakgeiee+5BQUGBzbZjx44hNjYWABAXF4eIiAhkZmaK+/V6PbKzs6HT6QAAOp0OFRUVyMnJEdts3rwZZrMZiYmJYptt27bBYDCIbTIyMtC+fXubGW1SsU675ywzIiIiaUgaiCZNmoRdu3bh7bffxq+//orly5dj8eLFSEtLAwDIZDJMnDgRb775Jn744Qfk5eXhmWeeQcuWLTF48GAAlh6lBx54AM899xx2796NHTt2YMKECXjiiSfQsmVLAMBTTz0FpVKJ0aNHIz8/H1999RXmzZuHyZMnS/XVbbCHiIiISFoKKT+8V69eWL16NaZNm4Y33ngDcXFx+OCDD5Camiq2mTJlCmpqavD888+joqICffv2xcaNG+Hj4yO2WbZsGSZMmIABAwZALpdj2LBhmD9/vrhfo9Hgxx9/RFpaGnr06IGwsDDMmDHDZq0iKVl7iBiIiIiIpCETBEGQuojmQK/XQ6PRoLKy0uHjicZ9mYMNh0owa1BHDNe1duixiYiIPFlT/35LfusOajDLjD1EREREkmAgcgNcmJGIiEhaDERu4MrCjLx6SUREJAUGIjcgDqo2mSSuhIiIyDMxELkBTrsnIiKSFgORG7iyMCMvmREREUmBgcgNcJYZERGRtBiI3AAvmREREUmLgcgNiLPMOO2eiIhIEgxEbkDpJQPAHiIiIiKpMBC5AS7MSEREJC0GIjfAS2ZERETSYiByA5xlRkREJC0GIjcgrlTNQERERCQJBiI3wEtmRERE0mIgcgPsISIiIpIWA5Eb4CwzIiIiaTEQuQHroGoDe4iIiIgkwUDkBthDREREJC0GIjdgDUScdk9ERCQNBiI3YB1UzVlmRERE0mAgcgO82z0REZG0GIjcgLWHyCwARvYSERERuRwDkRvwVlz5NRhMgoSVEBEReSYGIjdg7SECeNmMiIhICgxEbsDbSyY+rzOZJKyEiIjIMzEQuQGZTNZgphkvmREREbkaA5Gb4EwzIiIi6TAQuQkGIiIiIukwELkJ6zgiLs5IRETkegxEboK37yAiIpIOA5GbsA6q5iUzIiIi12MgchPevJ8ZERGRZBiI3ISKl8yIiIgkw0DkJlQKLwC8ZEZERCQFBiI3ofK29hBxpWoiIiJXYyByEyquQ0RERCQZBiI3wWn3RERE0mEgchPWMUS8ZEZEROR6DERuQpxlZmAPERERkatJGohmzpwJmUxm8+jQoYO4v7a2FmlpaQgNDUVAQACGDRuG0tJSm2MUFRUhJSUFfn5+CA8PxyuvvAKj0WjTZsuWLejevTtUKhXatm2LpUuXuuLr2UUcQ8R1iIiIiFxO8h6ijh07ori4WHxs375d3Ddp0iSsWbMGq1atwtatW3HmzBkMHTpU3G8ymZCSkoL6+nrs3LkTX3zxBZYuXYoZM2aIbQoLC5GSkoL77rsPubm5mDhxIsaMGYNNmza59HveiMrbesmMgYiIiMjVFJIXoFAgIiLiqu2VlZX4/PPPsXz5cvz1r38FACxZsgTx8fHYtWsX+vTpgx9//BGHDx/GTz/9BK1Wi65du2LWrFmYOnUqZs6cCaVSiUWLFiEuLg7vvvsuACA+Ph7bt2/H+++/j+TkZJd+1+ux3rqjzsAxRERERK4meQ/R8ePH0bJlS7Rp0wapqakoKioCAOTk5MBgMCApKUls26FDB8TExCArKwsAkJWVhc6dO0Or1YptkpOTodfrkZ+fL7ZpeAxrG+sxrqWurg56vd7m4UxcqZqIiEg6kgaixMRELF26FBs3bsTHH3+MwsJC9OvXD1VVVSgpKYFSqURQUJDNe7RaLUpKSgAAJSUlNmHIut+673pt9Ho9Ll26dM3a0tPTodFoxEd0dPStft3rsi7MyHWIiIiIXE/SS2YPPvig+LxLly5ITExEbGwsvv76a/j6+kpYGTBt2jRMnjxZfK3X650aiq5Mu2cgIiIicjXJL5k1FBQUhDvvvBO//vorIiIiUF9fj4qKCps2paWl4pijiIiIq2adWV/fqI1arb5u6FKpVFCr1TYPZ7pyyYxjiIiIiFzNrQJRdXU1fvvtN0RGRqJHjx7w9vZGZmamuL+goABFRUXQ6XQAAJ1Oh7y8PJSVlYltMjIyoFarkZCQILZpeAxrG+sx3AVXqiYiIpKOpIHoH//4B7Zu3Yrff/8dO3fuxJAhQ+Dl5YUnn3wSGo0Go0ePxuTJk/Hzzz8jJycHI0eOhE6nQ58+fQAAAwcOREJCAoYPH44DBw5g06ZNeO2115CWlgaVSgUAGDt2LE6cOIEpU6bg6NGjWLhwIb7++mtMmjRJyq9+FfGSGRdmJCIicjlJxxCdOnUKTz75JM6fP48WLVqgb9++2LVrF1q0aAEAeP/99yGXyzFs2DDU1dUhOTkZCxcuFN/v5eWFtWvXYty4cdDpdPD398eIESPwxhtviG3i4uKwbt06TJo0CfPmzUNUVBQ+++wzt5pyDzS4ZMaFGYmIiFxOJgiCIHURzYFer4dGo0FlZaVTxhP9cvwshn++Gx0iArFxYn+HH5+IiMgTNfXvt1uNIfJk1ktmnHZPRETkegxEboKDqomIiKTDQOQmuFI1ERGRdBiI3ATXISIiIpIOA5Gb4N3uiYiIpMNA5Casd7uvN5rBiX9ERESuxUDkJqw3dwXYS0RERORqDERuwjqGCADquTgjERGRSzEQuQnrJTOAt+8gIiJyNQYiNyGTyTjTjIiISCIMRG6EizMSERFJ46Zv7nrx4kUUFRWhvr7eZnuXLl1uuShPpVJ4oQpG3r6DiIjIxewORGfPnsXIkSOxYcOGRvebTLzcc7O4WjUREZE07L5kNnHiRFRUVCA7Oxu+vr7YuHEjvvjiC7Rr1w4//PCDM2r0GNap93UGhkoiIiJXsruHaPPmzfj+++/Rs2dPyOVyxMbG4v7774darUZ6ejpSUlKcUadHsN7xnj1ERERErmV3D1FNTQ3Cw8MBAMHBwTh79iwAoHPnzti3b59jq/MwHFRNREQkDbsDUfv27VFQUAAAuOuuu/DJJ5/g9OnTWLRoESIjIx1eoCexjiHioGoiIiLXsvuS2UsvvYTi4mIAwOuvv44HHngAy5Ytg1KpxNKlSx1dn0fhOkRERETSsDsQPf300+LzHj164I8//sDRo0cRExODsLAwhxbnaTiGiIiISBo3vQ6RlZ+fH7p37+6IWjweZ5kRERFJo0mBaPLkyU0+4HvvvXfTxXg61eX7mfHmrkRERK7VpEC0f/9+m9f79u2D0WhE+/btAQDHjh2Dl5cXevTo4fgKPciVHiIGIiIiIldqUiD6+eefxefvvfceAgMD8cUXXyA4OBgAcOHCBYwcORL9+vVzTpUegmOIiIiIpGH3tPt3330X6enpYhgCLOsRvfnmm3j33XcdWpyn4SwzIiIiadgdiPR6vbgYY0Nnz55FVVWVQ4ryVEquQ0RERCQJuwPRkCFDMHLkSHz77bc4deoUTp06hW+++QajR4/G0KFDnVGjx+DNXYmIiKRh97T7RYsW4R//+AeeeuopGAwGy0EUCowePRpz5851eIGehGOIiIiIpGF3IPLz88PChQsxd+5c/PbbbwCAO+64A/7+/g4vztOIs8w4hoiIiMilbnphRn9/f3Tp0sWRtXg88ZIZp90TERG5VJMC0dChQ7F06VKo1eobjhP69ttvHVKYJxIHVXNhRiIiIpdqUiDSaDSQyWTic3IOcQwRe4iIiIhcqkmBaMmSJY0+J8fiOkRERETSsHvaPTkPZ5kRERFJo0k9RN26dRMvmd3Ivn37bqkgT2adZcaFGYmIiFyrSYFo8ODB4vPa2losXLgQCQkJ0Ol0AIBdu3YhPz8f48ePd0qRnkLpxYUZiYiIpNCkQPT666+Lz8eMGYMXX3wRs2bNuqrNyZMnHVudh+E6RERERNKwewzRqlWr8Mwzz1y1/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 | }
--------------------------------------------------------------------------------