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

miércoles, 24 de septiembre de 2025

Datos. Python.


Biblioteca Camelot (II)

Extracción de 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 tan simples como el utilizado en la [entrada anterior].


Es cierto que esta mayor complejidad es relativa, pero lo es suficientemente como para que necesitemos formular script con Camelot diferentes del anterior. Aprovecharemos también esta entrada para variar un poco de objetivo, buscando ahora guardar nuestras tablas en un documento externo.

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
    print (table.df) #Y la imprime en consola 

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 asume por defecto esa condición, pero si omitimos el parámetro cuando el documento tiene más de una página, no se produce error, pero el script sólo trabaja con la primera página del documento y devuelve únicamente las tablas que contenga la página 1 del documento.

Por el contrario, si conocemos el documento y sabemos en qué páginas contiene tablas y en 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 las hojas 1 al final del documento, lo que equivale a  pages= 'all' (todas las hojas); pero sí especifico  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), 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 son cuando el documento presenta mayor complejidad. Aunque no siempre incluirlo mejora 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 (Shell en realidad) 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))

Bueno, pues en esta entrada hemos aprendido unas cuantas cosas más. Especialmente interesante poder guardar las tablas extraídas en un documento de fácil acceso y manejo.