Как scp в Python?

158

Какой самый питонный способ scp файла в Python? Единственный маршрут, который мне известен, это

os.system('scp "%s" "%s:%s"' % (localfile, remotehost, remotefile) )

это взлом, который не работает вне Linux-подобных систем, и которому нужна помощь от модуля Pexpect, чтобы избежать запросов пароля, если у вас уже не установлен SSH без пароля для удаленного хоста.

Я знаю о Twisted conch, но я бы предпочел избегать реализации scp самостоятельно через низкоуровневые ssh-модули.

Мне известен paramikoмодуль Python, который поддерживает SSH и SFTP; но он не поддерживает SCP.

Справочная информация: я подключаюсь к маршрутизатору, который не поддерживает SFTP, но поддерживает SSH / SCP, поэтому SFTP не вариант.

РЕДАКТИРОВАТЬ : Это дубликат Как скопировать файл на удаленный сервер в Python с использованием SCP или SSH? , Тем не менее , этот вопрос не дает конкретного ответа scp, который имеет дело с ключами из Python. Я надеюсь на способ запуска кода вроде

import scp

client = scp.Client(host=host, user=user, keyfile=keyfile)
# or
client = scp.Client(host=host, user=user)
client.use_system_keys()
# or
client = scp.Client(host=host, user=user, password=password)

# and then
client.transfer('/etc/local/filename', '/etc/remote/filename')
Майкл Гундлах
источник

Ответы:

106

Попробуйте модуль Python scp для Paramiko . Это очень просто в использовании. Смотрите следующий пример:

import paramiko
from scp import SCPClient

def createSSHClient(server, port, user, password):
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(server, port, user, password)
    return client

ssh = createSSHClient(server, port, user, password)
scp = SCPClient(ssh.get_transport())

Затем позвоните scp.get()или scp.put()выполните операции SCP.

( Код SCPClient )

Том Шен
источник
3
За исключением того, что модуль на самом деле не использует paramiko - это большой код, который в конце scpконцов фактически вызывает scpкомандную строку, которая работает только на * nix.
Ник Бастин
8
Согласитесь, в исходном коде вы видите удаленный вызов scp -tили scp -f(режимы 'to' и 'from', которые существуют для этой серверной цели). По сути, так работает scp - он опирается на другую копию scp, существующую на сервере. Эта статья объясняет это очень хорошо: blogs.oracle.com/janp/entry/how_the_scp_protocol_works
laher
8
Это решение работало для меня с двумя оговорками: 1. Это операторы импорта, которые я использовал: import paramiko from scp import SCPClient2. Вот пример команды scp.get ():scp.get(r'/nfs_home/appers/xxxx/test2.txt', r'C:\Users\xxxx\Desktop\MR_Test')
Крис Нильсен
Это не только прекрасно работает, но и использует преимущества ключей SSH, если они существуют.
Марсель Уилсон
Обратите внимание, что вы также можете установить эту библиотеку из PyPI: pip install scpв версии 0.10.2 на момент написания этой статьи.
Андрей Б.
15

Возможно, вам будет интересно попробовать Pexpect ( исходный код ). Это позволит вам иметь дело с интерактивными подсказками для вашего пароля.

Вот пример использования (для ftp) с основного сайта:

# This connects to the openbsd ftp site and
# downloads the recursive directory listing.
import pexpect
child = pexpect.spawn ('ftp ftp.openbsd.org')
child.expect ('Name .*: ')
child.sendline ('anonymous')
child.expect ('Password:')
child.sendline ('noah@example.com')
child.expect ('ftp> ')
child.sendline ('cd pub')
child.expect('ftp> ')
child.sendline ('get ls-lR.gz')
child.expect('ftp> ')
child.sendline ('bye')
Пэт Нотц
источник
11

Вы также можете проверить Paramiko . Там нет модуля scp (пока), но он полностью поддерживает sftp.

[EDIT] Извините, пропустил строку, где вы упомянули paramiko. Следующий модуль является просто реализацией протокола scp для paramiko. Если вы не хотите использовать paramiko или conch (единственные реализации ssh, которые я знаю для python), вы можете переделать это, чтобы запустить обычный сеанс ssh с использованием каналов.

scp.py для paramiko

JimB
источник
Вы говорите, что подключенное решение будет безопасно передавать файлы на любой компьютер с sshd, даже если он не работает с sftpd? Это именно то, что я ищу, но я не могу сказать из вашего комментария, оборачивает ли это просто sftp в scp-подобный фасад.
Майкл Гундлах
2
Это позволит передавать файлы на любой компьютер, на котором запущен sshd, в котором есть scp в PATH (scp не является частью спецификации ssh, но он довольно распространен). Это вызывает «scp -t» на сервере и использует протокол scp для передачи файлов, который не имеет ничего общего с sftp.
ДжимБ
1
Обратите внимание, что в качестве модели я использовал реализацию scp в openssh, так что это не гарантирует работу с другими версиями. Некоторые версии sshd также могут использовать протокол scp2, который в основном такой же, как и sftp.
ДжимБ
Не могли бы вы посмотреть этот вопрос: stackoverflow.com/questions/20111242/… Мне интересно, использует ли paramiko подпроцесс или что-то еще, например, сокеты. У меня проблемы с памятью при использовании subprocess.check_output ('ssh blah@blah.com "cat / data / file *") из-за проблем с клонированием / разветвлением, и мне интересно, будут ли у Paramiko такие же проблемы или нет?
Пол
1
@Paul: у paramiko не будет тех же проблем, поскольку он не использует подпроцесс.
ДжимБ
9

Не удалось найти прямой ответ, и этот модуль "scp.Client" не существует. Вместо этого меня это устраивает:

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')
Maviles
источник
6

если вы установите putty на win32, вы получите pscp (putty scp).

так что вы также можете использовать хак os.system на win32.

(и вы можете использовать замазку для управления ключами)


извините, это всего лишь взлом (но вы можете обернуть его в класс Python)

Blauohr
источник
Единственная причина, по которой работает nix, - это то, что у вас есть SCP на пути; как указывает Блауор, это не так сложно исправить. +1
ojrac
6

Вы можете использовать подпроцесс пакета и вызов команды, чтобы использовать команду scp из оболочки.

from subprocess import call

cmd = "scp user1@host1:files user2@host2:files"
call(cmd.split(" "))
user7529863
источник
2
Чем это существенно отличается от базового случая, упомянутого спрашивающим? Да, подпроцесс лучше os.system, но в обоих случаях он не работает за пределами Linux-подобных систем, имеет проблемы с паролем подсказками и т.д.
Фун
5

На сегодняшний день лучшее решение, вероятно, AsyncSSH

https://asyncssh.readthedocs.io/en/latest/#scp-client

async with asyncssh.connect('host.tld') as conn:
    await asyncssh.scp((conn, 'example.txt'), '.', recurse=True)
Лоик
источник
1
Здравствуй. Вы заявляете, что AsyncSSH является лучшим, но могли бы вы сделать заявление или 2, чтобы поддержать это утверждение? Может быть, отличить его от scp (), или как это имеет значение для вашего случая использования. (Это говорит о том, что кода намного меньше - по крайней мере, в вашем примере)
Скотт Прайв
2
@Crossfit_and_Beer привет. Поэтому я сказал «наверное, лучший», я предоставлю суждение любому :) У меня сейчас не так много времени, чтобы сравнить AsyncSSH с другими библиотеками. Но очень быстро: он прост в использовании, он асинхронный, поддерживается и обслуживающий персонал очень приятный и полезный, он довольно полный и очень хорошо задокументирован.
Loïc
5

Посмотрите на fabric.transfer .

from fabric import Connection

with Connection(host="hostname", 
                user="admin", 
                connect_kwargs={"key_filename": "/home/myuser/.ssh/private.key"}
               ) as c:
    c.get('/foo/bar/file.txt', '/tmp/')
user443854
источник
2
Не могли бы Вы уточнить?
Ник Т
4

Прошло довольно много времени с тех пор, как был задан этот вопрос, и в то же время появилась другая библиотека, которая может справиться с этим: вы можете использовать функцию копирования, включенную в библиотеку Plumbum :

import plumbum
r = plumbum.machines.SshMachine("example.net")
   # this will use your ssh config as `ssh` from shell
   # depending on your config, you might also need additional
   # params, eg: `user="username", keyfile=".ssh/some_key"`
fro = plumbum.local.path("some_file")
to = r.path("/path/to/destination/")
plumbum.path.utils.copy(fro, to)
PMOS
источник
Как я могу ввести фразу-пароль для закрытого ключа с Plumbum? p
ekta
@ekta: Вам будет предложено указать это в командной строке. Если вы хотите предоставить его из своего собственного кода, я не думаю, что API plumbum поддерживает это. Но у Plumbum SshMachineесть доступ ssh-agent, поэтому, если вы просто хотите не вводить его каждый раз, это один из способов сделать это. Вы также можете подать запрос на функцию на странице Gumbub Plumbum.
pmos
3
import paramiko

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

client.connect('<IP Address>', username='<User Name>',password='' ,key_filename='<.PEM File path')

#Setup sftp connection and transmit this script 
print ("copying")

sftp = client.open_sftp() 
sftp.put(<Source>, <Destination>)


sftp.close()
Шриккант Роксор
источник
Было бы полезно, если бы вы добавили комментарий к своему ответу, объясняющий, почему ваше решение является хорошим, и помогли бы читателям сравнить его с другими доступными решениями. Просто размещение кода не всегда помогает ученику узнать, как распознать лучшие решения.
Брайан Томпсетт - 莱恩 莱恩
Это SFTP, а не SCP.
Мартин Прикрыл
2

Если вы используете * nix, вы можете использовать sshpass

sshpass -p password scp -o User=username -o StrictHostKeyChecking=no src dst:/path
user178047
источник
1

Хм, возможно, другой вариант будет использовать что-то вроде sshfs (есть sshfs для Mac тоже). После того, как ваш роутер смонтирован, вы можете просто скопировать файлы. Я не уверен, что это работает для вашего конкретного приложения, но это хорошее решение, чтобы держать под рукой.

Пэт Нотц
источник
1

Я недавно создал сценарий копирования SCP на python, который зависит от paramiko. Он включает в себя код для обработки соединений с секретным ключом или агентом ключа SSH с отступлением от аутентификации по паролю.

http://code.activestate.com/recipes/576810-copy-files-over-ssh-using-paramiko/

ccpizza
источник
Спасибо за ссылку и за то, что нашли время опубликовать хороший пример использования paramiko.
Питер М. - выступает за Монику