Obtener el tamaño de un archivo antes de descargarlo en Python

Estoy descargando un directorio completo desde un servidor web. Funciona bien, pero no puedo entender cómo obtener el tamaño del archivo antes de descargarlo para comparar si se actualizó en el servidor o no. ¿Se puede hacer esto como si estuviera descargando el archivo desde un servidor FTP?

import urllib import re url = "http://www.someurl.com" # Download the page locally f = urllib.urlopen(url) html = f.read() f.close() f = open ("temp.htm", "w") f.write (html) f.close() # List only the .TXT / .ZIP files fnames = re.findall('^.*<a href="(\w+(?:\.txt|.zip)?)".*$', html, re.MULTILINE) for fname in fnames: print fname, "..." f = urllib.urlopen(url + "/" + fname) #### Here I want to check the filesize to download or not #### file = f.read() f.close() f = open (fname, "w") f.write (file) f.close() 

@Jon: gracias por tu rápida respuesta. Funciona, pero el tamaño del archivo en el servidor web es ligeramente menor que el tamaño del archivo descargado.

Ejemplos:

 Local Size Server Size 2.223.533 2.115.516 664.603 662.121 

¿Tiene algo que ver con la conversión CR / LF?

He reproducido lo que estás viendo:

 import urllib, os link = "http://python.org" print "opening url:", link site = urllib.urlopen(link) meta = site.info() print "Content-Length:", meta.getheaders("Content-Length")[0] f = open("out.txt", "r") print "File on disk:",len(f.read()) f.close() f = open("out.txt", "w") f.write(site.read()) site.close() f.close() f = open("out.txt", "r") print "File on disk after download:",len(f.read()) f.close() print "os.stat().st_size returns:", os.stat("out.txt").st_size 

Produce esto:

 opening url: http://python.org Content-Length: 16535 File on disk: 16535 File on disk after download: 16535 os.stat().st_size returns: 16861 

¿Qué estoy haciendo mal aquí? ¿Os.stat (). St_size no devuelve el tamaño correcto?


Edit: OK, me di cuenta de cuál era el problema:

 import urllib, os link = "http://python.org" print "opening url:", link site = urllib.urlopen(link) meta = site.info() print "Content-Length:", meta.getheaders("Content-Length")[0] f = open("out.txt", "rb") print "File on disk:",len(f.read()) f.close() f = open("out.txt", "wb") f.write(site.read()) site.close() f.close() f = open("out.txt", "rb") print "File on disk after download:",len(f.read()) f.close() print "os.stat().st_size returns:", os.stat("out.txt").st_size 

esto produce:

 $ python test.py opening url: http://python.org Content-Length: 16535 File on disk: 16535 File on disk after download: 16535 os.stat().st_size returns: 16535 

Asegúrese de que está abriendo ambos archivos para lectura / escritura binaria.

 // open for binary write open(filename, "wb") // open for binary read open(filename, "rb") 

Usando la info() método devuelto-urllib-object info() , puede obtener información diversa sobre el documento recuperado. Ejemplo de agarrar el logo actual de Google:

 >>> import urllib >>> d = urllib.urlopen("http://sofes.miximages.com/python/olympics08_opening.gif") >>> print d.info() Content-Type: image/gif Last-Modified: Thu, 07 Aug 2008 16:20:19 GMT Expires: Sun, 17 Jan 2038 19:14:07 GMT Cache-Control: public Date: Fri, 08 Aug 2008 13:40:41 GMT Server: gws Content-Length: 20172 Connection: Close 

Es un dictado, así que para obtener el tamaño del archivo, debes hacer urllibobject.info()['Content-Length']

 print f.info()['Content-Length'] 

Y para obtener el tamaño del archivo local (para comparación), puede usar el comando os.stat ():

 os.stat("/the/local/file.zip").st_size 

El tamaño del archivo se envía como el encabezado Content-Length. Aquí es cómo conseguirlo con urllib:

 >>> site = urllib.urlopen("http://python.org") >>> meta = site.info() >>> print meta.getheaders("Content-Length") ['16535'] >>> 

Además, si el servidor al que se está conectando lo admite, consulte Etags y los encabezados If-Modified-Since y If-None-Match .

El uso de estos aprovechará las reglas de almacenamiento en caché del servidor web y devolverá un código de estado 304 No modificado si el contenido no ha cambiado.

En Python3:

 >>> import urllib.request >>> site = urllib.request.urlopen("http://python.org") >>> print("FileSize: ", site.length) 

Para un enfoque de python3 (probado en 3.5) recomendaría:

 with urlopen(file_url) as in_file, open(local_file_address, 'wb') as out_file: print(in_file.getheader('Content-Length')) out_file.write(response.read()) 

Una solución basada en solicitudes que utiliza HEAD en lugar de GET (también imprime encabezados HTTP):

 #!/usr/bin/python # display size of a remote file without downloading from __future__ import print_function import sys import requests # number of bytes in a megabyte MBFACTOR = float(1 << 20) response = requests.head(sys.argv[1], allow_redirects=True) print("\n".join([('{:<40}: {}'.format(k, v)) for k, v in response.headers.items()])) size = response.headers.get('content-length', 0) print('{:<40}: {:.2f} MB'.format('FILE SIZE', int(size) / MBFACTOR)) 

Uso

 $ python filesize-remote-url.py https://httpbin.org/image/jpeg ... Content-Length : 35588 FILE SIZE (MB) : 0.03 MB