web-dev-qa-db-fra.com

Comment copier un fichier sur un serveur distant en Python à l'aide de SCP ou de SSH?

J'ai un fichier texte sur mon ordinateur local qui est généré par un script Python 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.

85
Alok

Si vous voulez une approche simple, cela devrait fonctionner.

Vous voudrez d'abord ". Close ()" le fichier pour que vous sachiez qu'il est vidé sur le disque depuis Python.

import os
os.system("scp FILE USER@SERVER:PATH")
#e.g. os.system("scp foo.bar [email protected]:/path/to/foo.bar")

Vous devez préalablement générer (sur la machine source) et installer (sur la machine de destination) une clé ssh afin que le scp soit automatiquement authentifié avec votre clé ssh publique (autrement dit, votre script ne demande pas de mot de passe). . 

Exemple ssh-keygen

39
pdq

Pour faire cela en Python (c’est-à-dire ne pas insérer scp dans subprocess.Popen ou similaire) avec la bibliothèque Paramiko , vous feriez quelque chose comme ceci:

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 avec des hôtes inconnus, des erreurs, créer des répertoires nécessaires, etc.).

129
Tony Meyer

Vous utiliseriez probablement le module subprocess . 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 d’avoir signalé la faiblesse de ma réponse initiale, qui utilisait un seul argument de chaîne pour spécifier l’opération scp Shell=True - qui ne gérera pas les espaces dans les chemins.

La documentation du module contient des exemples de vérification d'erreur que vous souhaiterez peut-être effectuer conjointement à cette opération.

Assurez-vous que vous avez configuré les informations d'identification appropriées de manière à pouvoir effectuer un scp sans surveillance et sans mot de passe entre les ordinateurs . Il y a une question stackoverflow pour cela déjà .

28
Blair Conrad

Il existe différentes manières d’aborder le problème:

  1. Envelopper les programmes en ligne de commande
  2. utiliser une bibliothèque Python offrant des fonctionnalités SSH (par exemple, - Paramiko ou Twisted Conch )

Chaque approche a ses propres bizarreries. Vous devrez configurer les clés SSH pour permettre les connexions sans mot de passe si vous utilisez des commandes système telles que "ssh", "scp" ou "rsync". Vous pouvez intégrer un mot de passe dans un script à l'aide de Paramiko ou d'une autre bibliothèque, mais le manque de documentation peut être frustrant, en particulier si vous ne connaissez pas les bases de la connexion SSH (par exemple, les échanges de clés, les agents, etc.). Il va sans dire que les clés SSH sont presque toujours une meilleure idée que les mots de passe pour ce genre de choses.

REMARQUE: il est difficile de battre rsync si vous envisagez de transférer des fichiers via SSH, en particulier si vous utilisez l'alternative old scp.

J'ai utilisé Paramiko avec le souci de remplacer les appels système, mais je me suis retrouvé de retour aux commandes encapsulées en raison de leur facilité d'utilisation et de leur familiarité immédiate. Vous pourriez être différent. J'ai déjà fait un tour à Conch, mais cela ne m'a pas interpellé.

Si vous optez pour le chemin d’appel système, Python propose un éventail d’options telles que os.system ou les modules commandes/sous-processus. J'irais avec le module de sous-processus si vous utilisez la version 2.4+.

10
Michael

Atteint le même problème, mais au lieu de "piratage" ou émulation de ligne de commande:

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')
6
Maviles

Vous pouvez faire quelque chose comme ça, pour gérer la vérification de la clé de l'hôte

import os
os.system("sshpass -p password scp -o StrictHostKeyChecking=no local_file_path username@hostname:remote_path")
4
Pradeep Pathak

fabric pourrait être utilisé pour télécharger des fichiers via ssh:

#!/usr/bin/env python
from fabric.api import execute, put
from fabric.network import disconnect_all

if __name__=="__main__":
    import sys
    # specify hostname to connect to and the remote/local paths
    srcdir, remote_dirname, hostname = sys.argv[1:]
    try:
        s = execute(put, srcdir, remote_dirname, Host=hostname)
        print(repr(s))
    finally:
        disconnect_all()
3
jfs

Vous pouvez utiliser le paquet vassal, qui est exactement conçu pour cela.

Tout ce dont vous avez besoin est d'installer vassal et de le faire

from vassal.terminal import Terminal
Shell = Terminal(["scp username@Host:/home/foo.txt foo_local.txt"])
Shell.run()

En outre, cela vous permettra d’enregistrer les informations d’authentification et vous éviterez de les taper encore et encore.

1
Shawn
from paramiko import SSHClient
from scp import SCPClient
import os

ssh = SSHClient() 
ssh.load_Host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
ssh.connect(server, username='username', password='password')
with SCPClient(ssh.get_transport()) as scp:
        scp.put('test.txt', 'test2.txt')
0
michael

une approche très simple est la suivante: 

import os
os.system('sshpass -p "password" scp user@Host:/path/to/file ./')

aucune bibliothèque python n'est requise (seulement os) et cela fonctionne

0
Roberto Marzocchi

Essayez ceci si vous ne voulez pas utiliser les certificats SSL:

import subprocess

try:
    # Set scp and ssh data.
    connUser = 'john'
    connHost = 'my.Host.com'
    connPath = '/home/john/'
    connPrivateKey = '/home/user/myKey.pem'

    # Use scp to send file from local to Host.
    scp = subprocess.Popen(['scp', '-i', connPrivateKey, 'myFile.txt', '{}@{}:{}'.format(connUser, connHost, connPath)])

except CalledProcessError:
    print('ERROR: Connection to Host failed!')
0
JavDomGom

J'ai utilisé sshfs pour monter le répertoire distant via ssh, et shutil pour copier les fichiers:

$ mkdir ~/sshmount
$ sshfs user@remotehost:/path/to/remote/dst ~/sshmount

Puis en python:

import shutil
shutil.copy('a.txt', '~/sshmount')

Cette méthode présente l’avantage de pouvoir diffuser des données en continu si vous générez des données plutôt que de les mettre en cache localement et d’envoyer un seul fichier volumineux.

0
Jonno_FTW

L'appel de la commande scp via un sous-processus ne permet pas de recevoir le rapport de progression à l'intérieur du script. pexpect pourrait être utilisé pour extraire cette information:

import pipes
import re
import pexpect # $ pip install pexpect

def progress(locals):
    # extract percents
    print(int(re.search(br'(\d+)%$', locals['child'].after).group(1)))

command = "scp %s %s" % Tuple(map(pipes.quote, [srcfile, destination]))
pexpect.run(command, events={r'\d+%': progress})

Voir Fichier de copie python dans le réseau local (linux -> linux)

0
jfs