كيفية نسخ ملف إلى ملقم بعيد في بيثون باستخدام SCP أو SSH ؟
-
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 يحصل تلقائيا مع مصادقة المفتاح العمومي الخاص بك سة (وبعبارة أخرى ، لذلك السيناريو الخاص بك لا يسأل عن كلمة المرور).
نصائح أخرى
للقيام بذلك في بيثون (أيلا التفاف 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 بين آلات.هناك ستاكوفيرفلوو السؤال هذا بالفعل.
هناك عدة طرق مختلفة لمعالجة المشكلة:
- التفاف سطر الأوامر البرامج
- استخدام بيثون المكتبة التي توفر 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)