Comment se connecter à un serveur FTP à l’aide de Python
Le FTP (File Transfer Protocol) n’a pas besoin de présentation : c’est l’une des méthodes de transfert de fichiers les plus utilisées entre un ou plusieurs clients et un serveur. De par sa conception, il prend en charge à la fois l’accès anonyme et l’authentification, mais dans sa forme la plus basique, il ne fournit pas de cryptage des données, c’est pourquoi il est souvent sécurisé via TLS.
De nombreuses applications clientes FTP sont disponibles sous Linux, comme par exemple Filezilla (graphique) ou lftp (ligne de commande). Parfois, cependant, nous pouvons vouloir accéder à un serveur FTP par programmation, peut-être pour planifier des transferts de fichiers. Un moyen simple de le faire est d’utiliser un langage de programmation comme Python. Dans ce tutoriel, nous allons apprendre à utiliser la bibliothèque ftplib pour interagir avec un serveur FTP.
Dans ce tutoriel, vous allez apprendre :
- Comment créer une instance de ftplib. Classe FTP
- Comment lister des fichiers sur un serveur FTP distant
- Comment télécharger des fichiers en mode binaire et « lignes »
- Comment télécharger des fichiers en mode binaire et « lignes »
- Comment créer, supprimer et renommer des répertoires et des fichiers
- Comment changer de répertoire de travail
Comment se connecter à un serveur FTP à l’aide de Python
Configuration logicielle requise et conventions utilisées
La librairie ftplib
Le module ftplib fait partie de la bibliothèque standard Python, et fournit deux classes principales pour abstraire le travail avec une connexion FTP : ftblib. FTP et ftplib. FTP_TLS. Ce dernier est une sous-classe de la première et ajoute la prise en charge de TLS. Voyons quelques-uns des cas d’utilisation les plus courants de la bibliothèque.
Connexion à un serveur FTP
Pour se connecter à un serveur FTP, la première chose à faire est de créer une instance de la classe FTP. La classe supporte l’instruction with afin qu’elle puisse être utilisée avec un gestionnaire de contexte : de cette façon, la connexion sera automatiquement fermée lorsque nous aurons fini de travailler ou qu’une erreur se produira. Voici un exemple d’utilisation :
with ftplib.FTP('ftp.somehost.com') as ftp:
# codehere
Tous les paramètres du constructeur de la classe FTP sont facultatifs, mais ici nous avons fourni le premier argument accepté par celui-ci, qui est l’hôte auquel nous voulons nous connecter. Si l’argument est fourni, la méthode connect, utilisée pour établir une connexion avec le serveur, est appelée implicitement avec l’hôte spécifié passé en argument, sinon elle doit être appelée explicitement :
with ftplib.FTP() as ftp:
ftp.connect('ftp.somehost.com')
Le deuxième argument accepté par le constructeur de la classe FTP est l’utilisateur avec lequel nous voulons nous connecter au serveur ftp. Si vous fournissez cet argument, la méthode de connexion sera appelée implicitement avec l’utilisateur, les valeurs password et acct passées en arguments (ce sont les troisième et quatrième paramètres du constructeur de la classe, et par défaut une chaîne vide en valeur) :
with ftplib.FTP('ftp.somehost.it', 'testuser', 'testpassword') as ftp:
# codehere
Si l’argument n’est pas fourni, la méthode de connexion doit être appelée explicitement :
with ftplib.FTP('ftp.somehost.it') as ftp:
ftp.login('testuser', 'password')
Obtention d’une liste de fichiers sur le serveur
Une fois qu’un objet FTP est créé, nous avons essentiellement trois façons d’obtenir une liste des fichiers stockés sur le serveur FTP auquel nous sommes connectés. Tout d’abord, nous pouvons utiliser la méthode dir, qui produit une liste de répertoires telle que renvoyée par la commande LIST :
>>> with ftplib.FTP('ftp.somehost.it', 'user', 'password') as ftp:
... ftp.dir()
La méthode dir accepte un argument facultatif, qui est le répertoire à lister (la valeur par défaut est le répertoire de travail actuel, donc dans ce cas la racine FTP). Le code ci-dessus produit un résultat similaire à ce qui suit :
drwxr-xr-x 2 ftp ftp 4096 Oct 13 14:37 .
drwxr-xr-x 2 ftp ftp 4096 Oct 13 14:37 ..
-rw------- 1 ftp ftp 10 Sep 10 06:04 .ftpquota
-rw-r--r-- 1 ftp ftp 5306756 Oct 18 01:32 file.csv
La deuxième méthode que nous pouvons utiliser pour obtenir une liste de fichiers, est nlst. Comme son nom l’indique, cette méthode, sous le capot, envoie une commande NLST au serveur ; il renvoie une liste Python contenant le nom des fichiers en tant que membres :
>>> with ftplib.FTP('ftp.somehost.it', 'user', 'password') as ftp:
... ftp.nlst()
...
['.', '..', '.ftpquota', 'file.csv']
La troisième méthode que l’on peut utiliser pour obtenir la liste du contenu d’un répertoire est mlsd. Cette méthode utilise la commande MLSD (donc pour qu’elle fonctionne, le serveur doit la supporter), et accepte deux arguments optionnels :
- Le
chemin d’accèsdu répertoire qui doit être répertorié - Une liste des informations que nous voulons inclure dans le résultat
La méthode renvoie un générateur qui produit un tuple à deux éléments pour chaque fichier : le premier élément de chaque tuple est le nom du fichier ; le second un dictionnaire contenant les informations demandées et leurs valeurs. Voyons un exemple :
>>> with ftplib.FTP('ftp.somehost.it', 'user', 'password') as ftp:
... for filename, information in ftp.mlsd():
... print(filename, information)
Le résultat du code ci-dessus est le suivant :
. {'type': 'cdir', 'sizd': '4096', 'modify': '20201013123732', 'unix.mode': '0755', 'unix.uid': '1809', 'unix.gid': '1811', 'unique': 'fd04g58e0a67'}
.. {'type': 'pdir', 'sizd': '4096', 'modify': '20201013123732', 'unix.mode': '0755', 'unix.uid': '1809', 'unix.gid': '1811', 'unique': 'fd04g58e0a67'}
.ftpquota {'type': 'file', 'size': '10', 'modify': '20200910040430', 'unix.mode': '0600', 'unix.uid': '1809', 'unix.gid': '1811', 'unique': 'fd04g58e0a9d'}
file.csv {'type': 'file', 'size': '5306756', 'modify': '20201017233245', 'unix.mode': '0644', 'unix.uid': '1809', 'unix.gid': '1811', 'unique': 'fd04g58e020a'}
Notez qu’il n’est pas garanti que le serveur respecte la liste des informations que nous demandons.
Récupération de fichiers à partir du serveur
Pour récupérer des fichiers sur le serveur, nous pouvons utiliser les méthodes retrbinary ou retlines. Voyons comment ils fonctionnent.
La méthode retrbinary récupère un fichier en mode transfert binaire : c’est ce que vous voulez utiliser pour télécharger simplement un fichier du serveur sur votre machine locale et sans avoir besoin d’interagir avec son contenu. Voyons un exemple de son utilisation. Supposons que nous voulions télécharger le file.csv à partir du serveur ; Nous écririons simplement :
>>> with ftplib.FTP('ftp.somehost.it', 'user', 'password') as ftp:
... with open('file.csv', 'wb') as downloaded_file:
... ftp.retrbinary('RETR file.csv', downloaded_file.write)
...
'226-File successfully transferred\n226 0.823 seconds (measured here), 6.15 Mbytes per second'
Dans l’exemple ci-dessus, nous avons ouvert un fichier local pour l’écriture en mode binaire
(file.csv) à l’aide d’un gestionnaire de contexte, puis nous avons appelé la méthode retrbinary en passant
une commande RETR appropriée en tant que premier argument (RETR nameofthefile), et la méthode d’écriture
de l’objet file downloaded_file en tant que deuxième argument, qui
est un callback appliqué à chaque bloc de données reçu.
En parlant de blocs de données, la taille maximale de bloc utilisée pour le transfert
de données, par défaut, est de 8192 octets. Cependant, cela peut être modifié via le troisième paramètre facultatif
de la méthode retrbinary.
La méthode retrlines fonctionne un peu différemment, puisqu’elle récupère les fichiers en mode « ligne ». Le premier argument de cette méthode peut être une commande RETR valide, tout comme celle que nous avons utilisée dans l’exemple précédent, mais aussi une LIST (pour récupérer une liste de noms de fichiers et des informations les concernant) ou NLST (récupérer uniquement les noms de fichiers). Le deuxième argument de la méthode est facultatif et est un callback qui est appliqué à chaque ligne récupérée (le comportement par défaut est d’imprimer les lignes sur stdout). Il est important de noter que chaque ligne est dépouillée du caractère de fin de ligne, qui sous Linux est \n.
Voyons un exemple. Si nous utilisons la méthode retlines, nous pouvons récupérer le contenu du fichier file.csv ligne par ligne :
>>> import os
>>> with ftplib.FTP('host', 'user', 'password') as ftp:
... with open('file.csv', 'w') as csvfile:
... ftp.retrlines('RETR file.csv', lambda x: csfile.write("".join([x,os.linesep])))
...
Dans l’exemple ci-dessus, nous avons importé le module os, puis, comme précédemment, nous avons créé un fichier localement, cette fois en mode texte. Avec la méthode ftp.retrlines, nous avons récupéré le fichier distant file.csv ligne par ligne. Le callback que nous avons utilisé comme deuxième argument des retrlines est une fonction lambda qui prend la ligne comme argument et appelle la méthode write de l’objet csvfile pour écrire la ligne jointe avec le caractère linesep approprié pour l’Os, auquel nous avons accédé par os.linesep.
Nous pouvons utiliser le callback pour modifier également le contenu du fichier à la volée. À titre d’exemple trivial, imaginons que nous voulions mettre en majuscule chaque mot contenu dans le fichier distant lorsque nous le stockons localement. On pourrait écrire :
[...]
... ftp.retrlines('RETR file.csv', lambda x: csfile.write("".join([x.upper(),os.linesep])))
Cette méthode, comme nous l’avons déjà mentionné, peut également être utilisée pour travailler avec les lignes renvoyées par les commandes LIST ou NLST. Supposons que nous voulions enregistrer le résultat de la liste d’un répertoire sur le serveur distant dans un fichier local :
>>> with ftplib.FTP('host', 'user', 'password') as ftp:
... with open('list_result', 'w') as localfile:
... ftp.retrlines('LIST', lambda x: localfile.write("".join([x, os.linesep])))
Le fichier local list_result sera créé (ou tronqué et écrasé s’il existe déjà), et son contenu sera similaire à :
drwxr-xr-x 2 ftp ftp 4096 Oct 13 14:37 .
drwxr-xr-x 2 ftp ftp 4096 Oct 13 14:37 ..
-rw------- 1 ftp ftp 10 Sep 10 06:04 .ftpquota
-rw-r--r-- 1 ftp ftp 5306756 Oct 18 01:32 file.csv
Téléchargement de fichiers sur le serveur
Lorsque nous avons besoin de télécharger un fichier sur un serveur FTP, nous pouvons également choisir de le faire en mode binaire ou « lignes ». Les deux méthodes que nous pouvons utiliser pour accomplir la tâche sont respectivement : storebinary et storelines.
La méthode storebinary de la classe FTP prend deux arguments obligatoires qui sont une commande STOR valide, et l’objet fichier créé à partir d’un fichier local ouvert en mode binaire. Supposons que nous voulions télécharger un fichier ; Nous écririons :
>>> with ftplib.FTP('host', 'user', 'password') as ftp:
... with open('linuxconfig.txt', 'rb') as file_object:
... ftp.storbinary('STOR linuxconfig.txt', file_object)
C’est très simple ! Bien sûr, nous pouvons également stocker le fichier sur le serveur sous un autre nom. L’objet fichier passé en tant que deuxième argument de la méthode storbinary est lu jusqu’à EOF. Tout comme dans le cas de la méthode retrbinary, il est possible de modifier la taille du bloc de données, avec le troisième argument facultatif (la valeur par défaut est, encore une fois, de 8192 octets). Le quatrième argument accepté par la méthode storbinary est une fonction de rappel facultative qui est appliquée à chaque bloc de données.
Pour télécharger un fichier ligne par ligne, nous pouvons utiliser la méthode storlines à la place. Dans ce cas, le fichier que nous voulons télécharger sera lu ligne par ligne. Les deux premiers arguments sont les mêmes que ceux acceptés par la méthode storbinary, tandis que le troisième (et dernier) est un callback qui est appliqué à chaque ligne.
Navigation, création de répertoires, suppression et renommage de fichiers
La classe FTP (et la classe FTP_TLS qui l’étend) fournit également des méthodes très utiles pour effectuer certaines des opérations les plus courantes. Par exemple, pour créer un répertoire sur le serveur FTP distant, on peut utiliser la méthode mkd qui prend comme seul argument le chemin d’accès du répertoire à créer :
>>> ftp.mkd('newdir')
'newdir'
Pour changer le répertoire de travail, nous pouvons utiliser la méthode cwd, en passant le nom du répertoire dans lequel nous voulons nous déplacer comme argument :
>>> ftp.cwd('newdir')
'250 OK. Current directory is /newdir'
Pour supprimer un répertoire existant, on peut utiliser la méthode rmd en passant le nom du répertoire à supprimer :
>>> ftp.rmd('newdir')
'250 The directory was successfully removed'
Pour supprimer un fichier normal, nous pouvons utiliser la méthode delete à la place, en passant le nom du fichier à supprimer comme argument :
>>> ftp.delete('file.csv')
'250 Deleted file.csv'
Pour renommer des fichiers ou des répertoires, nous pouvons utiliser la méthode rename. Il accepte deux arguments : le premier est le nom actuel du fichier ou du répertoire, le second est le nouveau. Pour renommer file.csv en file0.csv, par exemple, nous écririons :
>>> ftp.rename('file.csv', 'file0.csv')
'250 File successfully renamed or moved'
Fermeture manuelle d’une connexion
Comme nous l’avons déjà appris, la classe FTP peut être utilisée avec un gestionnaire de contexte, de sorte que la connexion est automatiquement fermée lorsque l’interpréteur quitte le bloc d’instructions with. Dans les cas où nous devons fermer la connexion manuellement, cependant, nous devons utiliser la méthode quit : elle appelle la méthode close en interne et envoie une commande QUIT au serveur pour essayer de fermer la connexion correctement.
Conclusions
Dans cet article, nous avons appris à utiliser le module python ftplib afin de se connecter à un serveur FTP et d’interagir avec celui-ci. Nous avons vu comment créer une instance de la classe FTP et quelles sont les méthodes que nous pouvons utiliser pour lister le contenu d’un répertoire distant et charger/télécharger des fichiers. Nous avons également vu comment créer, supprimer, renommer et supprimer des répertoires ou des fichiers et comment modifier le répertoire de travail. Dans ce tutoriel, nous avons exploré les cas d’utilisation les plus courants, pour une liste complète des fonctionnalités, veuillez visiter la page officielle de libftp.
