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

在此先感谢您的帮助.我是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)

这会在命令完成后输出整个完成的输出.我也尝试在python脚本中添加-u选项以使其无缓冲运行.我也尝试过使用Python子进程.如果它有助于我运行的命令类型是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()

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

编辑:

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

编辑:

下面的Imrans代码,如果我打开浏览器到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脚本的输出?

解决方法:

您需要使用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'
上一篇:如何使用PHP 5.5.14在Yosemite上启用fastcgi


下一篇:php运行模式汇总