Obtenez la taille d'un fichier avant de le télécharger en Python
Question
Je télécharge un répertoire entier à partir d'un serveur Web.Cela fonctionne bien, mais je n'arrive pas à comprendre comment obtenir la taille du fichier avant le téléchargement pour comparer s'il a été mis à jour sur le serveur ou non.Cela peut-il être fait comme si je téléchargeais le fichier depuis un serveur 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 :merci pour votre réponse rapide.Cela fonctionne, mais la taille du fichier sur le serveur Web est légèrement inférieure à la taille du fichier téléchargé.
Exemples:
Local Size Server Size
2.223.533 2.115.516
664.603 662.121
Cela a quelque chose à voir avec la conversion CR/LF ?
La solution
J'ai reproduit ce que vous voyez :
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
Produit ceci :
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'est-ce que je fais de mal ici ?Est-ce que os.stat().st_size ne renvoie pas la bonne taille ?
Modifier:OK, j'ai compris quel était le problème :
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
cela donne :
$ 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
Assurez-vous que vous ouvrez les deux fichiers pour la lecture/écriture binaire.
// open for binary write
open(filename, "wb")
// open for binary read
open(filename, "rb")
Autres conseils
Utilisation de la méthode return-urllib-object info()
, vous pouvez obtenir diverses informations sur le document récupéré.Exemple de récupération du logo Google actuel :
>>> 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
C'est un dicté, donc pour obtenir la taille du fichier, vous le faites urllibobject.info()['Content-Length']
print f.info()['Content-Length']
Et pour obtenir la taille du fichier local (à titre de comparaison), vous pouvez utiliser la commande os.stat() :
os.stat("/the/local/file.zip").st_size
La taille du fichier est envoyée comme en-tête Content-Length.Voici comment l'obtenir avec urllib :
>>> site = urllib.urlopen("http://python.org")
>>> meta = site.info()
>>> print meta.getheaders("Content-Length")
['16535']
>>>
De plus, si le serveur auquel vous vous connectez le prend en charge, regardez Étiquettes et le Si-Modifié-Depuis et Si aucune correspondance en-têtes.
Leur utilisation tirera parti des règles de mise en cache du serveur Web et renverra un 304 Non modifié code d'état si le contenu n'a pas changé.
En Python3 :
>>> import urllib.request
>>> site = urllib.request.urlopen("http://python.org")
>>> print("FileSize: ", site.length)
Pour une approche python3 (testée sur 3.5), je recommanderais :
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())
UN demandes-solution basée sur HEAD au lieu de GET (imprime également les en-têtes 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))
Usage
$ python filesize-remote-url.py https://httpbin.org/image/jpeg ... Content-Length : 35588 FILE SIZE (MB) : 0.03 MB