web-dev-qa-db-ja.com

SCPまたはSSHを使用してPythonのファイルをリモートサーバーにコピーする方法は?

ローカルマシンに、cronで実行される毎日のPythonスクリプトによって生成されるテキストファイルがあります。

そのファイルをSSH経由でサーバーに安全に送信するためのコードを少し追加したいと思います。

92
Alok

シンプルなアプローチが必要な場合は、これでうまくいくはずです。

Pythonからディスクにフラッシュされていることがわかるように、最初にファイルを「.close()」する必要があります。

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

Scpが公開sshキーで自動的に認証されるように(つまり、スクリプトがパスワードを要求しないように)、事前にsshキーを生成(ソースマシン上)およびインストール(宛先マシン上)する必要があります。

ssh-keygenの例

46
pdq

Paramiko ライブラリを使用してPython(つまり、subprocess.Popenなどでscpをラップしない)でこれを行うには、何かを行う必要があります。このような:

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()

(おそらく、不明なホスト、エラー、必要なディレクトリの作成などに対処したいと思うでしょう)。

136
Tony Meyer

おそらく subprocess module を使用するでしょう。このようなもの:

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

destinationはおそらくuser@remotehost:remotepathの形式です。元の回答の弱点を指摘してくれた@Charles Duffyに感謝します。これは、単一の文字列引数を使用してscp操作Shell=Trueを指定しました。パスの空白は処理しません。

モジュールのドキュメントには、 この操作と組み合わせて実行するエラーチェックの例 があります。

マシン間の無人、パスワードなしのscp を実行できるように、適切な資格情報を設定したことを確認してください。 これに関するstackoverflowの質問 があります。

30
Blair Conrad

問題にアプローチする方法はいくつかあります。

  1. コマンドラインプログラムをラップする
  2. sSH機能を提供するPythonライブラリを使用します(例- Paramiko または Twisted Conch

各アプローチには独自の癖があります。 「ssh」、「scp」、「rsync」などのシステムコマンドをラップする場合は、パスワードなしのログインを有効にするためにSSHキーをセットアップする必要があります。 Paramikoまたは他のライブラリを使用してスクリプトにパスワードを埋め込むことができますが、特にSSH接続の基本(たとえば、キー交換、エージェントなど)に慣れていない場合は、ドキュメントが不足していることがわかります。おそらく、SSHキーの方がこの種のパスワードよりも常に優れたアイデアであることは言うまでもないでしょう。

注:SSH経由でファイルを転送する場合、特に代替手段が単純な古いscpである場合は、rsyncに勝るものはありません。

システムコールの置き換えに目を向けてParamikoを使用しましたが、使いやすさとすぐに慣れたために、ラップされたコマンドに引き戻されました。あなたは違うかもしれません。しばらく前にコンクをもう一度やりましたが、それは私にはアピールしませんでした。

システムコールパスを選択する場合、Pythonはos.systemやコマンド/サブプロセスモジュールなどのオプションの配列を提供します。バージョン2.4+を使用している場合は、サブプロセスモジュールを使用します。

11
Michael

同じ問題に到達しましたが、コマンドラインを「ハッキング」またはエミュレートする代わりに:

この答えを見つけました here

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

ホストキーチェックも処理するために、このようなことをすることができます

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

このために設計されたvassalパッケージを使用できます。

必要なのは、vassalをインストールして

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

また、認証情報が保存されるため、何度も入力する必要がありません。

1
Shawn

外部リソースparamikoを使用します。

    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

非常に簡単なアプローチは次のとおりです。

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

pythonライブラリは不要(osのみ)で、動作します

0

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

sshfs を使用してssh経由でリモートディレクトリをマウントし、 shutil を使用してファイルをコピーしました。

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

次に、Pythonで:

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

この方法には、ローカルにキャッシュして1つの大きなファイルを送信するのではなく、データを生成する場合にデータをストリーミングできるという利点があります。

0
Jonno_FTW

サブプロセス経由でscpコマンドを呼び出すと、スクリプト内で進行状況レポートを受信できません。 pexpectを使用して、その情報を抽出できます。

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})

ローカルネットワークのPythonコピーファイル(linux-> linux) を参照してください

0
jfs