124 votes

Comment copier un fichier sur un serveur distant en Python en utilisant SCP ou SSH ?

J'ai un fichier texte sur ma machine locale qui est généré par un script quotidien exécuté dans cron.

Je voudrais ajouter un peu de code pour que ce fichier soit envoyé en toute sécurité à mon serveur via SSH.

169voto

Tony Meyer Points 4700

Pour faire cela en Python (c'est-à-dire sans faire passer scp par subprocess.Popen ou similaire) avec la commande Paramiko bibliothèque, vous feriez quelque chose comme ça :

import os
import paramiko

ssh = paramiko.SSHClient() 
ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username=username, password=password)
sftp = ssh.open_sftp()
sftp.put(localpath, remotepath)
sftp.close()
ssh.close()

(Vous voudrez probablement traiter les hôtes inconnus, les erreurs, la création de tous les répertoires nécessaires, et ainsi de suite).

15 votes

paramiko dispose également d'une belle fonction sftp.put(self, localpath, remotepath, callback=None), ce qui vous évite d'avoir à ouvrir, écrire et fermer chaque fichier.

7 votes

Je tiens à préciser que SFTP n'est pas la même chose que SCP.

4 votes

@Drahkar la question demande que le fichier soit envoyé par SSH. C'est ce que cela fait.

66voto

pdq Points 236

Vous pouvez appeler le scp bash (il copie les fichiers sur SSH ) avec subprocess.run :

import subprocess
subprocess.run(["scp", FILE, "USER@SERVER:PATH"])
#e.g. subprocess.run(["scp", "foo.bar", "joe@srvr.net:/path/to/foo.bar"])

Si vous créez le fichier que vous voulez envoyer dans le même programme Python, vous voudrez appeler subprocess.run en dehors du with que vous utilisez pour ouvrir le fichier (ou appelez le bloc .close() sur le fichier d'abord si vous n'utilisez pas un fichier with ), de sorte que vous savez qu'il est transféré sur le disque depuis Python.

Vous devez générer (sur la machine source) et installer (sur la machine de destination) une clé ssh au préalable afin que le scp soit automatiquement authentifié avec votre clé ssh publique (en d'autres termes, afin que votre script ne demande pas de mot de passe).

3 votes

@CharlesDuffy : subprocess.check_call(['scp', srcfile, dest]) peut être utilisé depuis Python 2.5 à la place de rc = Popen(..).wait(); if rc != 0: raise ..

1 votes

L'ajout d'une clé ssh n'est pas une bonne solution lorsqu'elle n'est pas nécessaire. Par exemple, si vous avez besoin d'une communication ponctuelle, vous ne configurez pas de clé ssh pour des raisons de sécurité.

33voto

Blair Conrad Points 56195

Vous utiliseriez probablement le module de sous-processus . Quelque chose comme ça :

import subprocess
p = subprocess.Popen(["scp", myfile, destination])
sts = os.waitpid(p.pid, 0)

destination est probablement de la forme user@remotehost:remotepath . Merci à @Charles Duffy pour avoir souligné la faiblesse de ma réponse originale, qui utilisait un seul argument de type chaîne pour spécifier l'opération scp. shell=True - qui ne gère pas les espaces dans les chemins.

La documentation du module a des exemples de vérification d'erreurs que vous pourriez vouloir effectuer en conjonction avec cette opération.

Assurez-vous que vous avez mis en place les informations d'identification appropriées afin de pouvoir effectuer une vérification de l'identité de la personne. scp sans surveillance et sans mot de passe entre les machines. . Il existe un question de stackoverflow pour cela déjà .

3 votes

Utiliser subprocess.Popen est la bonne chose. Lui passer une chaîne plutôt qu'un tableau (et utiliser shell=True) est la mauvaise chose, car cela signifie que les noms de fichiers avec des espaces ne fonctionnent pas correctement.

2 votes

au lieu de "sts = os.waitpid(p.pid, 0)", nous pouvons utiliser "sts = p.wait()".

0 votes

existe-t-il un moyen sans exécution avec une API python directe pour ce protocole ?

14voto

Il existe plusieurs façons d'aborder le problème :

  1. Envelopper les programmes de ligne de commande
  2. utiliser une bibliothèque Python qui offre des fonctionnalités SSH (par exemple, la bibliothèque - Paramiko ou Conque tordue )

Chaque approche a ses propres particularités. Vous devrez configurer des clés SSH pour permettre des connexions sans mot de passe si vous enveloppez des commandes système comme "ssh", "scp" ou "rsync". Vous pouvez intégrer un mot de passe dans un script en utilisant Paramiko ou une autre bibliothèque, mais vous pourriez trouver le manque de documentation frustrant, surtout si vous n'êtes pas familier avec les bases de la connexion SSH (par exemple - échanges de clés, agents, etc). Il va probablement sans dire que les clés SSH sont presque toujours une meilleure idée que les mots de passe pour ce genre de choses.

NOTE : il est difficile de battre rsync si vous prévoyez de transférer des fichiers via SSH, surtout si l'alternative est le bon vieux scp.

J'ai utilisé Paramiko dans le but de remplacer les appels système, mais j'ai été attiré par les commandes enveloppées en raison de leur facilité d'utilisation et de leur familiarité immédiate. Vous êtes peut-être différent. J'ai jeté un coup d'oeil à Conch il y a quelque temps, mais il ne m'a pas séduit.

Si vous optez pour le chemin de l'appel système, Python offre un éventail d'options telles que os.system ou les modules commands/subprocess. J'opterais pour le module subprocess si vous utilisez la version 2.4+.

1 votes

Curieux : quelle est l'histoire de rsync vs. scp ?

12voto

Maviles Points 1222

J'ai rencontré le même problème, mais au lieu de "pirater" ou d'émuler la ligne de commande :

J'ai trouvé cette réponse ici .

from paramiko import SSHClient
from scp import SCPClient

ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect('example.com')

with SCPClient(ssh.get_transport()) as scp:
    scp.put('test.txt', 'test2.txt')
    scp.get('test2.txt')

1 votes

Note - ceci repose sur le paquet scp. En décembre 2017, la dernière mise à jour de ce paquet date de 2015 et le numéro de version est 0.1.x. Je ne suis pas sûr de vouloir ajouter cette dépendance.

2 votes

Nous sommes donc en 2018 et la version 0.11.0 est sortie en mai. Donc, il semble que SCPClient n'est pas mort après tout ?

0 votes

Le module scp est régulièrement mis à jour (la dernière fois en juin 2021) et a 380 étoiles sur github. c'est une solution légitime.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X