Pandas potenciado Encriptando archivos de Excel escritos desde DataFrames

Pandas ahora puede encriptar archivos de Excel generados desde DataFrames.

Presentación de una clase ExcelHelper que le permite cifrar archivos de Excel con una contraseña fuerte o una contraseña de su elección

Escribiendo en Excel y cifrándolo (Imagen del autor)

Introducción

En este artículo, compartiré cómo incorporar una clase ExcelHelper para abrir y cifrar el archivo de Excel después de escribir los marcos de datos en Excel. He incluido esta capacidad de cifrado en la función to_excel() en mi artículo anterior.

Pandas supercargado: Lectura y escritura en Excel

Mejorando los métodos .read_excel y .to_excel para permitirle centrarse en la exploración de datos

towardsdatascience.com

Para los científicos de datos y entusiastas del aprendizaje automático que están leyendo esto, es probable que lo encuentren útil ya que acelerará su trabajo al exportar marcos de datos y exportar a Excel.

Motivación

En un proyecto reciente, tuve que analizar datos y preparar estadísticas para algunas personas. Como los datos contenían información confidencial, era necesario proteger los archivos con contraseña. Esto está muy alineado con mi conjunto de habilidades y si ha leído mi artículo anterior, dentro de pypo.py, ya tengo una función to_excel() que abre el archivo de Excel después de que ha sido creado por el método df.to_excel(). Si bien esto me ha funcionado bien, parece un buen momento para reconsiderar cómo se implementó y también agregar la capacidad de proteger con contraseña el archivo de Excel.

Contenido

  1. Apertura y cifrado del archivo de Excel
  2. Generación de una contraseña fuerte
  3. Poniéndolo todo junto

Código completo aquí.

Parte 1 – Apertura y cifrado del archivo de Excel

Cuando se trabaja con Python y Pandas, hay buenas razones para abrir el archivo de Excel, por ejemplo, inspeccionarlo visualmente durante las pruebas o formatearlo antes de enviarlo a las partes interesadas. Si hay una necesidad adicional de cifrar el archivo de Excel, entonces habría 3 escenarios para manejar: solo abrir, solo cifrar, abrir y cifrar. Si no estamos abriendo ni cifrando el archivo de Excel, entonces no se necesita hacer nada ya que df.to_excel() sería suficiente.

ExcelHelper es una clase escrita para lanzar Excel (la aplicación) y luego abrir el libro de trabajo basado en la ruta proporcionada. Programáticamente, esto es un proceso de 2 pasos. La mayoría de las personas nunca se dan cuenta porque la aplicación de Excel y el libro de trabajo se lanzan juntos cuando se hace doble clic en un archivo de Excel.

Inicializar la clase ExcelHelper

  • __init__(self, launch=True, encrypt=False, password=None, length=20, quit_=True) Esta es la llamada de inicialización para ExcelHelper.
  • Si launch es igual a True, el libro de trabajo se muestra después de que se hace el cifrado.
  • Si encrypt es igual a True, se llama al método self._encrypt(), que se explicará más adelante.
  • password permite al usuario ingresar una contraseña preferida, de lo contrario sugerirá automáticamente una contraseña fuerte con length número de caracteres, donde la longitud máxima es 255.

Abrir libro de trabajo

  • _open_wb(self, path, visible=False) convierte la ruta dada en una ruta absoluta y luego la abre. Convertir una ruta en una ruta absoluta es necesario de lo contrario las aplicaciones despachadas por win32com.client no pueden encontrar el archivo. (Anteriormente, usé un bloque try-except para agregar la ruta con el directorio de trabajo actual, pero eso es innecesariamente detallado y lleva un poco de tiempo entender realmente lo que se está tratando de hacer.)
  • visible controla si la aplicación es visible para el usuario. En general, tiene sentido mostrar la aplicación solo después de que se haya completado el cifrado. Por lo tanto, si estamos lanzando y cifrando, debemos establecer visible = True solo después de que se haya hecho self._encrypt().

Encriptar Excel

  • _encrypt(self, visible=False) encripta el libro de trabajo de Excel y luego muestra la aplicación configurando el atributo self.xl.Visible después de que se complete la encriptación.
  • Establecer self.xl.DisplayAlerts en True es importante, de lo contrario, el archivo de Excel lanzado no dará ninguna alerta (por ejemplo, si presiona Ctrl+F e intenta encontrar algún mensaje sin sentido y no habrá ninguna advertencia 😱; me sucedió y estaba realmente confundido!).

Método Ejecutar

  • execute(self, path, launch, encrypt, quit_) maneja los 3 escenarios descritos anteriormente.
  • El argumento quit_ cierra la aplicación de Excel (el guión bajo final es una convención para denotar que quit es una palabra clave reservada en Python). Cuando se inicia ExcelHelper, si launch=False, la aplicación de Excel se ejecuta en segundo plano y el archivo de Excel se abre. Si el usuario hace doble clic en el archivo de Excel, se le solicitará que solo se puede abrir en modo de solo lectura. Es bastante difícil para el usuario no técnico cerrar el archivo; el truco sería abrir el Administrador de tareas, seleccionar el programa de Excel y luego finalizar la tarea. Por lo tanto, es necesario llamar a .Quit() para terminar la aplicación de Excel. Podríamos haber cerrado simplemente el libro de trabajo, pero tal vez no hay necesidad de manejar esto tan finamente por ahora.

Parte 2 — Generar una contraseña segura

Inicialmente, estaba usando from cryptography.fernet import Fernet; Fernet.generate_key() para generar contraseñas aleatorias. Si bien varios usuarios se sorprendieron gratamente por la longitud y la aleatoriedad de la contraseña, a mí no me gustó mucho porque es un poco demasiado larga y no contiene una variedad de signos de puntuación. Busqué en Google y encontré un enfoque mejor en StackOverflow. (Siempre estoy muy impresionado por lo fácil que es obtener respuestas de alta calidad en StackOverflow. Todo el trabajo difícil ya ha sido hecho por todos los gigantes, todo lo que necesitamos hacer es buscarlo, copiarlo, pegarlo y hacer pequeñas modificaciones (por ejemplo, cambiar los nombres de las variables).) La función es bastante sencilla y bastante autoexplicativa.

import secretsimport stringdef gen_password(self, length):    char = string.ascii_letters + string.digits + string.punctuation    return ''.join(secrets.choice(char) for _ in range(length))

Justo cuando todo iba un poco demasiado bien, mientras probaba mi código, ¡noté que ocasionalmente las contraseñas no se podían usar para abrir el archivo! Estaba realmente desconcertado. Tomó un poco de prueba y error y comencé a sospechar que podría haber algunos caracteres que no son adecuados como contraseñas porque este fenómeno solo ocurrió cuando las contraseñas contenían 2 barras invertidas \\.

Aquí hay un poco de antecedentes para que puedas apreciar la situación: uso Powershell y Notepad++, y mi código imprime las contraseñas en stdout. A continuación, resalto la contraseña impresa en Powershell y luego la pego cuando Excel me solicita que ingrese la contraseña. Por lo tanto, el problema es que \ es un carácter de escape, por lo tanto, se debe ignorar el primer \ cuando ingreso esto como la contraseña. Es problemático de manejar y para fines de contraseñas, puedo prescindir de un carácter menos. Por lo tanto, todo lo que hice fue cortar la barra invertida en string.punctuation.

  def _get_password(self, length):      string_punc = string.punctuation[:23] + string.punctuation[24:]      char = string.ascii_letters + string.digits + string_punc      return ''.join(secrets.choice(char) for _ in range(length))

Parte 3 — Poniéndolo todo junto

Dado que no hay casi ninguna ventaja en instanciar un objeto ExcelHelper si no se está lanzando o encriptando el archivo de Excel, se debe comenzar con if launch or encrypt:. A continuación, basta con pasar los argumentos de palabras clave de to_excelp a ExcelHelper y devolver el objeto y la contraseña.

def to_excelp(df, *arg, launch=True, encrypt=False, password=None, **kw):
    ''' Escribe en Excel y lo abre '''
    filename, *arg = arg
    if not filename.endswith(('.xlsx','.xls','.xlsm')):
        filename += '.xlsx'
    if os.path.isfile(filename):
        name, ext = filename.rsplit('.')
        filename = f'{name}_{timestr()}.{ext}'

    # Índice predeterminado es False
    index = kw.get('index', False)
    if not index:
        kw['index'] = False

    df.to_excel(filename, *arg, **kw)

    if launch or encrypt:
        xl = ExcelHelper(filename, launch=launch, encrypt=encrypt, password=password)
        return xl, xl.password
    else:
        return filename

Si estás escribiendo dataframes en varios archivos de Excel diferentes llamando a esta función, recomiendo almacenar los resultados en una lista de tuplas. Luego puedes iterar sobre esta lista de tuplas para obtener la ruta a los archivos de Excel y sus contraseñas. Almacenar el objeto puede ser útil en el futuro, especialmente si tienes la intención de agregar más funcionalidades a ExcelHelper.

l_xl_pw = []
for df in (df1, df2, df3, df4):
    xl, pw = df.to_excelp(launch=False, encrypt=True, password=None)
    l_xl_pw.append((xl, pw))

l_path_pass = [[xl.path, pw] for (xl, pw) in l_xl_pw]
df_path_pass = pd.DataFrame(l_path_pass, columns=['Ruta', 'Contraseña'])

# df_path_pass también se puede escribir en Excel usando .to_excelp(), ¡qué elegante! :D

ExcelHelper también se puede agregar a otros de tus scripts existentes.

def some_func():
    df = pd.read_excel('some_file.xlsx')
    # alguna manipulación de datos...
    df.to_excel('some_file_modified.xlsx')

def some_func(launch=False, encrypt=True, password='5tr0ngP@ssw0rd'):
    df = pd.read_excel('some_file.xlsx')
    # alguna manipulación de datos...
    df.to_excel('some_file_modified.xlsx')

    if launch or encrypt:
        xl = ExcelHelper('some_file_modified.xlsx', launch=launch, encrypt=encrypt, password=password)
        return xl, xl.password

Conclusión

Revisitar código antiguo escrito por uno mismo es como un paseo por el camino de la memoria que revela cuánto sabíamos en ese entonces. Aunque estoy muy avergonzado de ello, me alegra saber que he progresado desde entonces.

“Si no estás avergonzado por tu antiguo código, no estás progresando como programador.” [Anónimo]

Escribir estas pequeñas clases y funciones lleva tiempo, pero hay inmensos beneficios al tenerlas, ya que automatiza las partes mecánicas y no tan divertidas del trabajo y permite enfocarse en las tareas importantes. (Imagina tener que pensar en contraseñas con mayúsculas, minúsculas, números y puntuación y almacenarlas en un archivo todo el tiempo).

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Un nuevo estudio de IA desvela los secretos de las baterías de ion de litio a través de la visión por computadora

Miles de partículas minúsculas empaquetadas densamente en los electrodos de las baterías de iones de litio recargable...

Inteligencia Artificial

Construir una máquina GPU vs. Usar la Nube GPU

El artículo examina los pros y los contras de construir una máquina GPU en las instalaciones en comparación con el us...