Descargar una imagen a través de urllib y python

184

Así que estoy tratando de hacer un script de Python que descargue webcomics y los coloque en una carpeta en mi escritorio. He encontrado algunos programas similares aquí que hacen algo similar, pero nada como lo que necesito. El que encontré más similar está aquí ( http://bytes.com/topic/python/answers/850927-problem-using-urllib-download-images ). Intenté usar este código:

>>> import urllib
>>> image = urllib.URLopener()
>>> image.retrieve("http://www.gunnerkrigg.com//comics/00000001.jpg","00000001.jpg")
('00000001.jpg', <httplib.HTTPMessage instance at 0x1457a80>)

Luego busqué en mi computadora un archivo "00000001.jpg", pero todo lo que encontré fue la imagen en caché. Ni siquiera estoy seguro de que guardó el archivo en mi computadora. Una vez que entiendo cómo descargar el archivo, creo que sé cómo manejar el resto. Esencialmente solo use un bucle for y divida la cadena en '00000000'. 'Jpg' e incremente el '00000000' hasta el número más grande, que de alguna manera tendría que determinar. ¿Alguna recomendación sobre la mejor manera de hacer esto o cómo descargar el archivo correctamente?

¡Gracias!

EDITAR 15/06/10

Aquí está el script completo, guarda los archivos en cualquier directorio que elija. Por alguna extraña razón, los archivos no se estaban descargando y simplemente lo hicieron. Cualquier sugerencia sobre cómo limpiarlo sería muy apreciada. Actualmente estoy trabajando en cómo descubrir que existen muchos cómics en el sitio para poder obtener solo el último, en lugar de hacer que el programa se cierre después de que se generen ciertas excepciones.

import urllib
import os

comicCounter=len(os.listdir('/file'))+1  # reads the number of files in the folder to start downloading at the next comic
errorCount=0

def download_comic(url,comicName):
    """
    download a comic in the form of

    url = http://www.example.com
    comicName = '00000000.jpg'
    """
    image=urllib.URLopener()
    image.retrieve(url,comicName)  # download comicName at URL

while comicCounter <= 1000:  # not the most elegant solution
    os.chdir('/file')  # set where files download to
        try:
        if comicCounter < 10:  # needed to break into 10^n segments because comic names are a set of zeros followed by a number
            comicNumber=str('0000000'+str(comicCounter))  # string containing the eight digit comic number
            comicName=str(comicNumber+".jpg")  # string containing the file name
            url=str("http://www.gunnerkrigg.com//comics/"+comicName)  # creates the URL for the comic
            comicCounter+=1  # increments the comic counter to go to the next comic, must be before the download in case the download raises an exception
            download_comic(url,comicName)  # uses the function defined above to download the comic
            print url
        if 10 <= comicCounter < 100:
            comicNumber=str('000000'+str(comicCounter))
            comicName=str(comicNumber+".jpg")
            url=str("http://www.gunnerkrigg.com//comics/"+comicName)
            comicCounter+=1
            download_comic(url,comicName)
            print url
        if 100 <= comicCounter < 1000:
            comicNumber=str('00000'+str(comicCounter))
            comicName=str(comicNumber+".jpg")
            url=str("http://www.gunnerkrigg.com//comics/"+comicName)
            comicCounter+=1
            download_comic(url,comicName)
            print url
        else:  # quit the program if any number outside this range shows up
            quit
    except IOError:  # urllib raises an IOError for a 404 error, when the comic doesn't exist
        errorCount+=1  # add one to the error count
        if errorCount>3:  # if more than three errors occur during downloading, quit the program
            break
        else:
            print str("comic"+ ' ' + str(comicCounter) + ' ' + "does not exist")  # otherwise say that the certain comic number doesn't exist
print "all comics are up to date"  # prints if all comics are downloaded
Miguel
fuente
Ok, ¡los tengo todos para descargar! Ahora estoy atrapado con una solución muy poco elegante para determinar cuántos cómics están en línea ... Básicamente estoy ejecutando el programa a un número que sé que supera el número de cómics y luego estoy ejecutando una excepción para que aparezca un cómic No existe, y cuando la excepción aparece más de dos veces (ya que no creo que falten más de dos cómics), se cierra el programa, pensando que no hay más para descargar. Dado que no tengo acceso al sitio web, ¿hay una mejor manera de determinar cuántos archivos hay en el sitio web? Publicaré mi código en un segundo.
Mike
creativebe.com/icombiner/merge-jpg.html Usé ese programa para fusionar todos los archivos .jpg en un PDF. ¡Funciona genial y es gratis!
Mike
77
Considere publicar su solución como respuesta y eliminarla de la pregunta. Las publicaciones de preguntas son para hacer preguntas, respondan las publicaciones para obtener respuestas :-)
BartoszKP
¿Por qué se etiqueta esto beautifulsoup? Esta publicación aparece en la lista de beautifulsouppreguntas principales
P0W
1
@ P0W He eliminado la etiqueta discutida.
kmonsoor

Respuestas:

252

Python 2

Usando urllib.urlretrieve

import urllib
urllib.urlretrieve("http://www.gunnerkrigg.com//comics/00000001.jpg", "00000001.jpg")

Python 3

Usar urllib.request.urlretrieve (parte de la interfaz heredada de Python 3, funciona exactamente igual)

import urllib.request
urllib.request.urlretrieve("http://www.gunnerkrigg.com//comics/00000001.jpg", "00000001.jpg")
Matthew Flaschen
fuente
Parece que me corta la extensión del archivo cuando se pasa como argumento (la extensión está presente en la URL original). ¿Alguna idea de por qué?
JeffThompson 01 de
1
El tuyo sí. Creo que supuse que si no se daba una extensión de archivo, se agregaría la extensión del archivo. Tenía sentido para mí en ese momento, pero creo que ahora entiendo lo que está sucediendo.
JeffThompson el
65
Nota para Python 3 que necesitarías importar [url.request] ( docs.python.org/3.0/library/… ):import urllib.request urllib.request.retrieve("http://...")
wasabigeek
1
Tenga en cuenta que la lista de documentos de Python 3 recupera () como parte de una "Interfaz heredada" y dice que puede quedar obsoleta en el futuro.
Nathan Wailes
18
Nota para Python 3 es en realidad import urllib.request urllib.request.urlretrieve("http://...jpg", "1.jpg"). Ahora es a urlretrievepartir de 3.x.
user1032613
81
import urllib
f = open('00000001.jpg','wb')
f.write(urllib.urlopen('http://www.gunnerkrigg.com//comics/00000001.jpg').read())
f.close()
DiGMi
fuente
70

Solo para el registro, utilizando la biblioteca de solicitudes.

import requests
f = open('00000001.jpg','wb')
f.write(requests.get('http://www.gunnerkrigg.com//comics/00000001.jpg').content)
f.close()

Aunque debería verificar el error de request.get ().

ellimilial
fuente
1
Incluso si esta solución no usa urllib, es posible que ya esté usando la biblioteca de solicitudes que ya está en su script de Python (ese fue mi caso mientras buscaba esto), por lo que es posible que también quiera usarla para obtener sus imágenes.
Iam Zesh
Gracias por publicar esta respuesta sobre las demás. Terminé necesitando encabezados personalizados para que mi descarga funcionara, y el puntero a la biblioteca de solicitudes acortó el proceso de hacer que todo funcione para mí considerablemente.
kuzzooroo
Ni siquiera pude hacer que urllib funcione en python3. ¡Las solicitudes no tuvieron problemas y ya está cargado! La mejor opción, creo.
user3023715
@ user3023715 en python3 necesita importar la solicitud de urllib ver aquí
Yassine Sedrani
34

Para Python 3 necesitará importar import urllib.request:

import urllib.request 

urllib.request.urlretrieve(url, filename)

para más información mira el enlace

HISI
fuente
15

Versión de Python 3 de la respuesta de @ DiGMi:

from urllib import request
f = open('00000001.jpg', 'wb')
f.write(request.urlopen("http://www.gunnerkrigg.com/comics/00000001.jpg").read())
f.close()
Dennis Golomazov
fuente
10

He encontrado esta respuesta y la edito de manera más confiable

def download_photo(self, img_url, filename):
    try:
        image_on_web = urllib.urlopen(img_url)
        if image_on_web.headers.maintype == 'image':
            buf = image_on_web.read()
            path = os.getcwd() + DOWNLOADED_IMAGE_PATH
            file_path = "%s%s" % (path, filename)
            downloaded_image = file(file_path, "wb")
            downloaded_image.write(buf)
            downloaded_image.close()
            image_on_web.close()
        else:
            return False    
    except:
        return False
    return True

De esto nunca obtienes otros recursos o excepciones durante la descarga.

Janith Chinthana
fuente
1
Deberías eliminar el 'yo'
Euphe
8

Si sabe que los archivos se encuentran en el mismo directorio dirdel sitio web sitey tienen el siguiente formato: filename_01.jpg, ..., filename_10.jpg, descárguelos todos:

import requests

for x in range(1, 10):
    str1 = 'filename_%2.2d.jpg' % (x)
    str2 = 'http://site/dir/filename_%2.2d.jpg' % (x)

    f = open(str1, 'wb')
    f.write(requests.get(str2).content)
    f.close()
Len
fuente
7

Es más fácil usarlo .read()para leer la respuesta parcial o completa, luego escribirlo en un archivo que haya abierto en una buena ubicación conocida.

Ignacio Vazquez-Abrams
fuente
5

Quizás necesites 'User-Agent':

import urllib2
opener = urllib2.build_opener()
opener.addheaders = [('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36')]
response = opener.open('http://google.com')
htmlData = response.read()
f = open('file.txt','w')
f.write(htmlData )
f.close()
Alejandro
fuente
Tal vez la página no está disponible?
Alexander
3

Todos los códigos anteriores, no permiten conservar el nombre de la imagen original, que a veces se requiere. Esto ayudará a guardar las imágenes en su unidad local, conservando el nombre de la imagen original.

    IMAGE = URL.rsplit('/',1)[1]
    urllib.urlretrieve(URL, IMAGE)

Prueba esto para más detalles.

Ojas
fuente
3

Esto funcionó para mí usando Python 3.

Obtiene una lista de URL del archivo csv y comienza a descargarlas en una carpeta. En caso de que el contenido o la imagen no exista, toma esa excepción y continúa haciendo su magia.

import urllib.request
import csv
import os

errorCount=0

file_list = "/Users/$USER/Desktop/YOUR-FILE-TO-DOWNLOAD-IMAGES/image_{0}.jpg"

# CSV file must separate by commas
# urls.csv is set to your current working directory make sure your cd into or add the corresponding path
with open ('urls.csv') as images:
    images = csv.reader(images)
    img_count = 1
    print("Please Wait.. it will take some time")
    for image in images:
        try:
            urllib.request.urlretrieve(image[0],
            file_list.format(img_count))
            img_count += 1
        except IOError:
            errorCount+=1
            # Stop in case you reach 100 errors downloading images
            if errorCount>100:
                break
            else:
                print ("File does not exist")

print ("Done!")
Víctor
fuente
2

Una solución más simple puede ser (python 3):

import urllib.request
import os
os.chdir("D:\\comic") #your path
i=1;
s="00000000"
while i<1000:
    try:
        urllib.request.urlretrieve("http://www.gunnerkrigg.com//comics/"+ s[:8-len(str(i))]+ str(i)+".jpg",str(i)+".jpg")
    except:
        print("not possible" + str(i))
    i+=1;
Ayush
fuente
Tenga cuidado al usar un simple, excepto así, consulte stackoverflow.com/questions/54948548/… .
AMC
1

¿Qué hay de esto?

import urllib, os

def from_url( url, filename = None ):
    '''Store the url content to filename'''
    if not filename:
        filename = os.path.basename( os.path.realpath(url) )

    req = urllib.request.Request( url )
    try:
        response = urllib.request.urlopen( req )
    except urllib.error.URLError as e:
        if hasattr( e, 'reason' ):
            print( 'Fail in reaching the server -> ', e.reason )
            return False
        elif hasattr( e, 'code' ):
            print( 'The server couldn\'t fulfill the request -> ', e.code )
            return False
    else:
        with open( filename, 'wb' ) as fo:
            fo.write( response.read() )
            print( 'Url saved as %s' % filename )
        return True

##

def main():
    test_url = 'http://cdn.sstatic.net/stackoverflow/img/favicon.ico'

    from_url( test_url )

if __name__ == '__main__':
    main()
gmas80
fuente
0

Si necesita soporte de proxy, puede hacer esto:

  if needProxy == False:
    returnCode, urlReturnResponse = urllib.urlretrieve( myUrl, fullJpegPathAndName )
  else:
    proxy_support = urllib2.ProxyHandler({"https":myHttpProxyAddress})
    opener = urllib2.build_opener(proxy_support)
    urllib2.install_opener(opener)
    urlReader = urllib2.urlopen( myUrl ).read() 
    with open( fullJpegPathAndName, "w" ) as f:
      f.write( urlReader )
Eamonn Kenny
fuente
0

Otra forma de hacerlo es a través de la biblioteca fastai. Esto funcionó como un encanto para mí. Estaba enfrentando un SSL: CERTIFICATE_VERIFY_FAILED Erroruso, urlretrieveasí que lo intenté.

url = 'https://www.linkdoesntexist.com/lennon.jpg'
fastai.core.download_url(url,'image1.jpg', show_progress=False)
Sid
fuente
Me enfrentaba a un SSL: CERTIFICATE_VERIFY_FAILED Error stackoverflow.com/questions/27835619/…
AMC
0

Usar solicitudes

import requests
import shutil,os

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
}
currentDir = os.getcwd()
path = os.path.join(currentDir,'Images')#saving images to Images folder

def ImageDl(url):
    attempts = 0
    while attempts < 5:#retry 5 times
        try:
            filename = url.split('/')[-1]
            r = requests.get(url,headers=headers,stream=True,timeout=5)
            if r.status_code == 200:
                with open(os.path.join(path,filename),'wb') as f:
                    r.raw.decode_content = True
                    shutil.copyfileobj(r.raw,f)
            print(filename)
            break
        except Exception as e:
            attempts+=1
            print(e)

if __name__ == '__main__':
    ImageDl(url)
Sohan Das
fuente
0

Usando urllib, puede hacer esto al instante.

import urllib.request

opener=urllib.request.build_opener()
opener.addheaders=[('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1941.0 Safari/537.36')]
urllib.request.install_opener(opener)

urllib.request.urlretrieve(URL, "images/0.jpg")
Sreekant Shenoy
fuente