Programing

SCP 또는 SSH를 사용하여 Python의 원격 서버에 파일을 복사하는 방법은 무엇입니까?

lottogame 2020. 8. 31. 08:18
반응형

SCP 또는 SSH를 사용하여 Python의 원격 서버에 파일을 복사하는 방법은 무엇입니까?


cron에서 실행되는 매일 Python 스크립트에 의해 생성되는 로컬 컴퓨터에 텍스트 파일이 있습니다.

SSH를 통해 해당 파일을 내 서버로 안전하게 전송하기 위해 약간의 코드를 추가하고 싶습니다.


간단한 접근 방식을 원한다면 이것이 작동합니다.

먼저 파일을 ".close ()"하여 Python에서 디스크로 플러시된다는 것을 알 수 있습니다.

import os
os.system("scp FILE USER@SERVER:PATH")
#e.g. os.system("scp foo.bar joe@srvr.net:/path/to/foo.bar")

scp가 공개 ssh 키로 자동으로 인증되도록 (즉, 스크립트가 암호를 요청하지 않도록) ssh 키를 미리 생성하고 (소스 시스템에서) 설치 (대상 시스템에)해야합니다. .

ssh-keygen 예


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

(알 수없는 호스트, 오류, 필요한 디렉토리 생성 등을 처리하고 싶을 것입니다.)


아마도 subprocess 모듈을 사용할 것입니다 . 이 같은:

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

어디 destination아마 양식입니다 user@remotehost:remotepath. 단일 문자열 인수를 사용하여 shell=True경로의 공백을 처리하지 않는 단일 문자열 인수를 사용하는 내 원래 답변의 약점을 지적한 @Charles Duffy에게 감사드립니다 .

모듈 설명서에는 이 작업과 함께 수행 할 수있는 오류 검사 예제가 있습니다.

머신간에 무인 암호없는 scp를 수행 할 수 있도록 적절한 자격 증명을 설정했는지 확인합니다 . 이미 이것에 대한 stackoverflow 질문이 있습니다.


문제에 접근하는 방법에는 몇 가지가 있습니다.

  1. 명령 줄 프로그램 래핑
  2. SSH 기능을 제공하는 Python 라이브러리 사용 (예 : Paramiko 또는 Twisted Conch )

각 접근 방식에는 고유 한 단점이 있습니다. "ssh", "scp"또는 "rsync"와 같은 시스템 명령을 래핑하는 경우 암호없는 로그인을 사용하려면 SSH 키를 설정해야합니다. Paramiko 또는 다른 라이브러리를 사용하여 스크립트에 암호를 포함 할 수 있지만 특히 SSH 연결의 기본 사항 (예 : 키 교환, 에이전트 등)에 익숙하지 않은 경우 문서가 부족하다는 것을 알 수 있습니다. SSH 키가 이런 종류의 암호보다 거의 항상 더 나은 아이디어라는 것은 말할 필요도 없습니다.

참고 : SSH를 통해 파일을 전송할 계획이라면 rsync를 이기기가 어렵습니다. 특히 대안이 일반 오래된 scp 인 경우 더욱 그렇습니다.

저는 Paramiko를 시스템 호출을 대체하기 위해 사용했지만 사용의 용이성과 즉각적인 친숙 함으로 인해 래핑 된 명령에 다시 끌 렸습니다. 당신은 다를 수 있습니다. 나는 얼마 전에 Conch를 한 번 줬지만 그것은 나에게 호소력이 없었습니다.

시스템 호출 경로를 선택하면 Python은 os.system 또는 명령 / 하위 프로세스 모듈과 같은 옵션 배열을 제공합니다. 버전 2.4 이상을 사용하는 경우 하위 프로세스 모듈을 사용합니다.


동일한 문제에 도달했지만 "해킹"또는 에뮬레이션 명령 줄 대신 :

여기 에서이 답변을 찾았 습니다 .

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

이와 같은 작업을 수행하여 호스트 키 검사도 처리 할 수 ​​있습니다.

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

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

You can use the vassal package, which is exactly designed for this.

All you need is to install vassal and do

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

Also, it will save you authenticate credential and don't need to type them again and again.


Calling scp command via subprocess doesn't allow to receive the progress report inside the script. pexpect could be used to extract that info:

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

See python copy file in local network (linux -> linux)


I used sshfs to mount the remote directory via ssh, and shutil to copy the files:

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

Then in python:

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

This method has the advantage that you can stream data over if you are generating data rather than caching locally and sending a single large file.


Try this if you wan't to use SSL certificates:

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!')

a very simple approach is the following:

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

no python library are required (only os) and it works


Using the external resource 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')

Kind of hacky, but the following should work :)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)

참고URL : https://stackoverflow.com/questions/68335/how-to-copy-a-file-to-a-remote-server-in-python-using-scp-or-ssh

반응형