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:
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:
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:
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"}]
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:
defdownloader(url):print('Started download process...')# List to create the PDF
files=[]formatter=url.replace('page_1.jpg','')page_counter=1whileTrue:url_page=formatter+'page_'+str(page_counter)+'.jpg'filename=str(page_counter)+'.jpg'ifexists(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+=1else:# No more images
breakprint('Completed download process...')# Time to create the pdf
returnfiles
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.
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.