web-dev-qa-db-fra.com

Python-FTP télécharge tous les fichiers du répertoire

Python newb ici, alors s'il te plaît, supporte-moi. Je m’assemble un script pour télécharger tous les fichiers d’un répertoire via FTP. Jusqu'à présent, j'ai réussi à me connecter et à récupérer un fichier, mais je n'arrive pas à le faire fonctionner par lots (obtenir tous les fichiers du répertoire). Voici ce que j'ai jusqu'à présent:

from ftplib import FTP
import os, sys, os.path

def handleDownload(block):
    file.write(block)
    print ".",

ddir='C:\\Data\\test\\'
os.chdir(ddir)
ftp = FTP('test1/server/')

print 'Logging in.'
ftp.login('user1\\anon', 'pswrd20')
directory = '\\data\\test\\'

print 'Changing to ' + directory
ftp.cwd(directory)
ftp.retrlines('LIST')

print 'Accessing files'

for subdir, dirs, files in os.walk(directory):
    for file in files: 
        full_fname = os.path.join(root, fname);  
        print 'Opening local file ' 
        ftp.retrbinary('RETR C:\\Data\\test\\' + fname,
                       handleDownload,
                       open(full_fname, 'wb'));
        print 'Closing file ' + filename
        file.close();
ftp.close()

Je parie que vous pouvez dire que cela ne fait pas grand chose quand je le lance. Toute suggestion d’amélioration serait donc grandement appréciée.

PS Ce n'est pas un devoir: DD

Merci!!

26
Sosti

J'ai réussi à résoudre ce problème, alors publions maintenant le code pertinent pour les futurs visiteurs:

filenames = ftp.nlst() # get filenames within the directory
print filenames

for filename in filenames:
    local_filename = os.path.join('C:\\test\\', filename)
    file = open(local_filename, 'wb')
    ftp.retrbinary('RETR '+ filename, file.write)

    file.close()

ftp.quit() # This is the “polite” way to close a connection

Cela a fonctionné pour moi sur Python 2.5, Windows XP.

62
Sosti

Si vous souhaitez simplement résoudre ce problème, je suggérerais la commande wget:

cd c:\destination
wget --mirror --continue --no-Host-directories --user=username --password=s3cr3t ftp://hostname/source/path/

L'option --continue peut être très dangereuse si les fichiers change sur le serveur. Si les fichiers ne sont que jamais ajoutés _, alors c'est très convivial.

Cependant, s’il s’agit d’un exercice d’apprentissage pour vous et que vous souhaitez faire fonctionner votre programme, je pense que vous devriez commencer par regarder cette ligne:

for subdir, dirs, files in os.walk(directory):

directory a été le répertoire source distant dans la plupart des programmes, mais la fonction os.walk() ne peut pas parcourir un répertoire distant. Vous devez parcourir vous-même les fichiers renvoyés, à l'aide d'un rappel fourni à la fonction retrlines .

Examinez les options MLSD ou NLST au lieu de LIST, elles seront probablement plus faciles à analyser. (Notez que FTP ne spécifie pas réellement à quoi doit ressembler les listes; il a toujours été conçu pour être piloté par un humain situé sur une console ou par un nom de fichier spécifique transféré. Ainsi, les programmes qui agissent intelligemment avec les listes FTP telles que les présentent à l'utilisateur dans une interface graphique doit probablement contenir d’énormes piles de code de cas particulier, pour des serveurs impairs ou obscurs, et ils font probablement tous quelque chose de stupide face à des noms de fichiers malveillants.)

Pouvez-vous utiliser sftp à la place? sftpest spécifie comment les listes de fichiers sont censées être analysées, ne transmet pas le nom d'utilisateur/mot de passe en clair, et n'a pas la gêne géante des connexions passives vs actives - il utilise simplement la connexion unique, ce qui signifie qu’elle fonctionne sur plus de pare-feu que FTP.

Edit: vous devez passer un objet 'appelable' à la fonction retrlines. Un objet appelable est soit une instance d'une classe qui a défini une méthode __call__, soit une fonction. Bien que la fonction puisse être plus facile à décrire, une instance de classe peut être plus utile. (Vous pouvez utiliser l'instance pour collecter les noms de fichiers, mais la fonction doit écrire dans une variable globale. Bad.)

Voici l'un des objets appelables les plus simples:

>>> class c:
...  def __call__(self, *args):
...   print(args)
...
>>> f = c()
>>> f('hello')
('hello',)
>>> f('hello', 'world')
('hello', 'world')

Cela crée une nouvelle classe, c, qui définit une méthode d'instance __call__. Cela ne fait qu'imprimer ses arguments d'une manière assez stupide, mais cela montre à quel point nous parlons peu. :)

Si vous vouliez quelque chose de plus intelligent, il pourrait faire quelque chose comme ceci:

class handle_lines:
  def __init__(self):
    self.lines = []
  def __call__(self, *args):
    self.lines << args[0]

Appelez iterlines avec un objet de cette classe, puis cherchez dans le membre lines de l'objet pour plus de détails.

7
sarnold

ce code est un peu excessif, je pense. 

(à partir de l'exemple python https://docs.python.org/2/library/ftplib.html ) Après ftp.login () et la définition de ftp.cwd (), vous pouvez simplement utiliser:

os.chdir(ddir)
ls = ftp.nlst()
count = len(ls)
curr = 0
print "found {} files".format(count)
for fn in ls:
    curr += 1
    print 'Processing file {} ... {} of {} ...'.format(fn, curr, count)
    ftp.retrbinary('RETR ' + fn, open(fn, 'wb').write)

ftp.quit()
print "download complete."

télécharger tous les fichiers.

3
kztd

Je suis débutant et je n’ai donc pas conçu le code de manière efficace, mais j’ai réussi à le tester et à le tester. C’est ce que j’ai fait pour télécharger des fichiers et des dossiers à partir du site ftp, mais avec une profondeur limitée dans la structure des fichiers.

try:
   a = input("Enter hostname : ")
   b = input("Enter username : ")
   c = input("Enter password : ")
   from ftplib import FTP
   import os
   os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp")
   os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp")
   ftp = FTP(Host = a, user= b, passwd = c)
   D = ftp.nlst()
   for d in D:
      l = len(d)
      char = False
      for i in range(0,l):
          char = char or d[i]=="."
      if not char:
         ftp.cwd("..")
         ftp.cwd("..")
         E = ftp.nlst("%s"%(d))
         ftp.cwd("%s"%(d))
         try:
             os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s"%(d))
         except:
             print("you can debug if you try some more")
         finally:
             os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s"%(d))
             for e in E:
                l1 = len(e)
                char1 = False
                for i in range(0,l1):
                   char1 = char1 or e[i]=="."
                if not char1:
                   ftp.cwd("..")
                   ftp.cwd("..")
                   F = ftp.nlst("%s/%s"%(d,e))
                   ftp.cwd("%s/%s"%(d,e))
                   try:
                       os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s\\%s"%(d,e))
                   except:
                       print("you can debug if you try some more")
                   finally:
                       os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s\\%s"%(d,e))
                       for f in F:
                           if "." in f[2:]:
                               with open(f,'wb') as filef:
                                   ftp.retrbinary('RETR %s' %(f), filef.write)
                           Elif not "." in f:
                               try:
                                  os.makedirs("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s\\%s\\%s"%(d,e,f))
                               except:
                                  print("you can debug if you try some more")
                Elif "." in e[2:]:
                   os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp\\%s"%(d))
                   ftp.cwd("..")
                   ftp.cwd("..")
                   ftp.cwd("..")
                   ftp.cwd("%s"%(d))
                   with open(e,'wb') as filee:
                      ftp.retrbinary('RETR %s' %(e), filee.write)
      Elif "." in d[2:]:
          ftp.cwd("..")
          ftp.cwd("..")
          os.chdir("C:\\Users\\PREM\\Desktop\\pyftp download\\ftp")
          with open(d,'wb') as filed:
             ftp.retrbinary('RETR %s'%(d), filed.write)
   ftp.close()
   print("Your files has been successfully downloaded and saved. Bye")
except:
    print("try again you can do it")
finally:
    print("code ran")
0
PremVijay