Hojas de cálculo con Python
Ya vimos que una de las opciones disponibles para automatizar el trabajo con servicios ofimáticos mediante Python consiste en implementar librerías específicas para trabajar con MSO, concretamente con Word y con Excel. Dada la compatibilidad entre MSO y LibreOffice, aunque la suite no sea LO, esto no impide que finalmente podamos trabajar desde esta suite, utilizando incluso script OOoBasic para complementar la automatización del documento.
En una entrada anterior traté el trabajo con Word, así que en la presente me centraré en una de las opciones para trabajar con Excel: la librería OpenPyXL. Además del anterior (web oficial), al final de la entrada te dejo algunos enlaces de interés.
Aunque las posibilidades de uso son muchas, por el momento me voy a limitar a lo más básico: lo equivalente a lo hecho con Word/Writer, aunque sin entrar en comparaciones entre el uso de OOoBasic y Python, ya que ese discurso y sus implicaciones quedaron dichas en una entrada precedente respecto a un ejemplo práctico. Me parece más útil ahora centrarme en el uso básico de OpenPyXL con el objetivo inmediato de alcanzar el conocimiento necesario para desarrollar aplicaciones similares a los docap simples que podemos crear con OOoBasic; esto nos permitirá dar posteriormente algunos pasos en esa dirección.
Para ello expondré cómo crear un libro Excel, cómo acceder a un libro previamente creado, cómo acceder a una hoja concreta del libro y los rudimentos del trabajo con celdas: lectura y escritura de contenido. Estos conocimientos me permiten emular las acciones básicas que desarrollamos en OOoBasic (script y/o macros), por lo que, como dije antes, nos situamos en Python en niveles de competencia similares a los que nos han permitido crear docap sencillo en OOo Basic. Creo que el camino que debimos recorrer en OOoBasic para llegar a ese nivel y el que vamos a recorrer ahora en Python es un buen ejemplo del potencial de este lenguaje.
Lo primero que tenemos que hacer para trabajar con OpenPyXL es instalar este paquete para que está disponible en Python, ya que no es una de las librerías que trae Python en su instalación de base. Como ya vimos respecto a python-docx, la instrucción necesaria (pip install openpyxs) de escribe en el cmd, tras el prompt C:\Users\NombreUsiario> (sea NombreUsuario el que corresponda en tu ordenador).
Lo segundo que debes hacer, ahora ya en la creación de un script Python, es importar la librería instalada. La forma más simple, que no la única, pero sí la que vamos a utilizar por ahora, es la instrucción import opnepyxl escrita siempre y necesariamente al inicio del script (puedes, eso sí, escribir algún comentario explicativo de lo que se pretende con el script; es más, te lo recomiendo)
Pasemos ahora a crear nuestro primer archivo Excel, algo tan sencillo en Python como lo siguiente:
libro = openpyxl.Workbook()
libro.save("PrimerLibro.xlsx")
La primera línea de instrucciones asigna a la variable libro la creación del libro excel mediante la función Workbook(). La segunda guarda el libro creado con la función save().(1) Sin esto, el libro no se guardará, por lo que perderemos todo el trabajo que hagamos en el script, así que es muy importante finalizar este con una instrucción save() y lo que corresponda escribir dentro del paréntesis, claro.
Existe un modo alternativo y simplificado de crear un libro excel:
- Primero importamos OpenPyXL incluyendo en la solicitud la expresión Workbook del siguiente modo:
from openpyxl import Workbook
- Después creamos la variable libro y asignamos la función Workbook()
libro = Workbook()
Como puedes ver, de este modo lo que hacemos es omitir openpyxl de la expresión openpyxl.Workbook(), pero el resto del procedimiento es igual, así que puedes optar por una forma o por otra, que el resultado será el mismo.
Entre paréntesis escribimos, como parámetro de la fución, el nombre del archivo y la extensión (.xlsx), ambos como cadena de texto. La forma empleada en el ejemplo, crea el archivo excel PrimerLibro.xlsx en el mismo directorio en el que esté ubicado el script python. Para indicar otra dirección deberemos señalarlo como parámetro. Un ejemplo podría ser...
libro.save("C:/Users/NombreUsuario/Desktop/PrimerLibro.xlsx")
Donde pone NombreUsuario deberás escribir el que corresponda. Observa además que he invertido la barra separadora que genera windows por defecto.
C:\Users\NombreUsuario\Desktop\PrimerLibro.xlsx
Para ahorrarte experimentos condenados al fracaso: puedes utilizar la extensión Calc para nombrar el fichero (PrimerLibro.ods) y se creará el archivo sin ningún problema, pero cuando intentes abrirlo desde Calc te encontrarás con un menaje de error y no podrás acceder a él. Por el contrario, un archivo de extensión xlsx podrás abrirlo perfectamente desde Calc y trabajar con él sin mas problemas. Después ya decides tú si lo conviertes al formato .ods o lo dejas como .xlsx. Por cierto, Calc crea ficheros xlsx desde la opción guardar como... Excel 2007-365.
Resuelta la primera cuestión, vamos a plantear la segunda. Antes creamos un libro (de momento no hicimos nada en él), pero ahora nos planteamos que lo que necesitamos no es crear un nuevo libro, sino acceder a uno ya creado.
En este caso, después de importar el módulo openpyxl (2), podemos plantearnos también dos opciones:
- La primera consiste en crear una variable ruta (path, si prefieres) y después utilizarla para acceder al archivo. Esta opción es válida para cualquier ubicación del archivo al que deseamos acceder.
ruta = "C:\\Users\\NombreUsuario\\Desktop\\NombreArchivoExcel.xlsx" (3)
libro = openpy.load_workbook(ruta)
- La segunda forma consiste en utilizar directamente el nombre del libro excel en la instrucción de apertura. Esta opción es útil (y yo diría que recomendable) cuando el libro excel se encuentra en el mismo directorio que el script Python.
libro = openpy.load_workbook("NombreArchivoExcel.xlsx")
Una vez que hemos accedido al libro deseado, o que lo hemos creado, (obviamente antes de guardarlo si queremos que surta efecto lo que hagamos en él) nos podemos plantear diferentes tareas, pero todas ellas pasan por acceder a una hoja, en primer lugar, y por acceder a una celda en particular. Resumiendo, que nos interesa saber cómo manejarnos con las hojas del libro y con las celdas de las hojas. A ello vamos a continuación, empezando por las hojas.
Cuando creamos un nuevo libro, inicialmente sólo tiene una hoja, pero cuando cargamos uno ya creado, nos puede interesar saber cuántas hojas tiene; para ello emplearemos la siguiente instrucción...
print(libro.sheetnames)
... después de haber asignado a libro el acceso al archivo cargado, por ejemplo...
libro = openpy.load_workbook("NombreArchivoExcel.xlsx")
La instrucción anterior imprime en pantalla (cmd) una lista con los nombres de las hojas que contiene el libro, en mi caso ['Hoja0', 'Hoja1']. Esto nos permite trabajar con las hojas como podemos hacerlo con cualquier lista python, por ejemplo, conocer el número de hojas del libro con la función len()
lista_hojas = libro.sheetnames
num_hojas = len(lista_hojas)
print(num_hojas) -> devuelve 2
Con frecuencia vas a necesitar añadir nuevas hojas a un libro. No en el caso de acceder a un libro creado previamente, pero sí seguramente en caso de crear un libro mediante Python, ya que lo que se crea es un libro básico de una única hoja. Vamos, entonces a aprender cómo crear nuevas hojas mediante OpenPyXL.
Estas son las diferentes formas con que podemos crear una hoja (4).
hoja1 = libro.create_sheet("Hoja_Creada") -> Crea la Hoja_Creada al final del libro
hoja2 = libro.create_sheet("Hoja_Ini",0) -> Crea la Hoja_Ini al inicio del libro
hoja3 = libro.create_sheet("Hoja_Fin",-1) -> Crea Hoja_Fin en la penúltima posición
También nos puede interesar borrar una hoja creada, por ejemplo, la hoja Hoja_Creada que posicionamos al final del libro. Para ello utilizaremos la función remove() mediante la siguiente instrucción:
libro.remove(libro['Hoja_Creada']) -> Observa que estamos trabajando con una lista
Una vez creadas las hojas necesarias (y borradas las no deseada), necesitamos actuar sobre cada una de ellas, lo que supone acceder a la hoja activa
Debemos saber que, por defecto, la hoja activa es, por defecto, la hoja que ocupa la posición 0. Por ejemplo, según lo hecho mediante las anteriores instrucciones de creación de hojas, la que ocupa la posición 0 es la hoja llamada Hoja_Ini, así que...
hoja_activa = libro.active
print(hoja_activa.title) ... nos devolverá Hoja_Ini
... y podemos aprovechar este procedimiento para modificar el nombre o título de la hoja mediante...
hoja_activa.title ="PrimeraHoja" (5)
Pero aun más interesante para el manejo básico del código es posicionarse en otra hoja, lo que es lo mismo que desplazar el foco (la condición de hoja activa) a esa nueva hoja. Para ello volvemos a trabajar sobre la lista de hojas del libro mediante las siguientes instrucciones:
hoja_activa = libro['Hoja_Fin']
libro.active = hoja_activa
... de modo que se ahora pedimos el nombre de la nueva hoja activa (print(hoja_activa.title), ahora nos devolverá Hoja_Fin, lo mismo que si lo pedimos de este modo: print(libro.active.title)
Para un uso básico de OpenPyXL, nos falta aprender a acceder a las celdas, cosa que ahora ya estamos en disposición de hacer, una vez que hemos sido capaces de acceder a una hoja y convertirla en hoja activa. Esto quiere decir que, al menos una de las formas de acceder a una celda pasa por las siguientes fases:
- Accedemos al libro
- Accedemos a la hoja (la hoja activa)
- Y finalmente accedemos a la celda que nos interesa, que, supongamos, es la celda A5.
celda_interes = hoja_activa['A5']
Otra forma consiste en utilizar las referencias de columna y fila:
celda_interes = hoja_activa.cell(row=5, column=1)
... y la mejor forma de saber a ciencia cierta que estamos trabajando sobre la celda A5 es pedir su contenido:
print(celda_interes.value) -> Nos devuelve None, ya que está vacía, pero...
Podemos atribuir valores (contenido) a cada celda de forma muy sencilla:
- Asignando el valor directamente a la celda:
hoja_activa['A5'] = 10
celda_interes =hoja_activa['A5']
- Usando la notación fila-columna y el argumento value
celda_interes =hoja_activa.cell(row=5, column=1,value=10)
- O actualizando la propiedad value de una celda
celda_interes = hoja_activa.cell(row=5, column=1)
celda_interes.value=10
Si ahora solicitamos el valor de la celda...
print(celda_interes.value)
... nos deberá devolver 10 en todos los casos.
No está todo dicho, ni mucho menos, sobre lo que podemos hacer con OpenPyXL, pero esta entrada está siendo ya demasiado extensa, y como tenemos los fundamental para empezar a trabajar, mejor será dejarlo así de momento, pero con una propuesta de trabajo sencilla:
- Crea un libro excel nuevo en el mismo directorio que el script Python
- Cambia el nombre de la primera y única hoja disponible a "DATOS"
- Escribe en esa hoja un "a modo de formulario" de datos de identificación:
- A1 -> "Datos de identificación"
- A2 -> "Nombre" - C2 -> alum_nombre
- A3 -> "Apellidos" - C3 -> alum_apellidos
- A4 -> "Curso/Nivel - C4 -> centro_nivel
- A5 -> "Centro" - C5 -> centro_nombre
- Página oficial de la librería OpenPyXL.
- Programación .net. Cómo trabajar con archivos Excel utilizando Python.
- J2LOGO. Crear archivo excel en Python con openpyxl
- Barcelona Geeks. Leer un archivo excel usando el módulo Python openpyxl
- Pybonacci. Curso sobre cómo trabajar con hojas de cálculo (Excel, Calc) usando openpyxl en Phyton (III)
NOTA 1. Fíjate que Workbook() se escribe con primera letra en mayúscula, pero que save() se escribe todo en minúscula. Esta diferencia es fundamental en Python y deberás escribir ambas funciones exactamente como te indico, así evitarás un mensaje de error innecesario.
NOTA 2. De una forma - import openpyxl - o de otra - from openpyxl import Workwook - como vimos antes. Yo opto por la primera forma, de ahí que después acceda al archivo empleando la instrucción que incluye la llamada a openpyxl.
NOTA 3. Observa que he usado dos formas diferentes de separar las carpetas de la ruta: mediante dos barrar inclinadas hacia la izquierda (\\) y mediante una inclinada hacia la derecha (/). En Windows ambas surten el mismo efecto.
NOTA 4. Respecto a hoja2 y hoja3, los valores de posición 0 y -1 (posición inicial y posición anterior a final, respectivamente) pueden ser sustituidos por otros valores, siempre que exista un número de hojas que lo permita.
NOTA 5. Si ahora pedimos saber la hoja activa mediante la función print() [print(hoja_activa.title], ahora nos devolverá PrimeraHoja en vez de Hoja_Ini.