Chemin principal : Accueil > Python > FTP > Récupérer un répertoire par FTP

Autres chemins : (Aller directement au contenu de l'article)

Récupérer un répertoire par FTP

lundi 3 janvier 2011, mise à jour mercredi 8 août 2012, par Maïeul
Suivre la vie du site RSS 2.0 Forum

Pour sauvegarder régulièrement mes sites web, j’utilise un script Python personnel. Une des étapes consiste à récupérer des fichier sur un serveur FTP. Comme j’ai eu un peu de mal à comprendre comment fonctionne le module FTP de Python, je vous livre ici ma solution.

J’ai décidé de créer une nouvelle classe ftp_perso qui contiendra un ensemble de méthode. [1] Dérivée de la classe FTP elle devrait permettre :

  • de lister récursivement le contenu d’un répertoire.
  • de récupérer récursivement le contenu d’un répertoire.

Un problème qui s’est posé est que tous les serveurs FTP ne renvoient pas le même type de chemin : certains renvoient un chemin depuis la racine, d’autres se contentent d’indiquer le nom du répertoire courant.

Pour résoudre cela, à l’initialisation d’une instance de classe, un attribut d’objet est calculé. self.hierarchie : selon sa valeur, le parcours récursif ne sera pas effectué de la même manière, car il ne faudra pas envoyer les mêmes requêtes au serveur.

Par ailleurs certains listent les dossiers . et .. lorsqu’on envoie une commande ls. Comme il s’agit du répertoire courant et du répertoire parent, il ne faut pas les utiliser lorsqu’on parcourt récursivement, sinon on tourne. J’ai donc défini un attribut de d’objet, avec une valeur standard mais pouvant prendre de nouvelles valeurs à l’initialisation d’une instance : self.faux_reps, qui contient la liste des dossiers à ne pas parcourir.

Enfin, il n’est pas toujours évident de savoir si un fichier est un répertoire (dossier) ou nom : j’ai donc défini une méthode is_dir(self, file) que j’appelle sur chaque fichier avant de tenter d’y entrer comme un répertoire.

Au final j’ai donc :

  • une méthode is_dir() à usage interne.
  • une méthode lister_repertoire(self,rep='',niveau=0) qui permet de lister récursivement un répertoire. Cette méthode s’appelle elle même, d’où l’argument niveau.
  • une méthode rapatrier_repertoire(self,chemin_local='.',rep='',niveau=0) qui permet de récupérer un répertoire distant en local.
  1. class ftp_perso(FTP):
  2. ''' Reprend la class FTP de ftplib en rajoutant le listage récursive d'un répertoire et la récupération de l'ensemble du contenur d'un répertoire'''
  3. def __init__(self,host,user,mdp,faux_dossiers=()):
  4. FTP.__init__(self,host,user,mdp)
  5. self.mkd('pyftptest')
  6. self.mkd('pyftptest/pyftptest')
  7. self.hierarchie=self.nlst('pyftptest')
  8. self.rmd('pyftptest/pyftptest')
  9. self.rmd('pyftptest')
  10. self.faux_reps = ('..','.','.ok','article_PDF') + faux_dossiers
  11. if len(self.hierarchie) > 1:
  12.  
  13. from string import find
  14. if find(self.hierarchie[2],'/') > -1:
  15. self.hierarchie = '/'
  16. else:
  17. self.hierarchie = ''
  18. else:
  19. self.hierarchie = '/'
  20. def lister_repertoire(self,rep='',niveau=0):
  21. from string import rfind
  22. contenu = self.nlst(rep)
  23.  
  24. if self.hierarchie != '/':
  25. for i in contenu:
  26. if not i in self.faux_reps:
  27. print rep+'/'+i
  28. if not self.is_dir(rep+'/'+i):
  29. print "%sFichier «%s»" % (niveau * "\t", i )
  30. else:
  31. print "%s Dossier «%s»" % (niveau * "\t", i )
  32. self.lister_repertoire(rep+'/'+i,niveau=niveau+1)
  33. else:
  34. for i in contenu:
  35. if not i[rfind(i,'/')+1:] in self.faux_reps:
  36. if not self.is_dir(i):
  37. print "%sFichier «%s»" % (niveau * "\t", i[rfind(i,'/')+1:] )
  38. else:
  39. print "%s Dossier «%s»" % (niveau * "\t", i[rfind(i,'/')+1:] )
  40. self.lister_repertoire(i,niveau=niveau+1)
  41.  
  42. def is_dir(self,file):
  43. try:
  44. courant = self.pwd()
  45. self.cwd(file)
  46. self.cwd(courant)
  47. return True
  48. except:
  49. return False
  50.  
  51. def rapatrier_repertoire(self,chemin_local='.',rep='',niveau=0):
  52. from string import rfind
  53. contenu = self.nlst(rep)
  54. if self.hierarchie != '/':
  55. for i in contenu:
  56. if not i in self.faux_reps:
  57. print rep + '/' + i
  58. if not self.is_dir(rep+'/'+i):
  59. if rep!='' and rep[0]!='/':
  60. self.retrbinary('RETR '+rep+'/'+i,open(chemin_local+'/'+rep+'/'+i,'wb').write)
  61. else:
  62. self.retrbinary('RETR '+rep+'/'+i,open(chemin_local+rep+'/'+i,'wb').write)
  63. else:
  64.  
  65. if rep!='' and rep[0]!='/':
  66. makedirs(chemin_local+'/'+rep+'/'+i)
  67. else:
  68. makedirs(chemin_local+rep+'/'+i)
  69.  
  70. self.rapatrier_repertoire(chemin_local,rep+'/'+i,niveau=niveau+1)
  71. else:
  72. for i in contenu:
  73. if not i[rfind(i,'/')+1:] in self.faux_reps:
  74. print i
  75. if not self.is_dir(i):
  76. self.retrbinary('RETR '+i,open(chemin_local+'/'+i,'wb').write)
  77. else:
  78. makedirs(chemin_local+'/'+i)
  79. self.rapatrier_repertoire(chemin_local,i,niveau=niveau+1)

Télécharger

P.-S.

Si vous voulez récuperer le code, attention à bien prendre celui dans le lien de téléchargement, sinon vous perdez les indentations.

Notes

[1Si vous trouvez un nom mieux je suis preneur.

Qui êtes-vous ?

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici
  • Ce formulaire accepte les raccourcis SPIP [->url] {{gras}} {italique} <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

À propos

Titulaire d’un doctorat en théologie et d’un doctorat en histoire, sous la direction conjointe de Frédéric Amsler et d’Élisabeth_Malamut, je commence à partir du 1er août 2017 un travail d’édition critique des Actes de Barnabé.

Dans le cadre de la rédaction de mon mémoire de master puis de ma thèse de doctorat, j’ai été emmené à utiliser LaTeX, et j’ai donc décider de partager mes techniques. En effet, au cours de mes premiers apprentissages, j’ai découvert que les ressources indiquant les outils pour l’utilisation de LaTeX en sciences humaines étaient rares. Ceci m’a conduit à maintenir ou créer plusieurs packages LaTeX et à donner plusieurs formations.

Par ailleurs, je suis membre actif de la communauté SPIP, au sein de laquelle j’administre le site Spip-Contrib. Je propose sur ce site quelques notes sur SPIP, en général à destination de webmestre.

Il m’arrive également de faire un petit peu de Python, de temps en temps.

Enfin, je tiens un blog de réflexions politiques et religieuses.

Maïeul