Apakah mungkin untuk mengalirkan keluaran dari subproses python ke halaman web secara real time?

Terima kasih sebelumnya atas bantuan apa pun. Saya cukup baru mengenal python dan bahkan lebih baru mengenal html.

Saya telah mencoba beberapa hari terakhir untuk membuat halaman web dengan tombol untuk melakukan tugas di server rumah.

Saat ini saya memiliki skrip python yang menghasilkan halaman dengan tombol:

(See the simplified example below. removed code to clean up post)

Kemudian skrip python yang menjalankan perintah tersebut dan menghasilkan iframe di halaman:

(See the simplified example below. removed code to clean up post)

Ini menampilkan seluruh keluaran yang telah selesai setelah perintah selesai. Saya juga telah mencoba menambahkan opsi -u ke skrip python untuk menjalankannya tanpa buffer. Saya juga sudah mencoba menggunakan Python subprocess juga. Jika itu membantu, jenis perintah yang saya jalankan adalah apt-get update, dan skrip Python lainnya untuk memindahkan file dan memperbaiki izin folder.

Dan ketika dijalankan dari terminal server Ubuntu normal, ia berjalan dengan baik dan menghasilkan keluaran secara real time dan dari penelitian saya, ia seharusnya menghasilkan keluaran saat perintah dijalankan.

Adakah yang bisa memberi tahu saya di mana kesalahan saya? Haruskah saya menggunakan bahasa lain untuk menjalankan fungsi ini?

EDIT Contoh yang disederhanakan:

halaman awal:

#runcmd.html

<head>
    <title>Admin Tasks</title>
</head>

<center>
<iframe src="/scripts/python/test/createbutton.py" width="650" height="800" frameborder="0" ALLOWTRANSPARENCY="true"></iframe>
<iframe width="650" height="800" frameborder="0" ALLOWTRANSPARENCY="true" name="display"></iframe> 
</center>

skrip yang membuat tombol:

cmd_page = '<form action="/scripts/python/test/runcmd.py" method="post" target="display" >' + '<label for="run_update">run updates</label><br>' + '<input align="Left" type="submit" value="runupdate" name="update" title="run_update">' + "</form><br>" + "\n"

print ("Content-type: text/html")
print ''
print cmd_page

skrip yang harus menjalankan perintah:

# runcmd.py:

import os 
import pexpect
import cgi
import cgitb
import sys 

cgitb.enable()

fs = cgi.FieldStorage()

sc_command = fs.getvalue("update")

if sc_command == "runupdate":
    cmd = "/usr/bin/sudo apt-get update"

pd = pexpect.spawn(cmd, timeout=None, logfile=sys.stdout)

print ("Content-type: text/html")
print ''
print "<pre>"

line = pd.readline()  
while line:
    line = pd.readline()

Saya belum menguji contoh sederhana di atas jadi tidak yakin apakah ini berfungsi.

Sunting:

Contoh sederhana seharusnya bisa digunakan sekarang.

Sunting:

Kode Imrans di bawah ini jika saya membuka browser ke ip:8000 itu akan menampilkan output seperti sedang berjalan di terminal yang persis seperti yang saya inginkan. Kecuali saya menggunakan server Apache untuk situs web saya dan iframe untuk menampilkan hasilnya. Bagaimana cara melakukannya dengan Apache?

sunting:

Saya sekarang memiliki output yang masuk ke iframe menggunakan contoh Imrans di bawah ini tetapi sepertinya masih buffer misalnya:

If I have it (the script through the web server using curl ip:8000) run apt-get update in terminal it runs fine but when outputting to the web page it seems to buffer a couple of lines => output => buffer => ouput till the command is done.

But running other python scripts the same way buffer then output everything at once even with the -u flag. While again in terminal running curl ip:800 outputs like normal.

Apakah memang seperti itu cara kerjanya?

EDIT 19-03-2014:

setiap perintah bash/shell yang saya jalankan menggunakan cara Imrans tampaknya ditampilkan ke iframe hampir secara realtime. Tetapi jika saya menjalankan skrip python apa pun melaluinya, outputnya di-buffer kemudian dikirim ke iframe.

Apakah saya mungkin perlu PIPE output dari skrip python yang dijalankan oleh skrip yang menjalankan server web?


person ButtzyB    schedule 15.03.2014    source sumber
comment
Ya. Berikut contoh kode   -  person jfs    schedule 15.03.2014
comment
Kelihatannya membingungkan. Bagi saya sepertinya itu mengirimkan perintah ke terminal dan menampilkannya di sana?. yang saya inginkan adalah menampilkan output perintah di iframe seperti yang muncul di terminal. @J.F.Sebastian   -  person ButtzyB    schedule 15.03.2014
comment
kasus Anda bahkan lebih sederhana daripada contoh kode di mana pesan dikirim bolak-balik antara kode javascript di browser dan subproses di server. Untuk menjawab pertanyaan Anda: stdout dari subproses dikirim ke browser.   -  person jfs    schedule 15.03.2014
comment
Ya dengan kode yang saya miliki setelah perintah selesai, iframe diisi dengan seluruh output dari perintah. yang saya inginkan adalah mengisinya dengan setiap baris seperti yang Anda lihat saat perintah dijalankan di terminal. Tapi saya tidak tahu caranya. @J.F.Sebastian   -  person ButtzyB    schedule 15.03.2014
comment
contoh kode yang saya berikan mengirimkan output segera setelah subproses mengosongkan buffer stdout internalnya (contoh program python menggunakan -u flag, jadi tidak ada buffer; setiap byte segera dikirim)   -  person jfs    schedule 15.03.2014
comment
Tapi bukankah contoh itu membuat server web baru? Saya sudah menjalankan situs saya menggunakan server Apache jadi bagaimana saya melakukannya dengan Apache daripada menjalankan server terpisah? Seperti masuk ke halaman di situs server Apache saya =› klik tombol (untuk menjalankan perintah) =› keluaran ke iframe saya. @J.F.Sebastian   -  person ButtzyB    schedule 15.03.2014
comment
Anda dapat mencoba menjalankan aplikasi wsgi dari jawaban @Imran menggunakan mod_wsgi di Apache. Atau coba skrip cgi ini   -  person jfs    schedule 16.03.2014
comment
skrip kosong. @J.F.Sebastian   -  person ButtzyB    schedule 16.03.2014
comment
coba ini   -  person jfs    schedule 16.03.2014
comment
Sudahlah kesalahan format @J.F.Sebastian   -  person ButtzyB    schedule 17.03.2014
comment
tidak tidak keluar ke browser web sama sekali @J.F.Sebastian   -  person ButtzyB    schedule 17.03.2014
comment
Apa yang terjadi jika Anda menjalankan curl http://youhost.com/path/to/script.py?   -  person jfs    schedule 17.03.2014
comment
menggunakan curl dari terminal berfungsi dengan baik. @J.F.Sebastian   -  person ButtzyB    schedule 17.03.2014
comment
periksa apakah responsnya adalah HTTP/1.1 dan bukan HTTP/1.0   -  person jfs    schedule 17.03.2014
comment
ya responsnya sepertinya benar POST /scripts/python/runcmds.py HTTP/1.1 200 489 itulah yang muncul di log akses. @J.F.Sebastian   -  person ButtzyB    schedule 17.03.2014
comment
POST adalah permintaan. Lihatlah responnya. Mulai sniffer jaringan dan cari HTTP/1.1 200 OK (baris pertama dalam respons dari server)   -  person jfs    schedule 17.03.2014
comment
Saya membersihkan log dan mencoba lagi dan tidak ada hasil setelah mengklik tombol, hanya posting dan halaman menunggu skrip selesai tetapi tidak ada output ke iframe. @J.F.Sebastian   -  person ButtzyB    schedule 17.03.2014
comment
coba: curl -v http://youhost.com/path/to/script.py |& grep 'HTTP/' Apa yang Anda lihat HTTP/1.0 atau HTTP/1.1 200 OK?   -  person jfs    schedule 26.04.2014
comment
Saya telah berhasil membuatnya berfungsi sejak pesan terakhir saya. Satu-satunya masalah yang saya alami sekarang adalah menunggu buffer python terisi sebelum mulai mencetak. Perintah Bash tampaknya dikeluarkan hampir segera ke iframe tetapi skrip python lain yang dijalankan melaluinya tampaknya melakukan buffer terlebih dahulu kemudian mengeluarkannya. @J.F.Sebastian   -  person ButtzyB    schedule 27.04.2014
comment
jika Anda merasa telah menemukan solusinya; Anda dapat mempostingnya sebagai jawaban Anda sendiri. Untuk memperbaiki masalah buffering, sudahkah Anda mencoba python -u? Berikut adalah beberapa solusi untuk masalah buffering blok untuk stdout subproses.   -  person jfs    schedule 27.04.2014


Jawaban (1)


Anda perlu menggunakan HTTP pengkodean transfer terpotong untuk melakukan streaming keluaran baris perintah tanpa buffer. Modul wsgiserver CherryPy memiliki dukungan bawaan untuk pengkodean transfer terpotong. Aplikasi WSGI dapat berupa fungsi yang mengembalikan daftar string, atau generator yang menghasilkan string. Jika Anda menggunakan generator sebagai aplikasi WSGI, CherryPy akan menggunakan transfer terpotong secara otomatis.

Anggaplah ini adalah program yang keluarannya akan dialirkan.

# slowprint.py

import sys
import time

for i in xrange(5):
    print i
    sys.stdout.flush()
    time.sleep(1)

Ini adalah server web kami.

Versi 2014 (Versi cherrpy yang lebih lama)

# webserver.py

import subprocess
from cherrypy import wsgiserver


def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    proc = subprocess.Popen(['python', 'slowprint.py'], stdout=subprocess.PIPE)

    line = proc.stdout.readline()
    while line:
        yield line
        line = proc.stdout.readline()


server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8000), application)
server.start()

Versi 2018

#!/usr/bin/env python2
# webserver.py
import subprocess
import cherrypy

class Root(object):
    def index(self):
        def content():
            proc = subprocess.Popen(['python', 'slowprint.py'], stdout=subprocess.PIPE)
            line = proc.stdout.readline()
            while line:
                yield line
                line = proc.stdout.readline()
        return content()
    index.exposed = True
    index._cp_config = {'response.stream': True}

cherrypy.quickstart(Root())

Mulai server dengan python webapp.py, lalu di terminal lain buat permintaan dengan curl, dan lihat output dicetak baris demi baris

curl 'http://localhost:8000'
person Imran    schedule 15.03.2014
comment
Maaf seperti yang saya katakan, saya cukup baru dalam hal ini, jadi terbukalah dengan saya. Saya menggunakan Apache sebagai server web saya di server ubuntu 13.10. Dengan menggunakan kode Anda atau yang serupa, apakah itu akan menghasilkan iframe pada halaman yang sama dengan tombol? seperti pada tombol klik =› menjalankan subproses di server =› iframe diisi dengan output saat itu terjadi? @Imran - person ButtzyB; 15.03.2014
comment
Anda tidak harus menjalankan Apache, skrip ini sendiri adalah server web. Jika Anda menjalankan ini, Anda dapat mengatur iframe['src'] = 'localhost:8000' dengan perintah yang Anda inginkan untuk mengeksekusi sebagai string kueri, dan mengurai string kueri dari 'lingkungan' dalam kode aplikasi. - person Imran; 15.03.2014
comment
Hanya untuk memperjelas saya menjalankan Apache karena saya meng-hosting situs web dasar di server. Saya mencoba memiliki halaman dengan beberapa tombol yang menjalankan tugas tertentu (seperti apt-get update) dan menampilkan output ke iframe saat itu terjadi baris demi baris. Daripada setelah perintah selesai. Apakah ada cara saya bisa melakukan ini dengan Apache? @Imran - person ButtzyB; 15.03.2014
comment
Ketika saya menjalankan contoh Anda di terminal, saya mendapatkan keluaran seolah-olah saya telah mengetikkan perintah ke terminal. Saya ingin keluaran itu muncul di iframe seperti perintah yang dijalankan di terminal. Maaf jika saya terdengar membingungkan. @Imran - person ButtzyB; 15.03.2014
comment
baru saja mencoba contoh Anda dan membuka browser ke ip:8000 dan itu menampilkan persis seperti yang saya inginkan, Luar Biasa. sekarang bagaimana cara melakukannya dengan Apache dan iframe? Terima kasih. @Imran - person ButtzyB; 15.03.2014
comment
Apache tidak terkait dalam hal ini, iframe memungkinkan Anda menyematkan sumber eksternal di halaman web, jadi Anda cukup memasukkan iframe ke dalam html Anda. (Ketahuilah bahwa beberapa keamanan Lintas Situs mungkin memblokirnya) - person Jonathan; 30.05.2017
comment
Saya mencoba menerapkan hal yang sama. Saya menggunakan formulir kode versi 2018 di atas tetapi tidak mencetak output baris demi baris. Saya mendapatkan hasilnya sekaligus (setelah 5 detik). Apakah ada yang berubah? @Imran - person Hemabh; 27.08.2020