كيفية نسخ ملف إلى ملقم بعيد في بيثون باستخدام SCP أو SSH ؟

StackOverflow https://stackoverflow.com/questions/68335

  •  09-06-2019
  •  | 
  •  

سؤال

لدي ملف نصي على الجهاز المحلي الذي تم إنشاؤه بواسطة يوميا الثعبان تشغيل البرنامج النصي في كرون.

أود أن أضيف قليلا من التعليمات البرمجية أن يكون هذا الملف إرسالها بشكل آمن إلى الخادم عبر SSH.

هل كانت مفيدة؟

المحلول

إذا كنت ترغب في مقاربة بسيطة, هذا يجب أن تعمل.

سوف تريد ".close()" الملف أولا حتى تعرف أنه مسح القرص من بيثون.

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-keygen سبيل المثال

نصائح أخرى

للقيام بذلك في بيثون (أيلا التفاف scp خلال subprocess.Popen أو ما شابه) مع Paramiko مكتبة, كنت تفعل شيئا من هذا القبيل:

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.شكرا @تشارلز دافي لمدة مشيرا إلى ضعف في بلدي الأصلي الإجابة التي تستخدم سلسلة واحدة الحجة لتحديد scp العملية shell=True - أن لا تحمل بيضاء في المسارات.

وحدة الوثائق أمثلة من تدقيق الأخطاء التي قد تحتاج إلى إجراء بالتزامن مع هذه العملية.

التأكد من أن قمت بإعداد بيانات الاعتماد الصحيحة بحيث يمكنك إجراء غير المراقب ، باسفوردلس scp بين آلات.هناك ستاكوفيرفلوو السؤال هذا بالفعل.

هناك عدة طرق مختلفة لمعالجة المشكلة:

  1. التفاف سطر الأوامر البرامج
  2. استخدام بيثون المكتبة التي توفر SSH قدرات (على سبيل المثال - Paramiko أو الملتوية محارة)

وقد نهج كل المراوغات الخاصة.سوف تحتاج إلى إعداد SSH مفاتيح لتمكين كلمة المرور تسجيل الدخول إذا كنت التفاف نظام الأوامر مثل "ssh", "scp" أو "رسينك." يمكنك تضمين كلمة مرور في برنامج نصي باستخدام Paramiko أو مكتبة ، ولكن قد تجد عدم وجود وثائق محبطة ، خاصة إذا كنت لم تكن مألوفة مع أساسيات اتصال SSH (على سبيل المثال - تبادل المفاتيح, وكلاء, الخ).وربما من نافلة القول أن مفاتيح SSH هي دائما تقريبا فكرة أفضل من كلمات السر لهذا النوع من الاشياء.

ملاحظة:من الصعب الفوز على رسينك إذا كنت تخطط على نقل الملفات عن طريق SSH ، خاصة إذا كان البديل هو سهل القديمة الدائمة المعنية بقانون البراءات.

لقد استعملت Paramiko مع العين نحو استبدال نظام المكالمات ولكن وجدت نفسي رسمها مرة أخرى إلى ملفوفة الأوامر نظرا لسهولة الاستخدام الفوري الألفة.قد تكون مختلفة.أعطى محارة مرة واحدة منذ بعض الوقت ولكن ذلك لا يروق لي.

إذا كان اختيار منظومة مسار الدعوة ، بيثون يقدم مجموعة من الخيارات مثل نظام التشغيل.أو نظام الأوامر/subprocess وحدات.كنت أذهب مع subprocess وحدة في حالة استخدام الإصدار 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')

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

يمكنك استخدام تابعة باقة مصممة بالضبط هذا.

كل ما عليك هو تثبيت تابعة والقيام

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

كما أنه سيوفر لك مصادقة بيانات الاعتماد و لا تحتاج إلى كتابتها مرة أخرى ومرة أخرى.

الدعوة scp القيادة عبر subprocess لا يسمح بتلقي التقرير المرحلي داخل البرنامج النصي. 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')

اعتدت sshfs لتحميل الدليل البعيد عن طريق ssh ، shutil نسخ الملفات:

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

ثم في بايثون:

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

هذا الأسلوب له ميزة أنه يمكنك دفق البيانات أكثر إذا كنت توليد البيانات بدلا من التخزين المؤقت محليا و إرسال ملف كبير واحد.

جرب هذا إذا كنت wan't استخدام شهادات 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 ./')

لا بيثون مكتبة المطلوبة (فقط نظام التشغيل) و يعمل

نوع من hacky ، ولكن بعد أن عمل :)

import os
filePath = "/foo/bar/baz.py"
serverPath = "/blah/boo/boom.py"
os.system("scp "+filePath+" user@myserver.com:"+serverPath)
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top