DEV Community

Maximiliano Burgos
Maximiliano Burgos

Posted on

Diario de Python | #8. Issuu PDF Downloader

Estaba buscando ideas para seguir mejorando Color Choice, hasta que me enteré que la Replay seguía viva. Para los que no la conozcan, se trata de una revista de videojuegos retro con un contenido de calidad muy interesante, la cual está disponible en una plataforma de lectura llamada Issuu.

¡Las quiero todas!

Al día de la publicación de este artículo, tienen unos 35 o 40 números publicados. Decidí que quería bajarlas a mi Ipad, pero digamos que (salvo que el mismo publisher lo permita) no se pueden descargar desde Issuu.

Por lo cual, busqué algo como "Issuu PDF Downloader Online" y encontré este sitio para bajarlas, que trae todas las imágenes y las convierte a PDF.

El problema

Simplemente tenía que copiar cada URL de cada revista, lo cual era un proceso repetitivo que constaba de 40 iteraciones. Todo esto, para las revistas de Replay.

Imaginen si buscaba descargarme 100 números de algún otro publisher.

Luego recordé que soy desarrollador, y mi obligación moral consiste en automatizar cosas.

Hora de copiarse de la gente honesta

No quería trabajar a sudor y lágrima en una solución desarrollada de cero, así que decidí copiarme de la gente.

Quería hacerlo en Python para seguir fortaleciendo mis skills, así que busqué un repositorio que cumpliera mis expectativas. Encontré esto:

GitHub logo jpyamamoto / Issuu-PDF-Downloader

Program on python which downloads Issuu files as PDF

Issuu-PDF-Downloader

IMPORTANT: dependency package pyfpdf has obsolete version from pip or conda. Please install from its project GitHub page.

Program on python which downloads Issuu files as PDF

Issuu is a platform which allows users to upload PDF's and protect them from downloading (they didn't count with me)

However, while doing research on the source code, I was able to find its weakness. It stores each page of the PDF as a .jpg in a certain location, and labels it as page_1 <-- number of the page.

So, with this little code in python you're able to take advantage of this weakness and download any file you wish.

You have to run the file framework.py and paste the url of the file you want to download, that's it.

It will give you the images as well as a PDF.

You can change the image size in the resize.py file.

Pero como todo problema de desarrollo, nunca se encuentra una solución mágica. A veces parece que alguien ya pensó en tus inconvenientes, pero quizá estés en un terreno más personalizado (y ambicioso) del que pensabas.

Hora de contribuir a la sociedad

En primer lugar, hice un fork del repo, porque sabía que podía mejorar muchas cosas:

GitHub logo maxwellnewage / Issuu-PDF-Downloader

Program on python which downloads Issuu files as PDF

Issuu-PDF-Downloader

Este fork arregla los problemas de dependencias y la generación de PDFs.

También se reemplaza el input() por una lista de links de Issuu para automatizar el proceso.

Cómo funciona

El script dict_to_json_replay.py genera el archivo issuu_urls.json en la carpeta json con el siguiente esquema:

[
    {
        "name": "name of the pdf"
        "url": "issuu url"
    }
]
Enter fullscreen mode Exit fullscreen mode

Puedes utilizarlo para bajar las revistas de Replay, o reescribir tu propio json que contenga los links de las revistas que quieras convertir.

Para correrlo, debes ejecutar el script main.py. El proceso es el siguiente:

  • Carga y convierte el archivo json issuu_urls.json a un diccionario de Python.
  • Por cada url, descarga todas las páginas como imágenes. Guarda cada imagen en images.
  • Une todas las imágenes en un PDF con la librería FPDF, y luego genera un archivo en la carpeta pdfs.
  • Una…

Luego evalué que me ofrecía el mismo:

  • Se pueden descargar revistas, pero la librería está rota.
  • Tampoco tenía un requirements.txt, así que no podías importar automáticamente todas las dependencias necesarias.
  • Pedía una URL por consola, lo mismo que en la web, pero esta vez tenía que ejecutar el programa por cada enlace, un desastre.
  • La nomenclatura no era muy standard, y había muchas variables con nombres raros.

La verdad lo tenía difícil: el programa no compilaba por dependencias. Hice un par de búsquedas, las reparé, pero luego las librerías tenían métodos distintos o con parámetros nuevos. Se me estaba rompiendo por todos lados. Estuve varios días dándole vueltas, pero logré hacerlo andar.

He domado a la bestia

En primer lugar, yo quería algo automatizado, así que armé una lista de URLs, en vez de una sola por un input de consola. Pero, para hacerlo más dinámico, decidí armar un json que se pueda llenar de esos enlaces y luego se convierta en una lista de diccionarios en Python:

def get_issuu_json_as_dict():
    issuu_url_json = os.path.join('./json/', 'issuu_urls.json')
    issuu_url_file = open(issuu_url_json, "r").read()
    return json.loads(issuu_url_file)
Enter fullscreen mode Exit fullscreen mode

Entonces, la persona que quisiera utilizar mi aplicación, simplemente podría crear issuu_urls.json en la carpeta json y poner su lista de revistas en este formato:

[
    {
        "name": "name of the pdf",
        "url": "issuu url"
    }
]
Enter fullscreen mode Exit fullscreen mode

Por otro lado, lo primero que hacía el algoritmo viejo era bajar todas las imágenes y luego convertirlas en PDF (como el sitio que encontré más arriba). El problema era que las imágenes se almacenaban en la raíz del proyecto, y no se eliminaban nunca.

Lo solucioné en downloader.py:

def downloader(url):
    print('Started download process...')
    # List to create the PDF
    files = []
    formatter = url.replace('page_1.jpg', '')
    page_counter = 1
    while True:
        url_page = formatter + 'page_' + str(page_counter) + '.jpg'
        filename = str(page_counter) + '.jpg'
        if exists(url_page):
            # Save image directory
            filename_with_folder = os.path.join(IMAGE_DIR, filename)
            # Download images
            opener = open(filename_with_folder, 'wb')
            opener.write(urllib.request.urlopen(url_page).read())
            # Save images
            opener.close()
            print(f'Correctly saved file {filename} From URI: {url_page}')
            # Add filename to list, so we make the pdf later
            files.append(filename_with_folder)
            # Go for the next one
            page_counter += 1
        else:
            # No more images
            break

    print('Completed download process...')
    # Time to create the pdf
    return files
Enter fullscreen mode Exit fullscreen mode

la constante IMAGE_DIR contiene el valor "./images/", osea una carpeta de imágenes. Luego de que cada imagen se guarde ahí y se convierta en pdf, se corre un método llamado delete_old_images(), el cual limpia todos los archivos al final de la ejecución.

def delete_old_images():
    for image in os.listdir(IMAGE_DIR):
        if image.endswith(".jpg"):
            os.remove(os.path.join(IMAGE_DIR, image))
Enter fullscreen mode Exit fullscreen mode

Tuve que hacerlo de esa manera porque si intentaba limpiar por cada PDF creado, me arrojaba una excepción que indicaba que el archivo que quería eliminar estaba siendo utilizado. Muy raro.

Por cierto, para crear los PDFs utilicé una librería llamada PyFPDF, la cual permite crearlos de cero; incluso leer un documento y extraer información del mismo.

Detalles, de los que no te gustan

Mi fork es plenamente funcional. Le di mucho amor, e incluso dejé una documentación para que puedas clonarlo y probarlo sin dramas en tu hermoso IDE PyCharm.

Sin embargo, me encontré con unos detalles que pueden hacer fallar su ejecución: en primer lugar, si intentas bajar los 40 PDFs (podés generar mi json corriendo el script dict_to_json_replay.py), a mediados de la iteración número 15 o 20, te va a dar un error estilo Bad Request. Esto es porque a Issuu no le agrada que estés bajando tantas imágenes de su servidor y piensa que estás intentando hacer un ataque DDoS. Para evitar esto, te recomiendo partir tu json en 10 enlaces por cada ejecución.

Por otro lado, esto no resuelve el bloqueo de las revistas premium: si el publisher decidió que la mitad de las páginas no estén disponibles, vas a descargar imágenes muy desenfocadas en esa parte de tu documento. Pensá que esto no es un hack, sino más bien un web crawler que busca cada página y la recompone en un PDF.

Conclusiones

Me siento satisfecho con los resultados. Logré mi objetivo de automatizar la descarga masiva de revistas en Issuu de manera completamente legal. Los animo, simples mortales, a hacerle un fork a mi repositorio e intentar mejorar este proyecto. Estoy seguro de que pueden convertirlo en mucho más.

En las próximas entregas volveré sobre Color Choice, ese experimento social que me gustaría combinar con probabilidad y estadística.

Top comments (0)