如何使用 SCP 或 SSH 将文件复制到 Python 中的远程服务器?
-
09-06-2019 - |
题
我的本地计算机上有一个文本文件,该文件是由 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")
您需要预先生成(在源计算机上)并安装(在目标计算机上)ssh 密钥,以便 scp 自动使用您的公共 ssh 密钥进行身份验证(换句话说,这样您的脚本就不会要求输入密码) 。
其他提示
要在 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()
(您可能想要处理未知的主机、错误、创建任何必要的目录等等)。
你可能会使用 子流程模块. 。像这样的东西:
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问题了.
有几种不同的方法可以解决这个问题:
每种方法都有其独特之处。如果您是包装“ SSH”,“ SCP”或“ rsync”之类的系统命令,则需要设置SSH键以启用无密码登录。您可以使用Paramiko或其他一些库将密码嵌入脚本中,但是您可能会发现缺乏文档令人沮丧,尤其是如果您不熟悉SSH连接的基础知识(例如 - 键交换,代理等)。不言而喻,对于这类东西来说,SSH 密钥几乎总是比密码更好的主意。
笔记:如果您计划通过 SSH 传输文件,那么 rsync 很难被击败,特别是如果替代方案是普通的旧 scp。
我使用 Paramiko 的目的是为了替换系统调用,但发现自己又回到了包装命令,因为它们易于使用且易于熟悉。你可能会有所不同。前一段时间我曾浏览过海螺,但它对我没有吸引力。
如果选择系统调用路径,Python 会提供一系列选项,例如 os.system 或commands/subprocess 模块。如果使用 2.4+ 版本,我会使用 subprocess 模块。
遇到了同样的问题,但不是“黑客攻击”或模拟命令行:
找到了这个答案 这里.
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')
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()
您可以使用 vassal 包,它就是专门为此设计的。
您所需要做的就是安装 vassal 并执行以下操作
from vassal.terminal import Terminal
shell = Terminal(["scp username@host:/home/foo.txt foo_local.txt"])
shell.run()
此外,它还可以保存您的身份验证凭据,而无需一次又一次地输入它们。
呼唤 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})
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')
如果您不想使用 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!')
一个非常简单的方法如下:
import os
os.system('sshpass -p "password" scp user@host:/path/to/file ./')
不需要 python 库(仅操作系统)并且它可以工作
有点 hacky,但以下应该有效:)
import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)