it-swarm.com.de

Wie kann ich eine Datei mit Python "intelligenter" herunterladen?

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?

67
kender

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']
41
Oli

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. 

35
kender

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()
23
lostlogic

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
1
Denis Barmenkov

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. 

0
Jaydev