El problema.
Necesitaba descargar las imágenes de un sitio. Intenté de varias formas con resultados mixtos. Al principio usé wget, pero por más que le moví a los parámetros del comando descargaba de todo menos las imágenes. Sospecho que el problema fue que los archivos que quería descargar estaban en otros sitios conocidos por hospedar imágenes como Flickr o ImageShack. Era tiempo de ver otras opciones.
Posibles soluciones.
Primero intenté con DownThemAll un archifamoso complemento para firefox que permite descargar archivos de una página. Con la opción del filtro permite especificar únicamente las imágenes. Hace el trabajo, pero con demasiados clics de ratón. Lo dejé como plan B.
Image Harvester parecía ser justo lo que necesitaba. Lamentablemente resulto demasiado lento y de resultados dudosos. Después de 10 minutos jamás vi una imagen JPG en la enormidad de directorios que hizo el script. Afortunadamente inspeccionando su código surgío una idea.
ImageDownloader un script desarrollado por Lorenzo Carbonell. La idea era buena, buscar en una página todas las etiquetas img para luego descargarlas, simple y elegante. Sin embargo este script adolece de un gran problema, al encontrar la primera imagen con una referencia relativa ¡El programa truena! así que tampoco fue una solución.
ImageDownloader + wget
Primero quiero aclarar que mis habilidades con python son muy básicas, así que cualquier sugerencia será bienvenida. Modificando un poco el script de Image Downloader y encargandole la tarea de descargar los archivos a wget logré mi objetivo.
Todavía tiene problemas con rutas de imágenes relativas pero ya no truena y simplemente continua con la siguiente imagen. Todos los archivos los descarga en el directorio que se esta ejecutando.
Si lo necesitan o lo quieren modificar pueden descargar idw.
#! /usr/bin/python # -*- coding: iso-8859-1 -*- # __author__='Lorenzo Carbonell' __date__ ='$10/06/2011' # # # Copyright (C) 2011 Lorenzo Carbonell # lorenzo.carbonell.cerezo@gmail.com # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # Modificaciones para usarlo con wget: Linuxman http://linuxman.blogsome.com # import urllib2 import re import sys import os from os.path import basename from urlparse import urlsplit EXTENSIONS = ['.jpg','.png','.gif','.jpeg'] def download_images_from_url(url): if not url.lower().startswith('http://') and not url.lower().startswith('https://'): url = 'http://%s'%url print 'Downloading from %s...'%url urlContent = urllib2.urlopen(url).read() # Búsqueda del tag img en la página web. # HTML image tag: <img src="url" alt="some_text"/> imgUrls = re.findall('img .*?src="(.*?)"', urlContent) # download all images for imgUrl in imgUrls: # El print me sirvio para identificar los url relativos, # a continuación intenta descargar el archivo con wget. print imgUrl os.system('wget -q -nc ' + imgUrl) return 0 if __name__ == '__main__': args = sys.argv if len(args) < 2: print 'I need an url to download images' exit(-1) print args[1] download_images_from_url(args[1]) exit(0)
El siguiente paso será resolver las rutas relativas, o probablemente usar axel en lugar de wget para acelerar las descargas.
Actualización agosto 2015
Nuevamente necesité de usar este script y tuve que hacerle unas pequeñas mejoras. El mayor cambio fue el ejecutable de Python, ya que este script esta codificado en Python2 y si no le especifico otra cosa Manjaro manda llamar a Python3 provocando errores en la ejecución del programa.
Esta es la versión corregida y ligeramente modificada.
#! /usr/bin/python2 # -*- coding: iso-8859-1 -*- # __author__='Lorenzo Carbonell' __date__ ='$10/06/2011' # # IDW descarga todas las imágenes disponibles en un URL. # # Copyright (C) 2011 Lorenzo Carbonell # lorenzo.carbonell.cerezo@gmail.com # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # # Modificaciones para usarlo con wget: Linuxman https://linuxmanr4.com # import urllib2 import re import sys import os from os.path import basename from urlparse import urlsplit EXTENSIONS = ['.jpg','.png','.gif','.jpeg'] def download_images_from_url(url): if not url.lower().startswith('http://') and not url.lower().startswith('https://'): url = 'http://%s'%url print 'Descargando de %s...'%url urlContent = urllib2.urlopen(url).read() # Búsqueda del tag img en la página web. # HTML image tag: <img src="url" alt="some_text"/> imgUrls = re.findall('img .*?src="(.*?)"', urlContent) # Descargar todas las imágenes for imgUrl in imgUrls: # El print me sirvio para identificar los url relativos, # a continuación intenta descargar el archivo con wget. print imgUrl os.system('wget -q -nc ' + imgUrl) return 0 if __name__ == '__main__': args = sys.argv if len(args) < 2: print 'Necesito una dirección URL para descargar imágenes' exit(-1) print args[1] download_images_from_url(args[1]) exit(0)
Mi versión (septiembre 2022)
Han pasado algunos años desde que escribí este artículo y ahora que se un poco más sobre Pyhton decidí hacer mi propia versión de este programa.
El resultado es un código mucho más simple. Solamente utilizo dos módulos: requests para las descargas y re para manejar las expresiones regulares.
También uso otra expresión regular (que no es perfecta) pero que involucra diferentes tipos de conexión como http y https. También incluye ahora un formato que en aquellos días no era muy popular Webp.
# -*- coding: utf_8 -*- # Descargar Imágenes de una página web ... diw.py # ------------------------------------------------ """ Este programa encuentra todas los enlaces a imágenes en una página web y las descarga. """ import requests import re URL = "https://centaurodelnorte.com/ex-hacienda-la-loma-cuna-de-la-division-del-norte/" archivo = "descarga.html" # Guardamos el archivo para consulta y referencia. # pero es opcional respuesta = requests.get(URL) open(archivo, "wb").write(respuesta.content) # Obtener las direcciones de las imágenes usando expresiones regulares. html = respuesta.content.decode('utf-8') regex = r"(?:(?:https?)+\:\/\/+[a-zA-Z0-9_ÑñÁáÉéÍíÓóÚú\/\._-]{1,})+(?:(?:jpe?g|png|gif|webp))" matches = re.findall(regex, html) # Descargamos las imágenes encontradas. for x in matches: nombre_archivo = x[x.rfind("/") + 1:] respuesta = requests.get(x) open(nombre_archivo, "wb").write(respuesta.content) print(x)
Una novedad para mi fue el uso de la función rfind para separar el nombre del archivo del url de la imagen. Me pareció una solución muy elegante al problema.
De último minuto hice una corrección en la expresión regular para que también incluyera vocales acentuadas y la letra ñ como elementos del enlace. Son poco frecuentes, pero me di cuenta haciendo algunas pruebas que si puede pasar.
Agregando opciones
Para hacer la ejecución del código más flexible decidí incluir el manejo de opciones. Por el momento la única opción es el URL de la página que se quiere analizar para descargar las imágenes.
Usando el módulo Argparse es muy sencillo. El código quedó más o menos así.
#!/usr/bin/env python3 # -*- coding: utf_8 -*- # Descargar Imágenes de una página web ... diw.py # ------------------------------------------------ """ Este programa encuentra todas los enlaces a imágenes en una página web y las descarga. """ import argparse import requests import re # Empezamos con un parámetro que es la url que quiero analizar parser = argparse.ArgumentParser( description='Descarga las imágenes de una página web.') parser.add_argument('-u', '--url', help='URL de la página.', type=str, required=True) args = parser.parse_args() URL = args.url archivo = "descarga.html" # Guardamos el archivo para consulta y referencia. # pero es opcional respuesta = requests.get(URL) open(archivo, "wb").write(respuesta.content) # Obtener las direcciones de las imágenes usando expresiones regulares. html = respuesta.content.decode('utf-8') regex = r"(?:(?:https?)+\:\/\/+[a-zA-Z0-9_ÑñÁáÉéÍíÓóÚú\/\._-]{1,})+(?:(?:jpe?g|png|gif|webp))" matches = re.findall(regex, html) # Descargamos las imágenes encontradas. for x in matches: nombre_archivo = x[x.rfind("/") + 1:] respuesta = requests.get(x) open(nombre_archivo, "wb").write(respuesta.content) print(x)
Pues eso es todo, happy coding y hasta la próxima.
Gracias, me ayudo bastante para entender la libreria urllib2. 😀
Me interesaría rescatar algunas imagenes de alguna página, el caso es que hay que probar con todos los caracteres y numeros a una »dirección base» ejemplo:
http//pagina.com/XXXXX_usuario.png
Me gustaría saber si este script va probando los caracteres uno a uno y cada vez que no dé error me descarga la imagen o no ¿es eso lo que hace?
Supongo que se puede arreglar para que haga lo que quieres, pero en lugar de probar combinaciones me suena que sería mejor un enfoque de expresiones regulares. Dale una checadita a ver que obtienes.
Saludos !!!
Mejore el programa y lo publique en mi web.
Creo que asi esta mejor, se resuelven algunos problemas como:
las rutas relativas
2, ya no se cuelga si no puede descargar una imagen
3, Funciona en windows, Linux y Mac (usa urllib en vez de Wget)
y le hice unas mejoras mas 😀
Le di un vistazo rápido y me marca un error en la línea 46, probablemente sea un problema por copiar y pegar el código.. ¿Tienes un archivo para descargar?
Funciona para Archivos PDF? y htaccess
Supongo que sí, solo tendrías que agregar la búsqueda de este tipo de archivos al programa y wget se encarga de descargarlos.