我的本地计算机上有一个文本文件,它由在cron中运行的每日Python脚本生成。
我想添加一些代码,以便通过SSH将该文件安全地发送到我的服务器。
答案 0 :(得分:134)
要使用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()
(您可能希望处理未知主机,错误,创建必要的目录等等。)
答案 1 :(得分:45)
如果你想要简单的方法,这应该有效。
你首先想要“.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密钥进行身份验证(换句话说,因此您的脚本不会要求密码)。
答案 2 :(得分:28)
你可能会使用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
- 它不会处理路径中的空格。
模块文档有examples of error checking that you may want to perform in conjunction with this operation.
确保您已设置正确的凭据,以便执行unattended, passwordless scp between the machines。有stackoverflow question for this already。
答案 3 :(得分:11)
有几种不同的方法可以解决这个问题:
每种方法都有自己的怪癖。如果要包装“ssh”,“scp”或“rsync”等系统命令,则需要设置SSH密钥以启用无密码登录。您可以使用Paramiko或其他库在脚本中嵌入密码,但您可能会发现缺少文档令人沮丧,特别是如果您不熟悉SSH连接的基础知识(例如 - 密钥交换,代理等)。毫无疑问,SSH密钥几乎总是比这类东西的密码更好。
注意:如果你计划通过SSH传输文件,它很难击败rsync,特别是如果替代方案是普通的旧scp。
我已经将Paramiko用于替换系统调用,但由于其易于使用和即时熟悉,我发现自己被回归到包装的命令。你可能会有所不同。我不久前给了海螺一次,但它并没有吸引我。
如果选择系统调用路径,Python会提供一系列选项,例如os.system或命令/子进程模块。如果使用版本2.4 +,我会使用子进程模块。
答案 4 :(得分:6)
达到了同样的问题,但不是"黑客攻击"或模拟命令行:
找到了这个答案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')
答案 5 :(得分:4)
您可以执行类似的操作来处理主机密钥检查
import os
os.system("sshpass -p password scp -o StrictHostKeyChecking=no local_file_path username@hostname:remote_path")
答案 6 :(得分:3)
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()
答案 7 :(得分:1)
您可以使用专门为此设计的vassal软件包。
您所需要做的就是安装vassal并执行
from vassal.terminal import Terminal
shell = Terminal(["scp username@host:/home/foo.txt foo_local.txt"])
shell.run()
此外,这将节省您的身份验证凭据,而无需一次又一次地键入它们。
答案 8 :(得分:0)
通过子进程调用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})
答案 9 :(得分:0)
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')
答案 10 :(得分:0)
一个非常简单的方法如下:
import os
os.system('sshpass -p "password" scp user@host:/path/to/file ./')
不需要python库(只有操作系统)并且它可以正常工作
答案 11 :(得分:0)
我使用sshfs通过ssh挂载远程目录,使用shutil复制文件:
$ mkdir ~/sshmount
$ sshfs user@remotehost:/path/to/remote/dst ~/sshmount
然后在python:
import shutil
shutil.copy('a.txt', '~/sshmount')
此方法的优点是,如果要生成数据而不是本地缓存并发送单个大文件,则可以流式传输数据。
答案 12 :(得分: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!')
答案 13 :(得分:-2)
有点hacky,但以下应该有效:)
import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)