<jupyter_start><jupyter_text>[![imagenes/pythonista.png](imagenes/pythonista.png)](https://pythonista.io)  Creación y lectura de archivos en formato *PDF*. El formato *PDF* es un [estándar internacional](https://www.iso.org/standard/51502.html) para la creación de documentos que pueden ser desplegados o impresos de forma idéntica independientemente del dispositivo o aplicación que acceda a dichos documentos.El énfasis del formato *PDF* reside en la correcta legibilidad de la información para los seres humanos, poniendo en segundo término la estructura y orden de la información que contiene.  El paquete ```pdfkit```.El paquete ```pdfkit``` es una empaquetador (*wrapper*) de *Python* para la herramienta ```wkhtmltopdf```, el cual permite crear documentos *PDF* a partir de código *HTML*.  La herramienta ```wkhtmltopdf```.El proyecto https://wkhtmltopdf.org/ ofrece una herramienta capaz de transformar código *HTML* en documentos *PDF*. Dicha herramienta se ejecuta directamente como un comando del sistema con la sintaxis.```wkhtmltopdf   ``` La ejecución de ```wkhtmltopdf``` requiere del uso de la biblioteca [*Qt*](https://www.qt.io/). En el caso de las instalaciones en sistemas Windows, los binarios incluyen lo necesario para poder ejecutar la herramienta desde una terminal. Del mismo modo, los sistemas de escritorio basados en *GNU/Linux* también cuentan con un entorno gráfico gestionado por un *servidor X*. Sin embargo, es muy común que un servidor basado en *GNU/Linux* no cuente con un *servidor X* instalado.Para que ```pdfkit``` pueda funcionar, es necesario que el ejecutable de ```wkhtmltopdf``` se encuentre en una ruta conocida, por lo que en el caso de Windows, es necesario añadir esta ruta a la variable de entorno *PATH*.  Instalación de ```wkhtmltopdf``` en un *servidor X* virtual en *Ubuntu*.La máquina virtual que fue descargada del sitio http://pythonista.io no cuenta con un *servidor X*, por lo que es necesario instalarlo al igual que el paquete ```wkhtmltopdf```.**Nota:** Este ejercicio representa el caso menos favorable. Si se utiliza esta herramienta desde un sistema *Windows* o desde un entorno gráfico *GNU/Linux*, el uso de esta herramienta es mucho más simple.  Instalación y configuración del *servidor X* virtual.El servidor X virtual o *X Virtual FrameBuffer* (*xvfb*) es una variante de un *servidor X* que realiza las mismas opraciones que uno convencional, pero no se despliega en pantalla. Se utiliza para realizar operaciones que requieren de un entrono gráfico en un sistema *GNU/Linux*. * La siguiente celda instalará *X Virtual FrameBuffer*.<jupyter_code>!sudo apt install xvfb -y<jupyter_output><empty_output><jupyter_text>Creación del archivo de definición de servicio.Una vez instalado *xvfb*, es necesario habilitarlo como un servicio añadiendo el archivo [```src/xvfb.service```](src/xvfb.service) en ```/etc/systemd/system/```.Dicho archivo contiene el siguiente código:``` bash[Unit]Description=Virtual Frame Buffer X ServerAfter=network.target[Service]ExecStart=/usr/bin/Xvfb :42 -screen 0 1024x768x24 -ac +extension GLX +render -noreset[Install]WantedBy=multi-user.target``` * La siguiente celda copiará el archivo ```src/xvfb.service``` en ```/etc/systemd/system/```.**Nota:** Es necesario tener permisos de administrador para ejecutar la siguiente operación.<jupyter_code>!sudo cp src/xvfb.service /etc/systemd/system/<jupyter_output><empty_output><jupyter_text>Habilitación y puesta en marcha del servicio.Las siguientes celdas habilitarán e iniciarán el servicio ```xvfb``` mediante el comando ```systemctl```.<jupyter_code>!sudo systemctl enable xvfb
!sudo systemctl start xvfb<jupyter_output><empty_output><jupyter_text>Para comprobar que el servidor está corriendo ejecute lo siguiente:<jupyter_code>!sudo systemctl status xvfb --no-pager<jupyter_output><empty_output><jupyter_text>**Nota:** Este procedimiento sólo se requiere hace una vez. Una vez instalado, configurado y habilitado, el servicio iniciará junto con el servidor.  Instalación y configuración de ```wkhtmltopdf```.* La siguiente celda instalará ```wkhtmltopdf```.<jupyter_code>!sudo apt install wkhtmltopdf -y<jupyter_output><empty_output><jupyter_text>Es necesario que ```wkthmltopdf``` pueda acceder al servidor virtual, por lo que se debe de crear un script que incluya al comando ```xvfb-run``` el cual le indica al sistema que la instrucción hará uso de un *servidor X* virtual.El script [```src/wkhtmltopdf.sh```](src/wkhtmltopdf.sh) contiene el siguiente código:``` bash!/bin/bashxvfb-run -a --server-args="-screen 0, 1280x800x24" /usr/bin/wkhtmltopdf -q $*``` * El script en cuestión debe de contar con permisos de ejecución, lo cual se realiza de la siguiente manera.<jupyter_code>!chmod +x src/wkhtmltopdf.sh<jupyter_output><empty_output><jupyter_text>Ejecución del script.**Nota:** Este es un ejemplo de ejecución en la línea de comandos. No es código en *Python*. La siguiente celda ejecutará el script [```src/wkhtmltopdf.sh```]([src/wkhtmltopdf.sh]) * Se conectará a http://google/com.* El contenido será convertido a PDF y guarado en [```google.pdf```](google.pdf).<jupyter_code>!src/wkhtmltopdf.sh http://google.com google.pdf<jupyter_output><empty_output><jupyter_text>Instalación de ```wkhtmltopdf``` en *Windows*.En el caso de Windows sólo es necesario descargar  el instalador desde:https://wkhtmltopdf.org/downloads.htmlPor lo general, el ejecutable se lozaliza en ```C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe``` **Ejemplo:**La siguiente celda ejecutará ```wkhtmltopdf.exe``` en la ruta indicada. * Se conectará a http://google/com.* El contenido será convertido a *PDF* y creará al archivo [```google.pdf```](google.pdf).<jupyter_code>!"C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf" "https://google.com" "google.pdf"<jupyter_output><empty_output><jupyter_text>Instalación del paquete ```pdfkit```.Una vez instalado ```wkhtmltopdf``` en la plataforma correspondiente, es posible instalar el paquete ```pdfkit```. * La siguiente celda instalará el paquete ```pdfkit```.<jupyter_code>!pip install pdfkit<jupyter_output><empty_output><jupyter_text>* La siguiente celda importará al paquete.<jupyter_code>import pdfkit<jupyter_output><empty_output><jupyter_text>Funciones de ```pdfkit``` dependiendo la fuente de los datos.Este paquete permite transformar código *HTML* desde diversas fuentes.* Si el código *HTML* es ingresado como una cadena de caracteres se utiliza la función ```pdfkit.fromstring()``` con la siguiente  sintaxis:```pdfkit.fromstring(, '', )```* Si el código *HTML* proviene de un archivo local, se utiliza la función ```pdfkit.fromfile()``` con la siguiente  sintaxis:```pdfkit.fromfile('', '', )```* Si el código *HTML* proviene de un recurso en línea, se utiliza la función ```pdfkit.fromurl()``` con la siguiente  sintaxis:```pdfkit.fromurl('', '', )```  El objeto ```pdfkit.configuration```.El objeto ```pdfkit.configuration``` permite ingresar diversos parámetros de configuración y en este caso se puede indicar dónde se encuentra el archivo ejecutable de ```wkhtmltopdf``` con la siguiente sintaxis:```pdfkit.configuration(wkhtmltopdf='')```  Configuración en  *Ubuntu*.La configuración de ```pdfkit``` apuntará al script localizado en [```src/wkhtmltopdf.sh```](src/wkhtmltopdf.sh).<jupyter_code>conf = pdfkit.configuration(wkhtmltopdf='src/wkhtmltopdf.sh')<jupyter_output><empty_output><jupyter_text>Configuración en *Windows*.La configuración de ```pdfkit``` apuntará al ejecutable localizado en ```C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe```<jupyter_code>conf = pdfkit.configuration(wkhtmltopdf='C:\\Program Files\\wkhtmltopdf\\bin\\wkhtmltopdf.exe')<jupyter_output><empty_output><jupyter_text>Ejemplos de uso. * La siguiente celda convertirá el contenido del archivo [```html/menu.html```](html/menu.html) y creará el archivo [```menu.pdf```](menu.pdf).<jupyter_code>pdfkit.from_file('html/menu.html', 'menu.pdf', configuration=conf)<jupyter_output><empty_output><jupyter_text>* La siguiente celda se conectará a https://www.pythonista.io y creará el archivo [```pythonista.pdf```](pythonista.pdf).<jupyter_code>pdfkit.from_url('https://www.pythonista.io ',
                'pythonista.pdf', configuration=conf)<jupyter_output><empty_output><jupyter_text>El parámetro ```options```.Es posible modificar el tipo y orientación de la página, el tamaño de los márgenes y algunas otras características del documento PDF resultante mediante algunas opciones de ```wkhtmltopdf```, las cuales pueden ser consultadas en:https://github.com/worlduniting/bookshop/wiki/wkhtmltopdf-optionsEn el caso de ```pdfkit``` estas opciones deben de estar contenidas en un objeto tipo ```dict```. **Ejemplo:**Se creará nuevamente el archivo [```menu_oficio.pdf```](menu_oficio.pdf) con algunos ajustes a los márgenes e indicando el tipo de tamano de papel.<jupyter_code>options = {
    'page-size': 'Legal',
    'margin-top': '0.75in',
    'margin-right': '0.75in',
    'margin-bottom': '0.75in',
    'margin-left': '0.75in',
    'encoding': "UTF-8"
}
pdfkit.from_file('html/menu.html', 'menu_oficio.pdf', configuration=conf, options=options)<jupyter_output><empty_output><jupyter_text>Lectura de documentos *PDF* con ```pdfminer.six```.El paquete ```pdfminer.six``` es una implementación compatible con *Python 3* de ```pdfminer```. Es una herramienta especializada para la extracción de texto muy popular. Tiene la ventaja de acceder a porciones específicas de un documento *PDF* y gestionarlas en memoria.Los paquetes ```pdfminer``` y ```pdfminer.six``` cuentan con múltiples clases especializadas en gestionar, seleccionar, obtener, interpretar y convertir porciones específicas de un documento *PDF*.Para mayor información consultar la documentación localizada en:https://pdfminer-docs.readthedocs.io/ * La siguiente celda instalará el paquete ```pdfminer.six```.<jupyter_code>!pip install pdfminer.six<jupyter_output><empty_output><jupyter_text>Gestión de flujos de texto en memoria. El módulo ```io``` de la biblioteca estándar de *Python* contiene herramientas que facilitan el uso de flujos de entrada y salidas de datos. * La clase ```io.StringIO``` del módulo permite acceder a un flujo de datos en memoria como si fuera una cadena de caracteres. El paquete ```pdfminer``` aprovecha este tipo de objetos para manipular el contenido de un documento *PDF*.Para mayor información sobre el módulo ```io.StringIO``` puede ser consultsada desde:https://docs.python.org/3/library/io.htmltext-i-o<jupyter_code>from io import StringIO<jupyter_output><empty_output><jupyter_text>El módulo ```pdfminer.pdfinterp```.* ```PDFResourceManager```, cuyas instancias son capaces de gestionar el flujo de recursos de un documento *PDF* a los que ```pdfminer``` accede. En este caso, se encargará de  gestionar el flujo entre un archivo y el buffer en memoria.* ```PDFPageInterpreter```, cuyas instancias tienen la capacidad de acceder e interpetar el contenido de un recurso proveniente de un archivo *PDF*.<jupyter_code>from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter<jupyter_output><empty_output><jupyter_text>El módulo ```pdfminer.converter```.Contiene varias clases capaces de convertir contenidos específicos de un documento PDF, tales como XML, HTML o texto.* En este caso, se utilizará la clase ```TextConverter```.<jupyter_code>from pdfminer.converter import TextConverter<jupyter_output><empty_output><jupyter_text>El módulo ```pdfminer.layout```.Los archivos PDF incluyen por lo general una plantilla (layout) específica del documento que puede definir el tamaño de página, orientacion, numeración, márgenes, etc.La clase ```pdfminer.layout.LAParams```, se encarga de obtener los parámetros definidos en la plantilla de un documento *PDF*.<jupyter_code>from pdfminer.layout import LAParams<jupyter_output><empty_output><jupyter_text>El módulo ```pdfminer.pdfpage```.Los documentos PDF está compuestos por páginas cuyas características están definidas en los parámetros de la plantilla correspondiente.* La clase ```pdfminer.pdfpage.PDFPage``` crea objetos que emulan a una página del documento PDF.<jupyter_code>from pdfminer.pdfpage import PDFPage<jupyter_output><empty_output><jupyter_text>Extracción de un documento *PDF* .A continuacion se creará una función capaz de extraer el texto de las páginas indicadas desde un archivo *PDF*. * La función ```convierte()``` permite extraer el texto de las páginas enumeradas dentro de un objeto iterable que se ingresa como el argumento ```paginas``` a partir del archivo definido en el parámetro ```ruta```. En caso de no indicarlos, extraerá el texto de todas las páginas del documento.<jupyter_code>def convierte(ruta, paginas=None):
    if not paginas:
        numero_paginas = set()
    else:
        numero_paginas = set(paginas)
    salida = StringIO()
    gestor = PDFResourceManager()
    convertidor = TextConverter(gestor, salida, laparams=LAParams())
    interprete = PDFPageInterpreter(gestor, convertidor)

    archivo = open(ruta, 'rb')
    for pagina in PDFPage.get_pages(archivo, numero_paginas):
        interprete.process_page(pagina)
    archivo.close()
    convertidor.close()
    texto = salida.getvalue()
    salida.close
    return texto<jupyter_output><empty_output><jupyter_text>**Ejemplos:*** Se obtendrá el texto de la segunda página del archivo [*menu.pdf*](menu.pdf) que fue creado previamente.<jupyter_code>print(convierte('menu.pdf', paginas=[1]))<jupyter_output><empty_output><jupyter_text>* Se obtendrá el texto completo del archivo [*menu.pdf*](menu.pdf).<jupyter_code>convierte('menu.pdf')<jupyter_output><empty_output><jupyter_text>Lectura de documentos *PDF* con ```pdftotext```.Este paquete es una implementación de la biblioteca [*poppler*](https://poppler.freedesktop.org/), perteneciente a [XpdfReader](https://www.xpdfreader.com/). Este paquete corre en Linux, UNIX y MacOS X.<jupyter_code>!sudo apt install libpoppler-cpp-dev pkg-config -y
!pip install pdftotext
import pdftotext<jupyter_output><empty_output><jupyter_text>La clase *pdftotext.PDF* permite crear un objeto iterador que contienen el texto extraido de cada página de un documento PDF.<jupyter_code>with open("menu.pdf", "rb") as archivo:
    pdf = pdftotext.PDF(archivo)
type(pdf)
for page in pdf:
    print(page)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11154598825831702, 'fraction_numerical': 0.0030053117137265866, 'mean_word_length': 6.165247871807711, 'pattern_counts': {'":': 0, '<': 105, '<?xml version=': 0, '>': 105, 'https://': 13, 'lorem ipsum': 0, 'www.': 5, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '26', 'dir': 'jupyter-structured-clean-dedup', 'id': '73712', 'license': 'MIT', 'n_tokens_mistral': 4941, 'n_tokens_neox': 4843, 'n_words': 1469, 'path': '09_archivos_pdf.ipynb', 'repo_name': 'PythonistaMX/py121', 'size': '14308'}