Saltar al contenido principal

ScriptScultor: Tallando Soluciones en Código

· 16 min de lectura
Oscar Adrian Ortiz Bustos

Introducción

Como todo programador que se respete, soy una amante de la automatización, entre más automatizado se encuentre algo, mejor es para mí. Incluso dentro de la realización de estos artículos se ven inmiscuidos procesos de automatización, siendo más específico me refiero a la creación de los metadatos para cada artículo, en especial a la estructura de los mismos. A esta técnica revolucionaria (de acuerdo, estoy exagerando) la he llamado ScriptScultor, y en este artículo te explicaré de que se trata y como puedes convertirte en uno.

Banner-Post

Quizá me estoy viniendo arriba muy pronto, pero la realidad es que las interacciones a través de la terminal me encantan. Es por eso que cada que puedo generar un script para que me ayude un poco en las tareas repetitivas, no lo pienso dos veces y lo escribo.

¿Por qué?

Una de las preguntas que la mayoría de las personas me suelen hacer, y la razón es bastante simple. Quizá, y solo quizá, sea un poco flojo. Pero no me malinterpretes, no soy de esas personas que no les gusta trabajar, pero si soy de las personas que no les gusta trabajar en cosas repetitivas, y es que, ¿quién lo hace?. Puede que en algunos casos sea más laborioso hacerlo mediante el uso de scripts, pero la realidad es que a la larga, el tiempo que te ahorras es bastante considerable, además, me gusta complicarme la vida, así que no hay problema.

Si te has leído algunos de mis artículos últimamente te darás cuenta de que una de las principales fuentes de entretenimiento que tengo en la actualidad es el programar, así es, por más pequeño que sea, siempre busco la manera de estar programando.

¿Qué beneficios tiene?

Si bien, el principal beneficio es el ahorro de tiempo, no es el único, ya que, al automatizar procesos, se reduce la posibilidad de cometer errores, y en caso de que estos se cometan, es más fácil de detectarlos, ya que, al ser un proceso automatizado, se puede revisar el código y encontrar el error, en lugar de tener que repetir todo el proceso nuevamente.

Además, me está ayudando bastante a mejorar la lógica de programación, debido a que la belleza del scripting va más allá de la mera automatización; es un entrenamiento constante para el lado lógico de nuestro cerebro, permítanme mencionarles algunas razones por las cuales considero una buena opción ser un ScriptScultor.

  1. Desarrollo de algoritmos: Crear scripts implica pensar en pasos lógicos y secuenciales, cada línea de código es como una pieza de un rompecabezas, encajando perfectamente para lograr el resultado final. Y obviamente este proceso continuo de diseñar algoritmos contribuye significativamente al desarrollo de habilidades algorítmicas, lo que es muy útil para resolver problemas complejos.
  2. Descomposición de tareas: Debido a la naturaleza de la creación de scripts, debemos dividir las tareas más complejas en pasos más manejables, lo que nos ayuda a fomentar el pensamiento lógico al diseñar soluciones paso a paso.
  3. Solución de problemas: Implica abordar problemas específicos y buscar soluciones eficientes, lo que nos ayuda a agudizar la capacidad de analizar y resolver problemas de manera sistemática.
  4. Manejo eficiente de datos: La manipulación de datos es esencial en la programación, con la generación de script aprendemos a manejar variables, listas, diccionarios y otras estructuras de datos para gestionar la información de manera eficiente.
  5. Optimización: A medida que crecemos como _ScriptScultors, vamos buscando la manera de optimizar nuestro código, lo que nos lleva a fortalecer la eficiencia del programa y hacer que cualquier código que escribamos sea más legible para nosotros y los demás desarrolladores.
  6. Creatividad: Es la razón por la que decidí bautizar esta técnica, ya que la resolución de problemas mediante scripts muchas veces requiere de enfoques creativos. Nos acostumbramos a pensar fuera de lo convencional para encontrar soluciones únicas a los desafíos planteados.
  7. Exposición: Entendamos por exposición a la cantidad de tecnologías que podemos aprender dependiendo de la tarea a automatizar, permitiéndonos llenar nuestro Programmer's Toolkit y a su vez siendo más versátiles como desarrolladores.
  8. Práctica: No podía faltar la madre de todas, la creación regular de scripts nos ofrece la práctica constante, lo que nos ayuda a no oxidarnos y consolidar nuestras habilidades de programación a lo largo del tiempo.

Ejemplos

Mucho bla-bla-bla, pero poca acción, les voy a presentar algunos de los scripts que he realizado.

Debo de aclarar varias cosas, la primera es que no esperen una gran creatividad a la hora de nombrarlos, y la segunda es que todos fueron creados para solventar una tarea en específico en determinado momento, por lo que no puede ser funcional para todos.

MetaBuilder

El primero es un wizard para la creación de los metadatos de cada artículo, el cual me permite crearlos de una manera más rápida y sencilla, además de que me permite tener un control más estricto de los mismos. Es bastante sencillo por lo que únicamente les enseñaré el funcionamiento mediante el gif que les dejo a continuación.

MetaBuilder

BlueConnect

Continuo con el que siento que es el que puede llegar a ser más útil para la mayoría. Muchas veces queremos conectar nuestros dispositivos bluetooth de una manera fácil y sencilla; pero no siempre queremos estar abriendo ventana por ventana hasta llegar al gestor, y aunque muchas veces dentro de nuestra barra de estado se nos presenta el ícono para conectarlo, en mi caso no lo es. Creo que nunca lo he mencionado, pero utilizo Xfce como escritorio, debido a su ligereza y a que lo único que necesito es la terminal.

Me refiero a BlueConnect, el cual fue hecho debido a que quería gestionar mis bocinas bluetooth de una manera sencilla desde la terminal, lo diseñé para simplificar la conexión de dispositivos Bluetooth en entornos Linux (obviamente).

Advertencia

Este script fue probado única y exclusivamente en mi ordenador, por lo que puede no ser compatibles con otros.

#!/bin/bash

# BlueConnect es un script de Bash diseñado para simplificar la conexión de dispositivos Bluetooth en entornos Xfce, especialmente útil para aquellos que prefieren la eficiencia de la línea de comandos sobre las interfaces gráficas.
# ./blueconnect.sh
#


# Si se pasa el argumento disconnect, desconectar el dispositivo
if [ "$1" == "disconnect" ]; then
echo "Desconectando el dispositivo ..."
echo -e "disconnect\nquit" | bluetoothctl &> /dev/null
echo "¡El dispositivo se ha desconectado exitosamente!"
exit 0
fi

# Comprobar si el equipo cuenta con Bluetooth
if [ $(hciconfig | grep -c "hci") -gt 0 ]; then
echo "El equipo cuenta con Bluetooth"

# Comprobar si el equipo cuenta con bluez
if [ $(dpkg -l | grep -c "bluez") -gt 0 ]; then
echo "Bluez ya esta instalado en el equipo"
else
echo "El equipo no cuenta con bluez"
echo "Instalando bluez ..."
sudo apt-get install bluez
fi
# Verificar si el servicio de bluetooth está activo
if systemctl is-active --quiet bluetooth; then
echo "El servicio de bluetooth está activo"
else
echo "El servicio de bluetooth no está activo"
echo "Iniciando el servicio de bluetooth ..."
sudo systemctl start bluetooth
fi

# Verificar si el bluetooth está encendido
if rfkill list bluetooth | grep -q "Soft blocked: no" && rfkill list bluetooth | grep -q "Hard blocked: no"; then
echo "El bluetooth está encendido"
else
echo "El bluetooth está apagado"
echo "Encendiendo el bluetooth ..."
sudo rfkill unblock bluetooth
fi

# Lista de dispositivos cercanos
sleep 1 # Esperar un segundo para actualizar la lista de dispositivos
echo "Lista de dispositivos cercanos:"
hcitool scan

# Ingrese el nombre del dispositivo a conectar
echo "Ingrese el nombre del dispositivo a conectar:"
read device_name

# Obtener la dirección MAC del dispositivo
device_address=$(hcitool scan | grep -i $device_name | awk '{print $1}')
# Conectar al dispositivo
echo "Conectando al dispositivo $device_name con dirección MAC $device_address ..."
if echo -e "connect $device_address\nquit" | bluetoothctl &> /dev/null; then
sleep 1 # Esperar un segundo para actualizar la información de la conexión
if bluetoothctl info $device_address | grep "Connected: yes" &> /dev/null; then
echo "¡El dispositivo se ha conectado exitosamente!"
sleep 1 # Esperar un segundo para actualizar la información de la conexión
echo "Estableciendo como dispositivo de audio ..."
if pactl list short sinks | grep "bluez_sink.$(echo $device_address | tr ":" "_" ).a2dp_sink" &> /dev/null; then
echo "¡El dispositivo se ha establecido como dispositivo de audio exitosamente!"
else
echo "¡Error al establecer el dispositivo como dispositivo de audio!"
fi
else
echo "¡Error al conectar al dispositivo!"
fi
else
echo "¡Error al conectar al dispositivo!"
fi

else
echo "El equipo no cuenta con Bluetooth"
fi

WallChanger

El siguiente es uno que tengo activo hoy día en mi equipo, debido a que me gusta que el ordenador se vea dinámico y que mejor formar de hacerlo que estar cambiando periódicamente el fondo de pantalla. Ojito, para este se necesita tener un cronjob activado dependiendo de cada cuando quieres ejecutar el script, además de una APIKey por parte de _Unsplash. Yo lo tengo cada 30 minutos. Además, tengo distintos "sets de imágenes" para poder intercambiar dependiendo la fecha, así es, ahorita tengo el navideño.

#!/bin/bash

# Este script cambia el wallpaper de tu escritorio cada 10 minutos, las imágenes son aleatorias y no se repiten.
# Se debe exportar la variable "UNPLASH_ACCESS_KEY" con tu access key de Unplash, para obtener una visita https://unsplash.com/developers
# Ejemplo: export UNPLASH_ACCESS_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Lo puedes agregar al final de tu archivo .bashrc o .zshrc dependiendo de tu shell.

# Debug mode
# set -x
# set -e
# set -u
# set -o pipefail
# set -o noclobber
# set -o nounset

# Temas adicionales
nature="nature%2Clandscape%2Cmountain%2Cforest%2Cbeach%2Csunset%2Csunrise%2Cclouds%2Cwaterfall%2Cflowers%2Ctrees%2Crivers%2Clakes%2Csnow%2Cdesert%2Cfields%2Cparks%2Cwildlife%2Canimals"
cities="cities%2Ccityscape%2Curban%2Cskyscrapers%2Cbuildings%2Cstreets%2Ctraffic%2Cnightlife%2Carchitecture%2Cmetro%2Csubway%2Ctrain%2Ctaxis"
food="food%2Crestaurant%2Ccoffee%2Cpizza%2Csushi%2Ccuisine%2Cdessert%2Cchocolate%2Cburger%2Cpasta%2Cice%20cream%2Cfruit%2Cvegetables"
travel="travel%2Cvacation%2Choliday%2Ctrip%2Cadventure%2Cexploration%2Ctourism%2Ctourist%2Cjourney%2Cbackpacking%2Cpassport%2Cairplane%2Cairport%2Cpassport%2Csuitcase"
animals="animals%2Cpets%2Cdogs%2Ccats%2Cbirds%2Chorses%2Cwild%20animals%2Cmammals%2Creptiles%2Camphibians%2Cfish%2Cmarine%20life%2Cinsects%2Cbutterflies"
technology="technology%2Ccomputers%2Claptops%2Csmartphone%2Cinternet%2Ccoding%2Cprogramming%2Cdata%2Crobotics%2Ccybersecurity%2Cartificial%20intelligence"
abstract="abstract%2Ctexture%2Cpatterns%2Ccolors%2Cart%2Cdesign%2Cmodern%2Ccontemporary%2Cdigital%2Cconceptual%2Ccreative%2Cminimalism"
movies="movies%2Cfilm%2Ccinema%2Cactors%2Cactresses%2Cdirectors%2Cmovies%20posters%2Cmovie%20scenes%2Cfilm%20making%2Chollywood"
music="music%2Cmusical%2Cinstruments%2Cconcert%2Cfestival%2Cband%2Csinger%2Cmusic%20performance%2Cdance%2Cdj%2Crock%2Cpop%2Cjazz"
sports="sports%2Cathletes%2Cfootball%2Csoccer%2Cbasketball%2Ctennis%2Cgolf%2Cswimming%2Crunning%2Ccycling%2Csurfing%2Csnowboarding%2Cyoga"
christmas="christmas%2Cchristmas%20tree%2Cchristmas%20lights%2Cchristmas%20ornaments%2Cchristmas%20decorations%2Cchristmas%20decor%2Cchristmas%20decoration"
halloween="halloween%2Challoween%20costume%2Challoween%20costumes%2Challoween%20decorations%2Challoween%20decor%2Challoween%20decoration%2Challoween%20decorating%2Challoween%20decorated%2Challoween%20decorating%20ideas%2Challoween%20decorating%20idea%2Challoween%20decorating%20inspiration%2Challoween"
space="space%2Cspace%20wallpaper%2Cspace%20wallpapers%2Cspace%20background%2Cspace%20backgrounds%2Cspace%20galaxy%2Cspace%20galaxies%2Cspace%20nebula%2Cspace"

# Variables para los campos de la petición a la API de Unplash
UNSPLASH_QUERY="$christmas"
#UNSPLASH_QUERY="$movies%2C$nature%2C$animals%2C$travel%2C$cities%2C$food%2C$technology%2C$abstract%2C$sports%2C$christmas%2C$halloween%2C$space"
UNSPLASH_ORIENTATION="landscape"
# Concatenación de los campos de la petición
curl -s -H "Authorization: Client-ID $UNSPLASH_ACCESS_KEY" "https://api.unsplash.com/photos/random?orientation=$UNSPLASH_ORIENTATION&query=$UNSPLASH_QUERY" | jq -r '.urls.full' | xargs wget -qO "$HOME/.wallpapers/wallpaper.jpg"

Hashify

El último que les quiero mostrar es uno que hice hace relativamente poco para la clase de Seguridad Informática, ya que estábamos abordando el tema de la encriptación con SHA256 y se me ocurrió que para la clase podríamos usarlo para ejemplificar como se calculan los checksum. Es algo verdaderamente sencillo, pero que hace apología a lo que mencionaba anteriormente, de que cada script soluciona una problemática en concreto en un determinado tiempo:

#!/bin/bash

# Este script comprueba que el hash Sha256 de un archivo concida con el hash de referencia
# Tiene dos parámetros: el nombre del archivo y el hash de referencia
#Author: 4DRIAN0RTIZ
#Fecha: 09/09/2023

# Ejemplo de uso: ./hashify.sh <archivo> <hash>

# Colores para los mensajes de salida
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
PURPLE='\033[0;35m'
BROWN='\033[0;33m'
BLUE='\033[0;34m'
END_COLOR='\033[0m'

# Declaración de variables
sha_archivo=$(sha256sum $1 | awk '{print $1}')
sha_referencia=$(awk '{print $1}' $2)

# Comprueba que el número de parámetros es correcto

if [ $# -ne 2 ]; then
echo -e "${RED}Error: Número de parámetros incorrecto${END_COLOR}"
echo -e "${YELLOW}Uso: ./hashify.sh <archivo> <hash>${END_COLOR}"
exit 1
fi

# Comprueba que el archivo existe

if [ ! -f $1 ]; then
echo -e "${RED}Error: El archivo $1 no existe${END_COLOR}"
exit 1
fi
# Comprueba que el hash de referencia existe
if [ ! -f $2 ]; then
echo -e "${RED}Error: El archivo $2 no existe${END_COLOR}"
exit 1
fi

# Comprueba que el hash Sha256 del archivo coincide con el hash de referencia
if [ $sha_archivo == $sha_referencia ]; then
echo -e "${GREEN}El hash del archivo $1 coincide con el hash de referencia${END_COLOR}"
else
echo -e "${RED}El hash del archivo $1 no coincide con el hash de referencia${END_COLOR}"
echo -e "${YELLOW}Hash del archivo: $sha_archivo${END_COLOR}"
echo -e "${YELLOW}Hash de referencia: $sha_referencia${END_COLOR}"
fi

exit 0

ScriptScultor en la vida real

Hasta el momento solo les he mostrado scripts que no pueden ser consideras en un ambiente laboral, sin embargo, en este ámbito también he podido pulir cada día mis habilidades. Actualmente, me encuentro laborando en una empresa que requiere estar actualizando los productos que ofrece de manera periódica y siendo sincero, es algo bastante tedioso de realizar, ya que se vuelve repetitivo, y aquí es donde entran las habilidades de un ScriptScultor.

Me encargué de generar un script en python que se encargue de:

  1. Iniciar sesión como administrador.
  2. Ir al apartado de productos.
  3. Tomar el modelo del producto de una fila de excel y colocarlo en el buscador.
  4. Abrir el editor de producto.
  5. Copiar las especificaciones necesarias en los campos solicitados.
  6. Guardar en un archivo los modelos que han sido modificados.
  7. Guardar los cambios en el producto.

Lo que se iba a realizar en un día de manera manual, lo pude recortar a tan solo 60 minutos, siendo un hito bastante bueno para mí. Por cierto, le pusimos de nombre mechaSlave.

import time
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains

# Leer el archivo Excel
df = pd.read_excel('mecha.xlsx', engine='openpyxl')

# Configuración de Selenium
driver = webdriver.Chrome()
url_inicio_sesion = 'https://noquieroquemedenuncien.asique.censuroesto.com'
products_page = 'https://noquieroquemedenuncien.asique.censuroesto.com'
driver.get(url_inicio_sesion)
wait_time = 5


# Función para iniciar sesión
def iniciar_sesion():
driver.get(url_inicio_sesion)
driver.implicitly_wait(wait_time)
username_I = driver.find_element(By.ID, 'input-username')
password_I = driver.find_element(By.ID, 'input-password')
########### Es para uso interno, así que no me crucifiquen
username_I.send_keys('ciberseguridad')
password_I.send_keys('ciberseguridadatope.')
############ por poner las credenciales de esa manera.
driver.find_element(By.CSS_SELECTOR, '.btn-primary').click()

def abrir_product_page():
menu_catalog = driver.find_element(By.ID, 'menu-catalog')
menu_catalog.find_element(By.CLASS_NAME, 'parent.collapsed').click()
menu_catalog_collapse = menu_catalog.find_element(By.ID, 'collapse1')
menu_catalog_collapse.find_elements(By.TAG_NAME, 'li')[1].click()

iniciar_sesion()
abrir_product_page()

# Recorrer el DataFrame y realizar la búsqueda
for index, row in df.iterrows():
modelo = row['model']
input_model = driver.find_element(By.ID, 'input-model')
filter_btn = driver.find_element(By.ID, 'button-filter')
try:
input_model.clear()
input_model.send_keys(modelo)
filter_btn.click()
driver.implicitly_wait(wait_time)
tbody = driver.find_element(By.TAG_NAME, 'tbody')
tr = tbody.find_element(By.TAG_NAME, 'tr')
td = tr.find_elements(By.TAG_NAME, 'td')[7]
a = td.find_element(By.TAG_NAME, 'a').click()
print("Llegaste a la página del producto " + modelo)
nombre_producto = driver.find_element(By.ID, 'input-name2').get_attribute('value')
meta_tag_description = driver.find_element(By.ID, 'input-meta-description2').get_attribute('value')
campo_ds = driver.find_element(By.CSS_SELECTOR, '.note-editable.panel-body')
campo_ds.clear()
template = f"{nombre_producto}\nEspecificaciones:\n"
campo_ds.send_keys(template)
ActionChains(driver).key_down(Keys.CONTROL).key_down(Keys.SHIFT).send_keys('7').key_up(Keys.CONTROL).key_up(Keys.SHIFT).perform()

for linea in meta_tag_description.split('\n'):
linea = linea.replace('-', '')
driver.find_element(By.CSS_SELECTOR, '.note-editable.panel-body').send_keys(linea + '\n')

ActionChains(driver).send_keys(Keys.BACKSPACE).perform()
print("Llegaste a la página del producto e ingresaste la descripción " + modelo)
ul = driver.find_element(By.ID, 'language')
ul.find_elements(By.TAG_NAME, 'li')[1].click()
driver.find_element(By.ID, 'input-meta-title1').clear()
driver.find_element(By.ID, 'input-meta-title1').send_keys(nombre_producto)
print("Ya colocaste el nombre del producto en el lenguaje inglés")
print("Guardando cambios del producto " + modelo)
driver.find_element(By.CSS_SELECTOR, '.btn.btn-primary').click()

with open(f"Modelos_Guardados.txt", "a") as file:
file.write(modelo + '\n')
except:
print("Parece que hubo un error con el producto " + modelo + " Pasando al siguiente")
print("Ya terminé de hacer todo lo que me pediste, ahora me voy a dormir, y la queso")
print("Espero hayas hecho una copia de seguridad, porque si no, te vas a arrepentir")
driver.quit()

Algo que me quedó bastante grabado en la cabeza cuando le mostré el funcionamiento del script a mi actual jefa, además de su cara de asombro y alivio al ver que no tendría que hacer todo eso manualmente, fue la siguiente frase:

"Que bueno que te contratamos"

Palabras simples, pero que fueron más que suficientes para hacerme sentir que mi trabajo estaba siendo valorado.

Muchas veces, el arte de tallar código se subestima en el ambiente laboral. La eficacia que aporta a las tareas diarias puede llegar a pasar desapercibida, especialmente cuando la empresa no está familiarizada con este tipo de prácticas. Me he dado cuenta de que incluso pueden llegar a pensar que soy "Ocioso" por el simple hecho de no estar haciendo el trabajo yo; sino el script que he creado.

La realidad es que la automatización a través del scripting es una herramienta poderosa que puede transformar radicalmente la productividad. Aunado a esto, es fundamental que se reconozca que a aparente "inactividad" de un ScriptScultor no significa falta de productividad. De hecho, es todo lo contrario; ya que en esos momentos de "quietud" nos encontramos diseñando, mejorando scripts en nuestra cabeza.

Así que, la próxima vez que me encuentren aparentemente "sin hacer nada", recuerden que estoy trabajando diligentemente detrás de escenas, creando scripts que hacen que las operaciones diarias sean más eficientes y efectivas. El poder del scripting va más allá de la pantalla y deja una huella positiva en el rendimiento laboral.

Sé uno

Es fundamental recordar que el arte de tallar soluciones en código lleva tiempo y paciencia. No te desanimes si al principio encuentras obstáculos o cometes errores, eso es parte del viaje.

Lo que les puedo recomendar a las personas que estén interesadas en este mundo del scripting es que no tengan temor a probar nuevas ideas modificando los scripts, ya que la verdadera maestría viene con la experiencia, la experiencia surge de enfrentar desafíos y aprender de ellos. Es normal sentir cierta aprensión al principio, pero no temas arruinar las cosas, la belleza de la programación radica en la capacidad de iterar y mejorar.

En mis inicios en este mundo arruiné varias veces mi SO debido a la falta de experiencia, pero conforme iba practicando y viendo que es lo que podía y que no podía hacer es que fui perfeccionando mis habilidades; y no es que me considere un experto en scripting, ni de lejos, solo intento convencerlos de que no es tan grave como parece el intentarlo.

Conclusión

Desde La Cueva del NeanderTech queremos mencionar que el término de ScriptScultor no es simplemente una técnica de automatización, sino un arte que va más allá de tallar líneas de código. A través de la creación de Scripts, he descubierto un método para mejorar la lógica de programación al descomponer tareas complejas en pasos más específicos e impulsar el pensamiento algorítmico. Me encuentro redactando esto justo después de haber corrido un script que me ahorró bastante tiempo en el ambiente laboral, no es mentira cuando les digo que el hacer de estas prácticas un hobby será beneficioso en gran medida para cualquiera.

Invito a todos y cada uno de los cibernícolas a adoptar una mentalidad más relajada, a lo que me gusta llamar "Hippie Digital" es decir abrazar a una mente más relajada y disfrutar del proceso creativo que supone la realización de cada parte del código; sabiendo como fluir con las complejidades del desarrollo de software. Espero que este pequeño artículo los motive para poder adentrarse a este magnífico mundo, si fue así cómpartelo con alguien que creas que le será útil o déjame un comentario en la parte de abajo.

O eres tú quien crea la automatización o te estás automatizando.

— Tom Preston-Werner