Obtener el tamaño de un archivo antes de descargarlo en Python
Pregunta
Estoy descargando un directorio completo desde un servidor web.Funciona bien, pero no sé 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?
Solución
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?
Editar:Bien, descubrí 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 genera:
$ 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 abrir ambos archivos para lectura/escritura binaria.
// open for binary write
open(filename, "wb")
// open for binary read
open(filename, "rb")
Otros consejos
Usando el método de objeto-urllib-devuelto info()
, puede obtener diversa información sobre el documento recuperado.Ejemplo de cómo tomar el logotipo actual de Google:
>>> import urllib
>>> d = urllib.urlopen("http://www.google.co.uk/logos/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 dict, así que para obtener el tamaño del archivo, debes urllibobject.info()['Content-Length']
print f.info()['Content-Length']
Y para obtener el tamaño del archivo local (para comparar), puedes usar el comando os.stat():
os.stat("/the/local/file.zip").st_size
El tamaño del archivo se envía como encabezado de longitud del contenido.Aquí se explica cómo obtenerlo con urllib:
>>> site = urllib.urlopen("http://python.org")
>>> meta = site.info()
>>> print meta.getheaders("Content-Length")
['16535']
>>>
Además, si el servidor al que te estás conectando lo admite, mira Etiquetas electrónicas y el Si-modificado-desde y Si ninguno coincide encabezados.
Su uso aprovechará las reglas de almacenamiento en caché del servidor web y devolverá un 304 No modificado código de estado 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())
A peticiones-solución basada en 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