Comment télécharger un fichier en utilisant python d'une manière "intelligente"?

j'ai besoin de télécharger plusieurs fichiers via http en Python.

la façon la plus évidente de le faire est simplement en utilisant urllib2:

import urllib2
u = urllib2.urlopen('http://server.com/file.html')
localFile = open('file.html', 'w')
localFile.write(u.read())
localFile.close()

mais je vais devoir traiter avec les URL qui sont désagréables d'une certaine façon, dire comme ceci: http://server.com/!Run.aspx/someoddtext/somemore?id=121&m=pdf . Une fois téléchargé par l'intermédiaire du navigateur, le fichier a un nom lisible par l'humain, c.-à-d. accounts.pdf .

est - il possible de gérer cela en python, donc je n'ai pas besoin de connaître les noms de fichiers et le code dur dans mon script?

66
demandé sur kender 2009-05-14 12:21:42

5 réponses

les scripts de téléchargement de ce genre tendent à pousser un en-tête disant à l'utilisateur-agent ce qu'il faut appeler le fichier:

Content-Disposition: attachment; filename="the filename.ext"

si vous pouvez saisir cet en-tête, vous pouvez obtenir le bon nom de fichier.

il y a un autre thread qui a un peu de code à offrir pour Content-Disposition - agripping.

remotefile = urllib2.urlopen('http://example.com/somefile.zip')
remotefile.info()['Content-Disposition']
40
répondu Oli 2017-05-23 11:46:50

basé sur les commentaires et anwser de @Oli, j'ai fait une solution comme ceci:

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

il prend le nom de fichier du contenu-Disposition; s'il n'est pas présent, utilise le nom de fichier de l'URL (si redirection se produit, L'URL finale est prise en compte).

35
répondu kender 2013-03-28 07:59:14

en combinant une grande partie de ce qui précède, voici une solution plus pythonique:

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
répondu lostlogic 2012-04-23 14:48:00

2 Kender :

if localName[0] == '"' or localName[0] == "'":
    localName = localName[1:-1]

ce n'est pas sûr -- le serveur web peut passer le nom mal formaté en tant que Fichier [".ext] ou [fichier.ext'] ou même être vide et localName[0] soulèvera exception. Le code Correct peut ressembler à ceci:

localName = localName.replace('"', '').replace("'", "")
if localName == '':
    localName = SOME_DEFAULT_FILE_NAME
1
répondu Denis Barmenkov 2010-03-23 21:12:58

par wget :

custom_file_name = "/custom/path/custom_name.ext"
wget.download(url, custom_file_name)

utilisant urlretrieve:

urllib.urlretrieve(url, custom_file_name)

urlretrieve crée aussi la structure du répertoire si elle n'existe pas.

0
répondu Jaydev 2016-09-19 12:37:58