Mostrando entradas con la etiqueta Camelot. Mostrar todas las entradas
Mostrando entradas con la etiqueta Camelot. Mostrar todas las entradas

miércoles, 24 de septiembre de 2025

Datos. Archivos pdf

Biblioteca Camelot (III)

Conversión de tablas a Excel

Para finalizar esta serie de entradas sobre Camelot, expongo en esta entrada la transcripción del script del autor de ExcelMasPro, cuyo vídeo cité como fuente en esta entrada. Sirva de reconocimiento y agradecimiento por su buen trabajo.

El objetivo de esta entrada es triple: reconocer lo que ExcelMasPro nos aporta con su trabajo, mostrar otro modo de trabajar Python y retomar la referencia a la relación entre este lenguaje y las hojas de cálculo. Y todo en el mismo paquete.

Paso sin más a presentar el script que he copiado literalmente del vídeo, aunque omito la formulación de la función y la llamada a la misma, cosa que altera el funcionamiento del código pero lo simplifica adaptándolo a mi nivel actual de conocimiento.



import camelot
import os
import pandas as pd
from tkinter import Tk
from tkinter.filedialog import askopenfilename, askdirectory
from datetime import datetime
#Ocultar ventana principal de TKinter
Tk().withdraw()

#Seleccionamos el archivo pdf
print("Seleccione el archivo PDF:")
pdf_file = askopenfilename(
	title = "Seleccionar el archivo PDF",
	filetypes=[("Archivos PDF","*.pdf")]
    )
if not pdf_file:
	print("No se seleccionó ningún archivo. Saliendo...")

#Seleccionar la carpeta de destino
print("Seleccione la carpeta donde desea guardar el archivo Excel:")
output_folder = askdirectory(title="Seleccionar carpeta de destino")
if not output_folder:
	print("No se seleccionó ninguna carpeta. Saliendo...")

#Nombrar el archivo Excel
now = datetime.now().strftime("%m-%d-%y-%H-%M")
output_excel = os.path.join(output_folder, f'Import_PDF_a_Excel_{now}.xlsx')

#Extracción de las tablas del pdf mediante Camelot
print("Extrayendo tablas del PDF...")
tables = camelot.read_pdf(pdf_file,pages="all", flavor="stream")

#Guardar las tablas en Excel
if not tables:
	print("No se encontraron tablas en el archivo PDF:")

#Guardando las tablas
with pd.ExcelWriter(output_excel, engine="openpyxl") as write:
	for i, table in enumerate(tables):
		table.df.to_excel(write, sheet_name = f'Tabla_{i+1}', index=False)


En resumen, lo que hace este script es acceder a un archivo pdf, capturar las tablas que incluye (mejor dicho, lo que Camelot identifica como tales, que no siempre lo son) y copia su contenido en una hoja de cálculo en la que crea tantas hojas como tablas encuentra.

El uso de TKinter permite al script facilitar una entrada de datos personalizada y en formato gráfico, algo que raramente he empleado por considerarlo innecesario en este nivel de aprendizaje, pero que en este caso me ha parecido interesante mantenerlo por mostrar otras formas de trabajar con Python (más cercanas al desarrollo de aplicaciones o DocAp).

Me ha parecido especialmente interesante el modo de construir el nombre del documento Excel creado, aunque he realizado un pequeño cambio en el formato (uniendo todos los elementos mediante guion bajo).

Realmente este script es más que una forma de mostrar el uso de Camelot, incluyendo el procedimiento de crear y guardar datos en una hoja de cálculo de Excel; supone además poner a nuestra disposición una pequeña aplicación que resuelve el problema de acceder a cualquier documento pdf y extraer las tablas que contenga dejándonoslas disponibles como hoja de cálculo. Por desgracia no siempre funciona correctamente (sobre todo cuando los documentos son complejos) y no siempre extrae todos los datos de las tablas (por lo que siempre será necesario comprobar el resultado), pero al menos para pdf sencillo y tablas "normales" el éxito sí está garantizado.

Datos. Archivos pdf

Biblioteca Camelot (II)

Tablas en pdf complejos

Aunque se trate de una forma bastante simple de entender la complejidad, cuando manejamos un pdf con varias tablas y/o con varias páginas, la cosa cambia. Ya no nos sirven procedimientos simples como el utilizado en la entrada anterior. Cierto que esa complejidad es muy relativa, pero lo suficiente para que necesitemos formular un script con Camelot diferentes y más complejo que el anterior.



import camelot
# Especifica la ruta al archivo PDF
file_path = 'tablaSimple_c.pdf'
# Usa el método lattice para extraer tablas
tables = camelot.read_pdf(file_path, flavor= 'lattice' , pages= '1-end' )
# Guarda las tablas en formato CSV
tables.export( 'tablas.csv' , f= 'csv' , compress= True )
# Imprime el contenido de todas las tablas
for i, table in enumerate (tables):
	print ( f"Table {i + 1 } " )
# Numera la tabla y la imprime en consola
print (table.df)


El documento pdf con el que trabajamos en este caso está dividido en tres hojas y cada una de ellas contiene una tabla sencilla. El procedimiento, según se observa en el script, es, sin embargo un tanto diferente. Ahora no es suficiente con indicar en el método camelot.read_pdf() como único parámetro la ruta del archivo (file_path), también es necesario establecer el número de páginas a estudiar (pages= '1-end') y el método empleado para extraer las tablas (flavor= 'lattice'). Veamos ambos parámetros con más detalle.

Cuando un documento tiene una única página, la función camelot.read_pdf() no precisa que se especifique el parámetro pages ya que se asume por defecto esa condición, pero si omitimos el parámetro cuando el documento tiene más de una página, aunque no se produce error, el script sólo trabaja con la primera página del documento y devuelve únicamente las tablas que contenga esa página 1. Por el contrario, si conocemos el documento y sabemos qué páginas contienen tablas y cuales no, usando el identificador de páginas de forma selectiva no ahorramos obtener datos que no nos interesan, ya que Camelot puede interpretar como tablas segmentos del documento que no lo son. Por ejemplo, si el parámetro pages se concreta como pages= '1-end', el script registra las tablas de todas las hojas hasta el final del documento, lo que equivale a emplear al expresión pages= 'all' (todas las hojas); pero sí especificamos pages= '1-2' sólo trabajará con el intervalo de hojas 1 a 2 y si solicitamos pages= '1,3' lo hará con las tablas de las hojas 1 y 3. También son posibles combinaciones de página e intervalo, como por ejemplo pages= '1-5,4,7,12-end'.

Respecto al método de extracción de tablas, latice está diseñado para extraer tablas de contornos bien definidos, mientras que su alternativa (stream), aunque es más lento, permite trabajar con tablas de límites mal definidos y celdas separadas por espacios. Este parámetro (flavor) no es necesario cuando las tablas son el contenido único de la página y además están bien definidas, pero sí lo es cuando el documento presenta mayor complejidad, si bien incluirlo no garantiza que mejoren los resultados.

El siguiente paso consiste en generar un archivo (en este caso uno por tabla y en formato csv) para guardar el resultado de la extracción, lo que en este caso conseguimos con la función export() (tables.export( 'tablas.csv' , f= 'csv' , compress= True )), donde especificamos el nombre del archivo ('tablas.csv'), el tipo de archivo (f= 'csv') y si se presentan comprimidos o no (compress= True). El resultado es una carpeta comprimida que contiene (en mi caso) tres documentos csv, cada uno con su correspondiente tabla.

Finalmente podemos imprimir por consola cada una de esas tablas, cosa que ahora implica hacer uso de un bucle (for i, table in enumerate (tables):) que escribe por pantalla el número de la tabla según su posición en el texto (print ( f"Table {i + 1 } " )) y su contenido (print (table.df)). El resultado de esta parte del script es la escritura en consola de las tres tablas de forma consecutiva. Podríamos optar por acceder a cualquiera de ellas sustituyendo el ciclo por una instrucción simplificada de escritura (vg. print(tables[0].df))

martes, 23 de septiembre de 2025

Datos. Archivos pdf

Biblioteca Camelot (I)

Tablas en pdf

Cuando trabajamos con documentos pdf, uno de los contenidos de especial interés y que además resulta especialmente complicado de manejar son las tablas.

Para acceder a su contenido podemos emplear recursos como PyPDF2, pero el resultado no es muy satisfactorio como hemos tenido ocasión de comprobar, así que decidí probar con otro recurso.

Realmente resulta muy complicado automatizar la extracción de datos de tablas de un documento pdf de forma que resulte preciso y funcional, y son precisamente las tablas las que mayor dificultad presentan. Camelot es una librería pensada específicamente para esta tarea y funciona satisfactoriamente, al menos con tablas sencillas y reales, no imágenes incrustadas.

Cierto es que trabajar con Camelot presenta cierta dificultad, incluyendo algunas complicaciones para su instalación, pero se pueden superar. Por eso te recomiendo que conozcas esta biblioteca por su fuente, su propia página web, incluyendo la lectura de su manual on-line. También combiene plantearse metas sencillas y trabajar con pdf también sencillos; al menos al principio. Ya podrás incrementar la dificultad conforme vayas dominando la herramienta.

En esta entrada te mostraré la que es posiblemente la forma más sencilla de abordar un problema básico: mostrar en pantalla el contenido de una tabla de un sencillo documento pdf de una página que contiene una tabla simple. Inmediatamente podremos pasar a cuestiones de mayor complejidad. Supongamos que ese documento pdf (tablaSimple.pdf) contiene esta tabla...

... a la que deseamos acceder desde un script de Python,concretamente desde este...



import camelot
# Especifica la ruta al archivo PDF
file_path = 'tablaSimple.pdf'
# Lee las tablas que contiene el PDF
tables = camelot.read_pdf(file_path)
# Imprime el número de tablas encontradas
print (f"Total de tablas encontradas: {tables.n}")
# Imprime el contenido de la primera tabla
print (tables[ 0 ].df)


... que nos devuelve esa misma tabla en el IDE Shell

Vistas así las cosas, la verdad es que este resultado parece bastante pobre, pero podemos hacer varias cosas a partir de aquí, entre otras pasar la tabla a un archivo Excel o trabajar directamente con el contenido de la tabla mediante librerías como Pandas .

En este caso vamos a importar la librería pandas, sin entrar ahora en más explicación, y añadir unas cuantas instrucciones más al script, por ejemplo acceder a la tabla capturada y pasar los datos a una colección como paso previo para manejarla, por ejemplo, accediendo a las "celdas" [1-0] y [1-1] y mostrando su contenido...



import pandas as pd
tabla = tables[0].df
nombre = tabla.iloc[1,0]
dato = tabla.iloc[1,1]
print(f'Nombre {nombre} - Edad {dato}')


... para obtener por pantalla Nombre Juan - Edad 23

Tampoco esto parece gran cosa, pero detrás de ello tenemos toda la potencia del manejo de datos que permiten librerías como Pandas y todas aquellas que facilitan el tratamiento de datos en Python. El que lo podamos conseguir partiendo de una tabla de datos de un documento pdf es gracias a Camelot, por lo que conocer esta biblioteca es una buena forma de empezar.