informatica:programacion:cursos:python_avanzado_proyectos_seguridad:extraccion_metadatos_documentos_modulo_pypdf2

Extracción de metadatos en documentos con el módulo PyPDF2

Módulo perteneciente al curso Python avanzado para proyectos de seguridad

Uno de los módulos disponibles en Python para extraer datos de documentos PDF es PyPDF2.

Metadatos son datos que describen otros datos. El metadato puede ser texto, voz o imagen. El metadato ayuda a clarificar y encontrar datos. Por ejemplo, el metadato podría documentar atributos (nombre, tamaño, tipo de dato, etc), las estructuras de los datos (longitud, columnas, campos, etc), y datos sobre datos (donde está localizado, cómo está asociado, etc.). Un ejemplo de metadato es lo que se guarda en los sistemas de archivo. Para cada archivo informático almacenado se puede llegar a guardar la siguiente información: fecha y hora de creación, fecha y hora de modificación, última vez que fue accedido. Los metadatos se usan para facilitar la gestión de datos, ofreciendo información adicional sobre el contenido.

El módulo se puede descargar directamente con el comando pip install pypdf2 ya que se encuentra el repositorio oficial de Python: http://pypi.python.org/pypi/PyPDF2

Si ejecutamos los siguientes comandos desde el intérprete de python podemos obtener la ayuda del módulo.

>>> import PyPDF2
>>> dir(PyPDF2)

Si consultamos la ayuda del módulo, vemos que hay varias clases definidas, nosotros nos centraremos en la clase PdfFileReader.

En la siguiente imagen podemos ver los parámetros que acepta el constructor de esta clase:

Obtención de metadatos con PdfFileReader

El método que podríamos utilizar para obtener la información de un documento PDF es getDocumentInfo(), que devuelve un diccionario con los datos del documento. En la siguiente imagen podemos ver una descripción de este método perteneciente a la clase PdfFileReader:

El siguiente script nos permitiría obtener la información del documento pdf que se encuentra en la ruta pdf/TutorialPython3.pdf.

Puede encontrar el siguiente código en el archivo extraer_metadatos_pdf.py:

#!usr/bin/env python
 
from PyPDF2 import PdfFileReader
 
def get_metadatos_ruta_pdf():
 
    print("[+ Metadatos /pdf/TutorialPython3.pdf")
    pdf = PdfFileReader(open("pdf/TutorialPython3.pdf", 'rb'))
    info = pdf.getDocumentInfo()
    print(info)
 
get_metadatos_ruta_pdf()

Extraer información y metadatos XMP de documentos PDF

Para almacenar los metadatos, los ficheros PDF usan Extensible Metadata Platform (XMP). XMP se crea en XML, lo que facilita el intercambio de metadatos entre diversas aplicaciones y la publicación de flujos de trabajo. Los metadatos en la mayoría de los demás formatos (como Exif, GPS o TIFF) se transfieren de manera automática a XMP para facilitar su visualización y gestión.

El módulo pypdf2 proporciona el método getXmpMetadata() para obtener otra información relacionada con el documento, como los creadores, el editor y la versión en pdf.

El siguiente script nos permitiría obtener la información de todos los documentos PDF que se encuentren en la carpeta “pdf”.

Puede encontrar el siguiente código en el archivo extraer_metadatos_carpeta_pdf.py:

#!usr/bin/env python
 
from PyPDF2 import PdfFileReader
import os, os.path
 
def get_metadatos_carpeta_pdf():
    for dirpath, dirnames, files in os.walk("pdf"):
        for data in files:
            ext = data.lower().rsplit('.', 1)[-1]
            if ext in ['pdf']:
                print("[+Metadatos: %s " %(dirpath+os.path.sep+data))
                pdf = PdfFileReader(open(dirpath+os.path.sep+data, 'rb'))
                info = pdf.getDocumentInfo()
                for metadato in info:
                    print ('[+] ' + metadato.strip( '/' ) + ': ' + info[metadato])
 
                xmpinfo = pdf.getXmpMetadata()
                if hasattr(xmpinfo,'dc_contributor'):
                    print ('[+] Contributor:', xmpinfo.dc_contributor)
                if hasattr(xmpinfo,'dc_identifier'):
                    print ('[+] Identifier:', xmpinfo.dc_identifier)
                if hasattr(xmpinfo,'dc_date'):
                    print ('[+] Date:',xmpinfo.dc_date)
                if hasattr(xmpinfo,'dc_source'):
                    print ('[+] Source:', xmpinfo.dc_source)
                if hasattr(xmpinfo,'dc_subject'):
                    print ('[+] Subject:', xmpinfo.dc_subject)
                if hasattr(xmpinfo,'xmp_modifyDate'):
                    print ('[+] ModifyDate:', xmpinfo.xmp_modifyDate)
                if hasattr(xmpinfo,'xmp_metadataDate'):
                    print ('[+] MetadataDate:', xmpinfo.xmp_metadataDate)
                if hasattr(xmpinfo,'xmpmm_documentId'):
                    print ('[+] DocumentId:', xmpinfo.xmpmm_documentId)
                if hasattr(xmpinfo,'xmpmm_instanceId'):
                    print ('[+] InstanceId:', xmpinfo.xmpmm_instanceId)
                if hasattr(xmpinfo,'pdf_keywords'):
                    print ('[+] PDF-Keywords:', xmpinfo.pdf_keywords)
                if hasattr(xmpinfo,'pdf_pdfversion'):
                    print ('[+] PDF-Version:', xmpinfo.pdf_pdfversion)
 
get_metadatos_carpeta_pdf()

En la función get_metadatos_carpeta_pdf() usamos el método walk dentro del módulo os (operating system) que es útil para recorrer todos los ficheros y directorios que se encuentran incluidos en un directorio específico.

En el código anterior extraemos los metadatos xmp del documento comprobando previamente con el método hasattr() para comprobar si una determinada propiedad se encuentra dentro del objeto xmpinfo antes de poder acceder a dicha información.

Actividad práctica: Completar el código que permite obtener los metados del documento PDF que se encuentra en la ruta indicada

Completar el código que permite obtener los metadatos del documento PDF que se encuentran en la ruta indicada.

#!usr/bin/env python
 
from PyPDF2 import xxx
 
fichero = 'pdf/XMPSpecificationPart3.pdf'
 
pdf = xxx(open(xxx, 'rb'))
 
print("[+] Pages number:",pdf.xxx())
 
info = pdf.xxx()
 
if hasattr(info,'author'):
    print("[+] Author:",info.xxx)
if hasattr(info,'creator'):
    print("[+] Creator:",info.xxx)
if hasattr(info,'producer'):
    print("[+] Producer:",info.xxx)
 
xmpinfo = pdf.xxx()
 
if hasattr(xmpinfo,'dc_contributor'):
    print ('[+] Contributor:', xmpinfo.xxx)
if hasattr(xmpinfo,'dc_identifier'):
    print ('[+] Identifier:', xmpinfo.xxx)
if hasattr(xmpinfo,'dc_date'):
    print ('[+] Date:',xmpinfo.dc_date)
if hasattr(xmpinfo,'dc_source'):
    print ('[+] Source:', xmpinfo.xxx)
if hasattr(xmpinfo,'dc_subject'):
    print ('[+] Subject:', xmpinfo.xxx)
if hasattr(xmpinfo,'xmp_modifyDate'):
    print ('[+] ModifyDate:', xmpinfo.xxx)
if hasattr(xmpinfo,'xmp_metadataDate'):
    print ('[+] MetadataDate:', xmpinfo.xxx)
if hasattr(xmpinfo,'xmpmm_documentId'):
    print ('[+] DocumentId:', xmpinfo.xxx)
if hasattr(xmpinfo,'xmpmm_instanceId'):
    print ('[+] InstanceId:', xmpinfo.xxx)
if hasattr(xmpinfo,'pdf_keywords'):
    print ('[+] PDF-Keywords:', xmpinfo.xxx)
if hasattr(xmpinfo,'pdf_pdfversion'):
    print ('[+] PDF-Version:', xmpinfo.xxx)

La salida del script debería ser la siguiente:

[+] Pages number: 86
[+] Author: Adobe Developer Technologies
[+] Creator: FrameMaker 7.2
[+] Producer: Acrobat Distiller 8.1.0 (Windows)
[+] Contributor: []
[+] Identifier: None
[+] Date: []
[+] Source: None
[+] Subject: []
[+] ModifyDate: 2008-09-16 15:43:43
[+] MetadataDate: 2008-09-16 15:43:43
[+] DocumentId: uuid:a2a0d182-7b1c-4801-a22c-d610115116bd
[+] InstanceId: uuid:1a365cee-e070-4b52-8278-db5e46b20a4c
[+] PDF-Keywords: XMP metadata Exif IPTC PSIR file I/O
[+] PDF-Version: None

Solución

#!usr/bin/env python
 
from PyPDF2 import PdfReader
 
fichero = 'XMPSpecificationPart3.pdf'
 
pdf = PdfReader(open(fichero, 'rb'))
 
print("[+] Pages number:", len(pdf.pages))
 
info = pdf.metadata
 
if hasattr(info, 'author'):
    print("[+] Author:", info.author)
if hasattr(info, 'creator'):
    print("[+] Creator:", info.creator)
if hasattr(info, 'producer'):
    print("[+] Producer:", info.producer)
 
xmpinfo = pdf.xmp_metadata
 
if hasattr(xmpinfo, 'dc_contributor'):
    print ('[+] Contributor:', xmpinfo.dc_contributor)
if hasattr(xmpinfo, 'dc_identifier'):
    print ('[+] Identifier:', xmpinfo.dc_identifier)
if hasattr(xmpinfo, 'dc_date'):
    print ('[+] Date:', xmpinfo.dc_date)
if hasattr(xmpinfo, 'dc_source'):
    print ('[+] Source:', xmpinfo.dc_source)
if hasattr(xmpinfo, 'dc_subject'):
    print ('[+] Subject:', xmpinfo.dc_subject)
if hasattr(xmpinfo, 'xmp_modify_date'):
    print ('[+] ModifyDate:', xmpinfo.xmp_modify_date)
if hasattr(xmpinfo, 'xmp_metadata_date'):
    print ('[+] MetadataDate:', xmpinfo.xmp_metadata_date)
if hasattr(xmpinfo, 'xmpmm_document_id'):
    print ('[+] DocumentId:', xmpinfo.xmpmm_document_id)
if hasattr(xmpinfo, 'xmpmm_instance_id'):
    print ('[+] InstanceId:', xmpinfo.xmpmm_instance_id)
if hasattr(xmpinfo, 'pdf_keywords'):
    print ('[+] PDF-Keywords:', xmpinfo.pdf_keywords)
if hasattr(xmpinfo, 'pdf_pdfversion'):
    print ('[+] PDF-Version:', xmpinfo.pdf_pdfversion)

Extraer imágenes de un documento PDF

Para extraer imágenes de un documento PDF tenemos diferentes alternativas.

Si usamos una distribución basada en Debian como Ubuntu podríamos instalar la aplicación de línea de comandos pdfimages.

Esta herramienta la podemos utilizar con el comando:

$ apt-get install poppler-utils

Pdfimages permite extraer imágenes de documentos PDF en sistemas operativos Linux / UNIX. y guarda imágenes en formatos como Portable Pixmap (PPM), Portable Bitmap (PBM) o archivos JPEG.

Para cada imagen que detecta en el documento crear un fichero con el formato nnn.xxx, donde nnn es el número de imagen y xxx es el tipo de imagen (.ppm, .pbm, .jpg).

Para ejecutar la herramienta bastaría con pasarle como argumento la ruta del pdf y el directorio donde queremos extraer las imágenes:

$ pdfimages pdf/TutorialPython3.pdf ./imagenes

El siguiente script utiliza el comando anterior con el módulo subprocess para realizar este proceso.

Puede encontrar el siguiente código en el archivo extraer_imagenes_pdf_subprocess.py:

import subprocess
subprocess.run('pdfimages pdf/TutorialPython3.pdf ./imagenes', shell=True)

Otra alternativa que tenemos para extraer las imágenes es usar el módulo pymupdf:

Este módulo se podría instalar con las siguientes instrucciones en ubuntu:

sudo apt install python3-pip
sudo -H pip3 install --upgrade pip
sudo -H python3.6 -m pip install -U pymupdf

La forma de usar este módulo es usando la clase fitz que dispone de métodos para abrir el fichero y extraer las imágenes en formato PNG.

Puede encontrar el siguiente código en el archivo extract_images_fitz.py:

#!usr/bin/env python
 
import fitz
 
doc = fitz.open("pdf/TutorialPython3.pdf")
 
for i in range(len(doc)):
    for img in doc.getPageImageList(i):
        xref = img[0]
        pix = fitz.Pixmap(doc, xref)
        if pix.n < 5:       # this is GRAY or RGB
            pix.writePNG("p%s-%s.png" % (i, xref))
        else:               # CMYK: convert to RGB first
            pix1 = fitz.Pixmap(fitz.csRGB, pix)
            pix1.writePNG("p%s-%s.png" % (i, xref))
            pix1 = None
        pix = None

El script anterior extrae las imágenes y las guarda en formato PNG en el directorio de trabajo donde estás ejecutando el script.

Otras herramientas

Peepdf es una herramienta de Python que analiza archivos PDF y nos permite visualizar todos los objetos incrustados en el documento. También tiene la capacidad de analizar diferentes versiones de un archivo PDF, secuencias de objetos y archivos cifrados, así como modificar y ofuscar archivos PDF.

El objetivo de esta herramienta es proporcionar todos los componentes necesarios que un investigador de seguridad podría necesitar en un análisis PDF sin utilizar más de una herramienta para realizar todas las tareas.

Para ejecutarlo bastaría con pasarle por parámetro un fichero pdf y nos devolvería toda la información relacionada con firmas hash, tamaño del fichero, encriptación y objetos que tenga el documento respecto a imágenes y streams de datos.

File: TutorialPython3.pdf
MD5: 858dfc990a4c90a5045092bc453c8746
SHA1: 0dff694d630cffe97aeb7d1f2e1f064d434d4b3e
Size: 2657251 bytes
Version: 1.4
Binary: True
Linearized: False
Encrypted: False
Updates: 0
Objects: 2539
Streams: 727
Comments: 0
Errors: 0
informatica/programacion/cursos/python_avanzado_proyectos_seguridad/extraccion_metadatos_documentos_modulo_pypdf2.txt · Última modificación: por tempwin