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

jueves, 9 de octubre de 2025

Demanda. Propuesta.


Demanda de evaluación (VI)




Traslado de la demanda al SEO

Una vez que el Equipo Educativo ha elaborado su demanda, esta, de un modo u otro, pasa al SEO, que valora la información y se plantea qué hacer (y cómo), pero esas son cuestiones que pertenecen a otros procesos. Por lo que a éste se refiere, tras lo trabajado en las entradas anteriores y en lo que son los términos estrictos de esta sección, sólo queda resolver la recepción del documento por parte del SEO y el modo en que éste va a trabajar con dicho documento.

Al respecto, aunque son varias las posibilidades, la que me interesa plantear ahora es aquella en la que, quien corresponda, nos entrega un documento pdf (formato digital)(1). Nuestro objetivo como SEO es acceder al contenido, especialmente a la parte que contiene la información crítica (DA y dificultades EA, página 2), ya que sobre ella vamos a tomar decisiones y a montar un procedimiento de actuación. Nuestro interés es automatizar este acceso o, cuanto menos, ayudarnos de Python para acceder a esa información. Para este fin utilizaremos la biblioteca PyPDF2. Este sería el script básico...

from PyPDF2 import PdfReader

lector = PdfReader("solicitud.pdf")

pagina = lector.pages[1]

texto = pagina.extract_text()

... con el que podríamos dar por concluida esta tercera fase del proceso simplemente con este script, ya que cubre satisfactoriamente (aunque por la mínima) con el objetivo que enunciamos antes: nos permite acceder al documento (lector = PdfReader("solicitud.pdf")), concretamente a su página 2 (pagina = lector.pages[1]), de la cual extraemos su contenido (texto = pagina.extract_text()). Como puedes ver, mucho con muy poco (2).

Y ciertamente, en este punto podemos dar por finalizado el enfoque de trabajo que hemos mantenido en este proyecto hasta este momento (Python como lenguaje para construir script con los que abordar procedimientos), a la vez que iniciado (estamos aquí en una frontera borrosa) otro enfoque, más instrumental, en el que me planteo usar Python como herramienta para manejar el material (en este caso, el contenido de la segunda página de un documento pdf) que hemos recibido.

Como este planteamiento puede resultar un tanto confuso, aunque no es la primera vez que lo planteo, me parece una buena ocasión para ponerlo en práctica, lo que requiere que nos resituemos como SEO y nos planteemos con qué objetivos vamos a trabajar, ya que son estos los que nos van a guiar en el proceso.

En primer lugar, la finalidad última de nuestro trabajo se concreta como uso de la información sobre DA y dificultades EA para plantear actuaciones, la más inmediata es construir un guion de contenidos para una entrevista con el profesorado (tutor/a). 

Ahora bien, para esto necesitamos hacer algo más (que se aparta de lo que ahora nos planteamos), que es investigar en el expediente escolar del alumno, y no es estrictamente necesario que lo que sí podemos considerar parte de este nuestro actual procedimiento sea resuelto mediante Python: perfectamente podemos copiar el contenido de la salida que nos ofrece el script anterior si el añadimos un print(texto), y pegarlo en un documento (txt o Writer, por ejemplo) y ya podríamos trabajar con el contenido que nos interesa. Esta podría ser tu opción.

De hecho esto ya constituye una forma, la más simple que no la más útil (3), de aplicar ese enfoque directamente instrumental del uso de Python del que te estoy hablando. Lo que te propongo en esta entrada es desarrollarlo de forma más extensa y coherente con un planteamiento orientado a la automatización de los procedimientos de trabajo.

La cuestión está en que, desde este enfoque, no existe un script que entregar como base para tu uso (4); es el script lo que tienes que ir construyendo hasta obtener el resultado que te satisfaga. Esto implica formularlo y reformularlo conforme avanzas en un proceso que vas construyendo en parte en función de tu objetivo-guía, en parte en función de los resultados que vas obteniendo.

En este caso yo me planteo obtener por separado los datos DA observadas y dificultades EA observadas y almacenar ambos en sendos archivos txt para su posterior uso. Hasta aquí llegará mi trabajo con el contenido extraído de l documento PDF.

Esto implica desarrollar dos veces el siguiente proceso:

  • Extraer del documento las líneas correspondientes con la categoría 
  • Pasarlas a una lista específica 
  • Copiarlas en un archivo txt específico
Además, si se da el caso (que se da) será necesario modificar alguno de los elementos de estas listas (5)

Este planteamiento es el que se recoge en el código que te proporcionó en el archivo contenido en el zip que puedes descargar desde [este enlace] y que contiene todos los script del proyecto y todos los documentos auxiliares y aquellos que sirven a modo de ejemplo (6)

NOTAS

(1) En realidad no debería ser infrecuente recibir el conjunto de documentación generada, incluyendo el archivo datos.txt. No obstante ahora vamos a trabajar en base a una realidad tampoco inusual que si no es en este contexto puede perfectamente darse en otros. No es infrecuente tener que trabajar con información aportada en PDF e incluso, aun peor, con documentos en papel, los cuales deberemos escanear si deseamos acceder a su contenido. En ambas situaciones podremos hacer uso de la biblioteca PyPDF2 (u otra similar) como herramienta para automatizar (parcialmente) el acceso al contenido textual de esa documentación.
(2) Se debe entender que estamos usando Python (concretamente PyPDF2) como una herramienta, así que nuestro objetivo con este script no es crear una aplicación (por sencilla que sea) sino obtener un resultado inmediato usando el lenguaje como herramienta de trabajo que, en este caso, sustituye al copia-pega. Este enfoque de trabajo facilita interesantes desarrollos, como podremos ver a continuación en esta misma entrada.
(3) No es precisamente ésta la mejor solución, ya que el resultado del print()-copia-pega nos proporciona un texto plagado de trabajo, pero como ejemplo de lo que quiero decir me sirve perfectamente.
(4) Ese ha sido el planteamiento de los script anteriores dentro de este proyecto. En realidad sí podríamos crear un "borrador" de script con todas (o casi) las instrucciones comentadas para que tú las fueras activando conforme las fueras necesitando. Y puede ser una solución interesante cuando es de esperar que podamos repetir varias veces un mismo proceso, pero en la mayoría de los casos es más bien un esfuerzo excesivo para un resultado incierto. En cualquier caso lo que sí parece interesante es ir comentando el script conforme lo vamos construyendo para saber la motivación y objetivo de cada uno de los pasos que vamos dando: a partir de esta guía pueden surgir procedimientos de interés que podemos retomar como proyectos de script/app en otro momento.
(5) Cuando se trabaja con texto extraído de un PDF no hay garantías de correcta codificación, por lo que es posible que tengas que trabajar con el texto resultante. Este es el caso respecto a las tildes.
(6) Obviamente se trata de un supuesto, no de datos reales.

domingo, 14 de septiembre de 2025

Textos. Python

Librería PyPDF2. Guardar el texto


En sentido estricto esto no es propiamente parte del manejo de PyPDF2, pero sí parte necesaria del proceso, ya que de poco sirve obtener el contenido de un documento si no podemos disponer de él para seguir avanzando en nuestro proyecto. Es absurdo, y más teniendo a mano soluciones tan sencillas pero tan eficientes como la que explico en esta entrada.


Sea sobre el texto tal y como lo obtenemos mediante PyPDF2, sea tras su tratamiento, por ejemplo, mediante algún procedimiento de segmentación y recomposición como los explicados [en esta entrada], lo cierto es que necesitamos rescatar para un trabajo posterior el texto obtenido. Las formas son varias, como lo son los soportes, pero aquí vamos a exponer la más simple de todas: el archivo del contenido como documento txt.

Para ello sólo necesitamos añadir al código de nuestros script dos instrucciones que forman parte de una estructura wiht (1):

with open("pdf/textos/contenido_pdf1.txt", "w", encoding="utf-8") as archivo:
    archivo.write(texto)

Si te fijas, dentro del paréntesis que sigue a with open() tenemos...

  • En primer lugar y como primer parámetro, un string con la dirección donde guardar el archivo y el nombre (y extensión del propio archivo ("pdf/textos/contenido_pdf1.txt"). 
  • El segundo parámetro indica el tipo de acción a ejecutar, en esta caso w de writing (escribir)
  • Y el tercero y final el tipo de codificación (encoding) que vamos a emplear en este archivo txt; en este caso  ("utf-8") (2)
Completa esta instrucción la orden que ejecuta lo que previamente se ha establecido (archivo.write(texto)) mediante la función writer() aplicada al contenido  de la variable (texto) a la que hemos asignado el texto obtenido mediante PyPDF2 en la fase previa de nuestro script (3).

NOTAS

(1) Ya tuvimos ocasión de trabajar con esta estructura en el script de captura de imágenes [Ver entrada] en el que nos permitía ejecutar un procedimiento similar, pero relativo a la copia de las imágenes:

 with open(f'pdf/imgs/{str(n_pag)}__{image_file_object.name}', 'wb') as img:    
            img.write(image_file_object.data)

(2) Si prescindimos de esta codificación es muy probable que se produzca error a poco que el texto capturado contenga caracteres que se "salen" de los registros más básicos.
(3) Este código es tan simple que podemos utilizarlo sin mayor dificultad y con mínimos cambios para trabajar con otros script basados en PyPDF2 dirigidos a la obtención del texto del pdf.

sábado, 13 de septiembre de 2025

Textos. Python.

Biblioteca PyPDF2. Segmentar el contenido (otras unidades)


Aunque dividir el contenido por páginas es de interés, mayor cuanto de más páginas conste el documento, no es la única segmentación posible ni la única de la que podemos obtener beneficios a la hora de automatizar el acceso a un documento pdf. En esta entrada veremos otras segmentaciones posibles.


La primera que se me ocurre resulta de la aplicación de la función split() la cual, [como sabes] (1) sirve para separar los elementos de una cadena en función de un carácter usado como criterio de segmentación.

La aplicación de split() para crear una lista la realizamos sobre el contenido de la variable resultante de la captura del contenido textual del (o de los) pdf, por lo que mantenemos el código anterior y simplemente implementamos el nuevo (2).

En función del objetivo que busquemos con la segmentación, el cual a su vez puede estar determinado por la extensión (y otras características) del texto, deberemos utilizar el carácter divisor que más se ajuste a nuestro objetivo. 

Aunque el más simple consiste en obtener una lista con las palabras del texto usando simplemente la instrucción split() (3), posiblemente uno de los de mayor utilidad en caso de texto extensos y complejos de forma sea el salto de línea (\n), para el que, ya sabemos, contamos con la función específica splitlines().

Lo cierto es que, combinando este criterio de separación por saltos de línea con la función de recomposición de la unidad del texto mediante join() (4), podemos intentar resolver una de las "limitaciones" que observamos cuando trabajamos con pdf multi-columna.

from PyPDF2 import PdfReader

#Acceso al documento
lector = PdfReader("pdf/EvalTDAH.pdf")
pag = len(lector.pages)
texto = ""

for pg in range(pag):
    pagina = lector.pages[pg]
    texto += pagina.extract_text()

#Variables para cargar info
pag = len(lector.pages)
meta = lector.metadata 
num_pal = len(texto)

#Imprimir en consola
print("DATOS DEL DOCUMENTO --------------------------")
print("Número de páginas",pag)
print("Número de palabras",num_pal)
print("METADATOS DEL DOCUMENTO --------------------")
print("Autor",meta.author)
print("Título",meta.title)
print("TEXTO completo -----------------------------------")
print(texto)

#Segmentación del contenido en función de las líneas

listalin = []
listalin = texto.splitlines()

#Recomposición de la unidad del texto
textofin = ""
textofin = " ".join(listalin)

#Mostrar el nuevo texto por pantalla
print(textofin)

Muy cierto que pasamos de un problema a otro, pero no pretendo aquí más que mostrar lo que resulta de combinar split() con join() en el manejo de textos amplios y complejos. Evidentemente se puede mejorar mucho el resultado, pero necesitamos trabajar más el script, así que, por el momento voy a considerarlo suficiente.


NOTAS

(1) También sabes tanto OOo Basic como Python cuentan con esta función para la segmentación de cadenas, que además funciona del mismo modo en ambos lenguajes. Para OOo Basic puedes consultar [esta entrada].
(2) Al contrario de lo que hicimos cuando segmentamos el contenido en función de las páginas del pdf [ver entrada anterior]
(3) La utilidad inmediata de este procedimiento es conocer el número de palabras del texto mediante la función len(), pero no el la única; hay todo un mundo de opciones detrás de esta segmentación.
(4) Vale para join() el enlace asociado a 1 en el cuerpo de la entrada y lo dicho en esa misma nota para split()

viernes, 12 de septiembre de 2025

Textos. Python.

Biblioteca PyPDF2. Segmentar el contenido (páginas)


Resuelto (en parte) el [acceso a las imágenes] de un pdf (1), nos queda aun mucho por delante para mejorar los procedimientos de modo que nos sea realmente de utilidad. Y se me ocurre que segmentar el contenido, aunque no sea la solución, sí nos acerque a ella.

Segmentar el contenido nos puede ayudar de muchas maneras, siendo la primera de ellas facilitar el acceso a segmentos del texto desde el script, cosa que resulta complicada cuando el contenido textual es amplio. Posiblemente no sea la única ventaja, así que merece la pena explorar esta opción.

Para ello debemos tener en cuenta las propias divisiones de un texto en páginas, párrafos, líneas y palabras, algunas de las cuales nos pueden interesar como criterio de segmentación. También las funciones de que dispone Python para trabajar con cadenas y las propias colecciones de datos de este lenguaje.

Tomando las listas como colección básica y la página como referencia para la división, una primera segmentación es capturar de forma diferenciada y en una lista, el contenido de cada una de las páginas de un texto. En teoría esto nos podría servir para trabajar de forma diferenciada con cada una de las páginas, incluyendo el acceso selectivo en función de objetivos (2).

A modo de ejemplo, tomando como referencia el mismo documento multi-página que nos sirvió para aprender a acceder a un documento de estas características (3), te planteo ahora el script que nos permite acceder a cada página por separado.

from PyPDF2 import PdfReader

#Acceso al documento
leer_doc = PdfReader("pdf/Curriculo.pdf")
pag = len(leer_doc.pages)
pag_guardar= []

# Recorrer las páginas del documento asignándolas a los componentes de la lista pag_guardar
for i in range(pag):
    pagina = leer_doc.pages[i]
    pag_guardar.append(pagina.extract_text())

#Imprimir en consola

print("INICIO DEL TEXTO -----------------------\n")
for i in range(pag):
    print(pag_guardar[i] + "\n\n FÍN Página " + str(i+1) + "  -------------------------------\n\n")
print("\nFIN DEL TEXTO----------------------")

Puedes comparar este script con el que nos sirvió para acceder a las múltiples páginas del documento y cargarlas sobre la variable texto (4) y compararlo con el actual:

  • Observarás que ahora declaramos una lista para contener las diferentes páginas (pag_guardar= []) y no una variable.
  • Y lo que es más importante, ahora cargamos cada una de las páginas sobre cada uno de los elementos de la lista mediante la función append() (pag_guardar.append(pagina.extract_text())), siendo ésta la instrucción que sustituye a la que nos sirvió en su momento (texto += pagina.extract_text())
El resultado es un script realmente sencillo que después podemos "adornar" de diferentes maneras, incluyendo el que aquí presentamos en la parte final del script, que consiste en recorrer la lista mediante un bucle, mostrando página a página (5)



NOTAS

(1) Empecé por esta cuestión por ser evidente la carencia y a la vez por ser sencilla la solución. Desgraciadamente comprobamos que no es definitiva; pero sí prometedora (cuando funciona) para automatizar procedimientos de creación de soportes que emplean imágenes, como, por ejemplo, la creación de presentaciones.
(2) Aquí, por el momento, nos vamos a contentar con hacer posible la segmentación del documento en páginas, siguiendo la misma división que presenta el texto original.
(3) Remito a [la entrada] desde la que puedes acceder al documento
(4) Recuerda la instrucción que empleamos en ese script: texto += pagina.extract_text()
(5) No se trata ahora de plantear las múltiples formas con las que podemos trabajar con el contenido de cada página, pero, además del presentado se me ocurre, por ejemplo, el acceso selectivo a determinadas páginas.

miércoles, 10 de septiembre de 2025

Textos. Python.

Biblioteca PyPDF2. Imágenes.


Hasta este momento hemos visto como usar PyPDF2 para acceder al contenido de documentos pdf; también conocemos algunas de sus limitaciones, pero aun nos queda mucho por aprender respecto al acceso y el manejo de los datos recuperados. Es más, posiblemente lo realmente importante, lo que nos puede aportar soluciones de interés para nuestro trabajo, está aun por tratar. La idea es que empecemos a hacerlo en esta entrada.


Hasta ahora hemos traslado la referencia y acceso al texto obtenido mediante PyPDF2 a una variable y nos hemos limitado a mostrar ese contenido en pantalla, pero es difícil de sostener que ese esa un modo razonable de trabajar; es más, posiblemente esa sea una forma contraproducente y limitante de trabajar, responsable además de algunas de las limitaciones que hemos observado en la [entrada anterior]. Nos interesa ahora plantearnos formas más razonables de manejar y tratar el volumen de información al que nos permite acceder PyPDF2, aunque para ello debamos establecer, además, qué objetivos y con qué restricciones nos planteamos el uso de esta biblioteca.

Digo esto porque, dependiendo del objetivo, una teórica limitación puede serlo o no (o no tanto); y dependiendo de las restricciones (por ejemplo, qué tipo de documento pdf usamos como fuente de datos) nos deberemos plantear un procedimiento de trabajo u otro. Si lo que queremos es acceder a varios documentos y unificar todos los datos que contienen en uno único, no es lo mismo que si lo que nos interesa es acceder a un contenido o tipo de contenido en concreto. Si trabajamos con textos más o menos extensos basados en párrafos no es lo mismo que si trabajamos con textos muy estructurados en forma de tablas. 

Podría seguir planteando opciones y condiciones, pero lo que me interesa es transmitir que nuestro enfoque de trabajo puede ser diferentes según condiciones y objetivos, y que esa diferencia incide en qué consideremos ventaja o limitación, y, en consecuencia, también en cómo abordamos la solución de la segunda.

Dicho esto, por entrar en materia, consideremos una de las limitaciones que vimos en su momento, y uno de los aspectos en los que lo es: el acceso a las imágenes contenidas en un pdf, consideradas éstas como tales (1).

Dentro del interés por "apropiarnos" del contenido de un pdf puede estar hacerlo de las imágenes que contiene, sean estas gráficos de esquemas, fotografías o dibujos o gráficos estadísticos. Sabemos hasta ahora que PyPDF2 no permite acceder a esas imágenes; y sabemos también que, si son pocas, podemos capturarlas directamente mediante la funcionalidad Capturar pantalla, pero si son muchas o son muchos los documentos, automatizar la captura con Python sin duda es una buena solución (2).

Empecemos por la limitación y por cómo solucionarla: hasta ahora sabemos que PyPDF2 no permite extraer imágenes y hemos comprobado esta limitación en la práctica [ver entrada]; pero en realidad esta biblioteca cuenta con recursos para extraer las imágenes de un pdf. Veremos cómo hacerlo sobre un documento que versa sobre el arte Románico (3).

Suponemos la existencia de un directorio que contiene nuestro script, dentro del cual hemos creado un subdirectorio que contiene los archivos pdf (pdf), incluyendo en este caso el que nos interesa (ArteRomanico.pdf). Dentro de este subdirectorio creamos otro para guardar las imágenes (imgs).

El script podría ser el siguiente:

import PyPDF2

archivo = input("Nombre del archivo (sin la extensión): ")
lector = PyPDF2.PdfReader(f'pdf/{archivo}.pdf')

paginas = len(lector.pages)

for n_pag in range(paginas):
    pag = lector.pages[n_pag]
    for image_file_object in pag.images:
        with open(f'pdf/imgs/{str(n_pag)}__{image_file_object.name}', 'wb') as img:    
            img.write(image_file_object.data)

print ("Imágenes guardadas")

Después de cargar la biblioteca (import PyPDF2) (4) se desarrolla la primera fase del script, que consiste en los siguiente: 
  • Creamos un procedimiento interactivo basado en la función input() para  que el usuario aporte el nombre del archivo (que, como sabes, debe estar ubicado en el directorio pfd/) (archivo = input("Nombre del archivo (sin la extensión): ")). 
  • Sobre la variable lector construimos la instrucción basada en la función PdfReader(), la cual nos permite acceder al documento que contiene las imágenes (en nuestro caso ver 3) (lector = PyPDF2.PdfReader(f'pdf/{archivo}.pdf')).
  • Finalizamos asignando a la variable paginas el número de páginas del documento mediante la función len() (paginas = len(lector.pages)) (5)
La segunda fase del script se concreta como una estructura compleja de bucle que anida otro bucle, que a su vez contiene una instrucción with
  • El primer bucle (for n_pag in range(paginas):) recorre las páginas del documento y captura cada una de ellas en la variable pag (pag = lector.pages[n_pag])
  • El segundo bucle (anidado en el anterior) (for image_file_object in pag.images:) recorre la colección de imágenes que contiene cada una de las páginas del documento y desarrolla la instrucción with (6).
  • Ese instrucción desarrolla la acción de acceder al directorio y a las imágenes y las copia, y la finaliza, evitando que quede pendiente de ser finalizada (ver nota 6).
  • Finalmente añadimos una instrucción print() para informar del éxito del procedimiento (print ("Imágenes guardadas")) (7)
De esta forma tan sencilla hemos creado un "capturador" de imágenes que permite solucionar una de las limitaciones de PyPDF2. No siempre funciona bien (8), pero cuando lo hace resulta muy útil.


NOTAS

(1) Esto es, al margen de aquellas que contienen texto "fotografiado". Este segundo tipo requiere un tratamiento específico que no es posible dar con PyPDF2, como tendremos ocasión de comprobar.
(2) Observa que aquí abordamos una limitación y cómo superarla en el contexto del logro de un objetivo concreto (obtener imágenes de un documento pdf), planteándonos un manejo realista de la documentación resultante y con una doble posible condición: un pdf con muchas imágenes o una colección de pdf de los que nos interesa extraer las imágenes.
(3) Contexto: ArteRománico.pdf contiene una colección amplia de imágenes sobre el arte románico que, con los debidos permisos de uso, nos serán de utilidad para proporcionar material gráfico a un grupo de alumnos interesados por el tema. Para ello vamos a crear un script basado en PyPDF. Para lograr este objetivo me basaré en la información que aporta Programación para el mundo en You Tube.
(4) Recuerda que también puedes usar la fórmula from PyPDF2 import PdfReader, lo que te permite simplificar la estructura de la instrucción asociada a lector (lector = PyPDF2.PdfReader(f'pdf/{archivo}.pdf'))
(5) La función len() actúa sobre el atributo .pages del objeto (documento) asignado a la variable lector (en(lector.pages)), dado que ese atributo devuelve la colección formada por las páginas del documento.
(6) Según [los entendidos] esta permite ejecutar una acción que tiene un inicio (en nuestro caso el  fragmento de código que contiene la instrucción de acceso al subdirectorio imgs/ y a cada una de las imágenes de la página (open(f'pdf/imgs/{str(n_pag)}__{image_file_object.name}', 'wb') as img) y un final (en nuestro caso la "escritura de la imagen obtenida ( img.write(image_file_object.data))
(7) Aquí correspondería manejar la excepción mediante el procedimiento pertinente, pero dada la simplicidad del proyecto considero suficiente la información que aporta el IDE.
(8) De momento no tengo respuesta ni alternativa a esta limitación, la cual se da con más frecuencia de la deseada: no es infrecuente que PyPDF2 falle en el acceso a imágenes, bien por no detectarlas, por fracasar en el acceso a las mismas o por devolverlas como su negativo. 

martes, 9 de septiembre de 2025

Textos. Python.

Biblioteca PyPDF2. Limitaciones


Hasta ahora hemos visto diferentes formas de trabajar con documentos pdf para acceder a su contenido, pero nos hemos limitado a lo básico y positivo. Aunque lo que conseguimos así no es poco (1), la verdad es que nos hemos saltado algunas limitaciones y no podemos decir que la información obtenida resulte de fácil manejo. Dedicaremos esta entrada a exponer las limitaciones (algunas de las, para nosotros, más importantes) que presenta PyPDF2.


La primera y más radical de las limitaciones es que PyPDF2 no nos da acceso al contenido gráfico de los .pdf, incluyendo aquellas imágenes que siéndolo, contienen información textual.

Esto es así porque PyPDF2 no es un programa ocr, pero esta limitación, que puede ser menor si se trata de imágenes puras, es de cierta importancia cuando trabajamos con documentos pdf que contienen texto guardado como imagen. Este tipo de archivo pdf es más común de lo que creemos, especialmente si se trata de documentación antigua digitalizada; por ello puede suponer un hándicap de cierta importancia para la automatización del acceso a documentos pdf de cierta antigüedad y no tanta... (2).

Para probar lo dicho es suficiente con observar qué ha sucedido con la imagen de fondo del documento multi-página con el que trabajamos [en esta entrada], que simplemente ha desaparecido (3); pero lo que aquí es una ventaja, en este otro caso es un serio inconveniente.

Aunque el script ahora es lo de menos (lo que importa es el documento al que se accede), te remito al expuesto [en esta entrada], aunque debes cambiar la línea de acceso al pdf por esta otra (lector = PdfReader("pdf/DocImg.pdf")) para obtener el que ahora me interesa y cuyo contenido te muestro a continuación.


Como puede ver, no se trata de un documento antiguo ni difícil de trabajar con un ocr, pero sí cumple el criterio principal: aunque no lo parezca, es una captura de pantalla (img) pegada en un documento Writer, convertido posteriormente en un documento pdf. El procedimiento no se diferencia mucho del practicado en otro caso (4), pero el resultado es radicalmente distinto: en el primero obtenemos el contenido del documento, pero aplicado ese mismo script a este (DocImg.pdf) (5) el resultado es nada.

Esa misma limitación la observamos respecto a los elementos gráficos de este otro pdf (EvalTDAH.dpf) (6). Los gráficos estadísticos que contiene han desaparecido, aunque PyPDF2 nos permite rescatar cierta información asociada a ellos, cierto es que posiblemente de escaso interés. También nos permite acceder a la información de las tablas del documento (7), aunque se presentan de forma poco accesible. Pero lo posiblemente es aun más decepcionante es la forma en que aparece el texto en pantalla: al estar expresado en formato doble columna obtenemos líneas acortadas aunque correctas en cuanto a su sucesión; esto hace innecesariamente más extenso el texto y no facilita su lectura y el trabajo con su contenido (8).

Aquí nos encontramos, pues, con limitaciones/dificultades de uso de PyPDF2 que afectan a la presentación pero también a la recuperación y el manejo del texto. Incluso también, como resultado de lo segundo, al acceso a información concreta, siendo como es este el principal objetivo por el que usamos PyPDF2.

Vistas y demostradas en esta entrada limitaciones de relevancia para el uso que nosotros podemos hacer de PyPDF2, me propongo en entradas próximas a presentar soluciones, incluyendo aquellas que requieran recursos complementarios a esta librería, pero sobre todo avanzando (eso pretende) en un uso más potente de lo que Python nos puede aportar.

Documentos.

NOTAS

(1) Y da para unas cuantas cosas, algunas de las cuales veremos en otro momento.
(2) Estoy pensando por ejemplo en el trabajo con informes médicos que, por su formato, resultan complicados de escanear como texto, por lo que se suele recurrir al escaneo como imagen. 
(3) Cosa que en este caso nos viene bien, ya que lejos de aportar algo sólo podría servir para dificultar la lectura automatizada del documento.
(4) Salvo el tratamiento como img, el resto del procedimiento es exactamente el mismo que seguí para crear VueltaCavernas.pdf. Ten en cuenta que esta misma limitación la tenemos para acceder a pdf que contienen controles de formulario: en ellos podemos acceder a los elementos textuales de las tablas, pero no al contenido escrito en los controles. Esto supone una seria limitación, de la cual no hablamos en esta entrada por corresponder a desarrollos o aplicaciones concretas de PyPDF2 como herramienta de automatización a documentos. 
(5) Enlace para acceso, abajo, en Documentos
(6) Por tratarse ahora de un documento multi-página deberemos utilizar el script presentado [en esta entrada] de nuevo modificando la instrucción que especifica el archivo al que accedemos (lector = PdfReader("pdf/EvalTDAH.pdf")). También es este caso puedes acceder al pdf desde Documentos.
(7) ver, por ejemplo, el contenido de la página 6 del documento en la versión pdf del mismo y en el texto que el script devuelve en pantalla.
(8) Mucho más aun el acceso contenido específico que nos pudiera interesar. Este en, en realidad, la segunda de las limitaciones o dificultades de las que hablo en la intro de esta entrada.

Textos. Python

Biblioteca PyPDF2. Múltiples archivos


Tarea complementaria de la anterior (acceder a múltiples páginas) es la que me propongo resolver ahora: acceder de forma automatizada a varios archivos. Se trata también de una práctica que, sin duda, realizaremos con cierta frecuencia, así que interesa aprender cómo.


Realmente es menos relevante para este objetivo que nos interese una única página que sean varias (o todo el documento), pero sí es seguro que automatizar el acceso a varios documento nos va a ser de mucha ayuda, sea para la mera captura del texto de múltiples documento o para la búsqueda selectiva de información concreta en múltiples documentos de igual estructura.

Para llevar a cabo esta tarea, además de PyPDF2 necesitamos utilizar también la biblioteca os, gracias a la cual podremos automatizar el acceso a todos los documentos ubicados en un directorio determinado. Lo que resta es tarea que corresponde a PyPFD2, como veremos a continuación.

Para esta práctica he creado un directorio auxiliar llamado coleccion1, que contiene cinco documentos pdf simples (de una única página) que son la repetición de uno con el que ya trabajamos en [esta entrada] (1). Este es el código del script

import os
from PyPDF2 import PdfReader

#Accedo a directorio pdf/coleccion1
os.chdir('pdf/coleccion1')

#Creo variables para acceso al contenido de los documentos
texto = ''
separador = "\n\nSiguiente documento--------------\n\n"

#Listo los componentes del directorio
lista_archivos = os.listdir('.')

#... y los recorro accediendo al contenido, además de contarlos para identificar su número
i = 0
for lista in lista_archivos:
    lector = PdfReader(lista)
    pagina = lector.pages[0]
    texto += pagina.extract_text() + separador
    print(lista)
    i = i + 1

#Imprimo en pantalla el número de registros...
print("Número total de archivos " + str(i))

# y su contenido
print("\nINICIO DEL DOCUMENTO PDF ------------------------\n")
print(texto)
print("\nFIN DEL TEXTO DEL DOCUMENTO PDF ----------------")

Gracias a la biblioteca os y siguiendo el procedimiento ya explicado [en esta entrada] puedo acceder a los archivos del directorio que me interesa (2) y mediante el bucle (for lista in lista_archivos:) los recorro accediendo a su contenido gracias a (lector = PdfReader(lista)) y al procedimiento de acceso a la página (pagina = lector.pages[0]). El procedimiento finalizar, como ya sabemos, asignando acumulativamente el contenido de cada página a la variable texto (texto += pagina.extract_text() + separador), que después imprimimos por pantalla (print(texto)), aunque podríamos tratar de otro modo.

Si en lugar de trabajar con documentos pdf de una página trabajáramos con otros de múltiples páginas, pero sólo quisiéramos acceder al contenido de una de ellas, usaríamos el mismo script modificando la referencia al directorio (vg. os.chdir('pdf/coleccion2')) y el índice de la página en la instrucción (pagina = lector.pages[4]) (3).

Finalmente puede que nos interese acceder a todo el contenido de unos archivos multi-página. Para ello partiremos del script anterior, pero modificándolo de forma sustancial...

import os
from PyPDF2 import PdfReader

#Accedo a directorio pdf/coleccion2
os.chdir('pdf/coleccion2')

#Creo variables para acceso al contenido de los documentos
pag = 0
texto = ''
separador = "\n\nSiguiente documento--------------\n\n"

#Listo los componentes del directorio...
lista_archivos = os.listdir('.')

#... y los muestro en pantalla
i = 0
print("Listado de los archivos del directorio")
for lista in lista_archivos:
    print(lista)
    i = i +1
print("Número total de archivos " + str(i))

# Vuelvo a recorrer la lista de archivos, copio su contenido...
for lista in lista_archivos:
    lector = PdfReader(lista)
    pag = len(lector.pages)
    for pg in range(pag):
        pagina = lector.pages[pg]
        texto += pagina.extract_text()

# y lo muestro en pantalla
print("\nINICIO DEL DOCUMENTO PDF ------------------------\n")
print(texto)
print("\nFIN DEL TEXTO DEL DOCUMENTO PDF ----------------")

... primero, para hacerlo más claro separo el recorrido del directorio y la escritura del título de los documentos y su conteo a un bucle específico...

i = 0
print("Listado de los archivos del directorio")
for lista in lista_archivos:
    print(lista)
    i = i +1
print("Número total de archivos " + str(i))

... y segundo, recorro todas las páginas de cada uno de los archivos y las paso a la variable texto mediante un segundo bucle que recorre de nuevo los archivos y anida un segundo bucle que recorre las páginas de los documentos (4).

for lista in lista_archivos: # Primer bucle: recorre los archivos del directorio
    lector = PdfReader(lista)
    pag = len(lector.pages)
    for pg in range(pag): # Segundo bucle: recorre todas las páginas de cada uno de los pdf.
        pagina = lector.pages[pg]
        texto += pagina.extract_text()


NOTAS

(1) De este modo me ahorro subir los archivos, aunque tú tendrás que replicar la carpeta y su contenido. Recuerda crear dentro de coleccion1 de VueltaCavernas0.pdf a VueltaCavernas4.pdf.
(2) En este script mostrarlos en pantalla y contarlos es sólo un modo de conocer que el procedimiento funciona correctamente.
(3) Para este ejemplo he creado un segundo directorio (coleccion2) que contiene repetido el archivo multi-página usado en [esta entrada]. Para crear el script que acceda a una de sus páginas (la 5, en el ejemplo indicado en cuerpo de la entrada) sólo tienes que realizar sobre el explicado los cambios que se proponen.
(4) Para esta tercera opción puedes usar el mismo directorio que en la segunda versión del primer script (ver nota 3)