Ich muss mehrere Dateien über http in Python herunterladen.
Der naheliegendste Weg ist, urllib2 zu verwenden:
import urllib2
u = urllib2.urlopen('http://server.com/file.html')
localFile = open('file.html', 'w')
localFile.write(u.read())
localFile.close()
Aber ich muss mich mit den URLs befassen, die in irgendeiner Weise unangenehm sind, wie zum Beispiel: http://server.com/!Run.aspx/someoddtext/somemore?id=121&m=pdf
. Beim Herunterladen über den Browser hat die Datei einen vom Menschen lesbaren Namen, d. H. accounts.pdf
.
Gibt es eine Möglichkeit, damit in Python umzugehen, so dass ich die Dateinamen nicht kennen und sie nicht in mein Skript hartcodieren muss?
Skripts wie dieses herunterladen tendieren dazu, einen Header zu verschieben, der dem Benutzeragenten den Namen der Datei mitteilt:
Content-Disposition: attachment; filename="the filename.ext"
Wenn Sie sich den Header holen können, können Sie den richtigen Dateinamen erhalten.
Es gibt einen anderen Thread , der ein wenig Code für Content-Disposition
-Grabbing bietet.
remotefile = urllib2.urlopen('http://example.com/somefile.Zip')
remotefile.info()['Content-Disposition']
Basierend auf Kommentaren und der Antwort von @ Oli habe ich eine Lösung wie diese gemacht:
from os.path import basename
from urlparse import urlsplit
def url2name(url):
return basename(urlsplit(url)[2])
def download(url, localFileName = None):
localName = url2name(url)
req = urllib2.Request(url)
r = urllib2.urlopen(req)
if r.info().has_key('Content-Disposition'):
# If the response has Content-Disposition, we take file name from it
localName = r.info()['Content-Disposition'].split('filename=')[1]
if localName[0] == '"' or localName[0] == "'":
localName = localName[1:-1]
Elif r.url != url:
# if we were redirected, the real file name we take from the final URL
localName = url2name(r.url)
if localFileName:
# we can force to save the file as specified name
localName = localFileName
f = open(localName, 'wb')
f.write(r.read())
f.close()
Es verwendet den Dateinamen von Content-Disposition. Wenn es nicht vorhanden ist, wird der Dateiname von der URL verwendet.
Hier ist eine weitere Pythonic-Lösung:
import urllib2
import shutil
import urlparse
import os
def download(url, fileName=None):
def getFileName(url,openUrl):
if 'Content-Disposition' in openUrl.info():
# If the response has Content-Disposition, try to get filename from it
cd = dict(map(
lambda x: x.strip().split('=') if '=' in x else (x.strip(),''),
openUrl.info()['Content-Disposition'].split(';')))
if 'filename' in cd:
filename = cd['filename'].strip("\"'")
if filename: return filename
# if no filename was found above, parse it out of the final URL.
return os.path.basename(urlparse.urlsplit(openUrl.url)[2])
r = urllib2.urlopen(urllib2.Request(url))
try:
fileName = fileName or getFileName(url,r)
with open(fileName, 'wb') as f:
shutil.copyfileobj(r,f)
finally:
r.close()
2 Kender :
if localName[0] == '"' or localName[0] == "'":
localName = localName[1:-1]
es ist nicht sicher - Webserver kann falsch formatierten Namen als ["file.ext] oder [file.ext '] übergeben oder sogar leer sein und localName [0] führt zu einer Ausnahme sieht aus wie das:
localName = localName.replace('"', '').replace("'", "")
if localName == '':
localName = SOME_DEFAULT_FILE_NAME
wget
verwenden:
custom_file_name = "/custom/path/custom_name.ext"
wget.download(url, custom_file_name)
Verwenden von urlretrieve:
urllib.urlretrieve(url, custom_file_name)
urlretrieve erstellt auch die Verzeichnisstruktur, falls keine vorhanden ist.