miércoles, 24 de septiembre de 2025

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))

No hay comentarios:

Publicar un comentario

Comenta esta entrada