Programa en Python para descargar imágenes de una página web

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.

idw descargando imágenes

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.

idw script en python para descargar imágenes
Probando los cambios en el script.
#! /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.

7 comentarios en “Programa en Python para descargar imágenes de una página web”

  1. 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?

    Responder
    • 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 !!!

      Responder

¡Me encantaría saber que opinas!

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.