是否可以实时将python子流程的输出流式传输到网页?

时间:2014-03-15 12:38:28

标签: python html linux web cgi

提前感谢您的帮助。我对python很新,甚至比html更新。

过去几天我一直在尝试创建一个带有按钮的网页,以便在家庭服务器上执行任务。

目前我有一个python脚本生成一个带按钮的页面:

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

然后是一个python脚本,它运行所述命令并输出到页面上的iframe

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

在命令完成后,它会输出整个完成的输出。我还尝试将-u选项添加到python脚本中以使其无缓冲运行。我也尝试过使用Python subprocess。如果它有助于我运行的命令类型apt-get update,以及其他用于移动文件和修复文件夹权限的Python脚本。

当从普通的Ubuntu服务器终端运行时,它运行正常并实时输出,并且从我的研究中它应该在命令运行时输出。

谁能告诉我哪里出错了?我应该使用其他语言来执行此功能吗?

编辑简化示例:

初始页面:

#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>

创建按钮的脚本:

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
应该运行命令的

脚本:

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

我没有测试上面的简化示例,因此不确定它的功能是否正确。

编辑:

简化示例现在应该可以使用。

编辑:

如果我打开一个浏览器到ip:8000,它会显示输出,就像它在终端中运行一样,这正是我想要的。除了我使用Apache服务器为我的网站和iframe显示输出。我如何用Apache做到这一点?

编辑:

我现在使用下面的Imrans示例将输出转到iframe,但它似乎仍然缓冲,例如:

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.

它应该如何运作?

编辑19-03-2014:

我使用Imrans方式运行的任何bash / shell命令似乎都是近乎实时地输出到iframe。但是,如果我通过它运行任何类型的python脚本,输出将被缓冲,然后发送到iframe。

我是否可能需要PIPE运行Web服务器的脚本运行的python脚本的输出?

1 个答案:

答案 0 :(得分:6)

您需要使用HTTP chunked transfer encoding来传输无缓冲的命令行输出。 CherryPy的wsgiserver模块内置了对分块传输编码的支持。 WSGI应用程序可以是返回字符串列表的函数,也可以是生成字符串的生成器。如果您使用生成器作为WSGI应用程序,CherryPy将自动使用分块传输。

我们假设这是一个程序,其输出将被流式传输。

# slowprint.py

import sys
import time

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

这是我们的网络服务器。

2014年版(旧版本)

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

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

使用python webapp.py启动服务器,然后在另一个终端中使用curl发出请求,并观察逐行打印的输出

curl 'http://localhost:8000'