简体   繁体   English

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

[英]Is it possible to stream output from a python subprocess to a webpage in real time?

Thanks in advance for any help. 在此先感谢您的帮助。 I am fairly new to python and even newer to html. 我是python的新手,甚至更新的HTML。

I have been trying the last few days to create a web page with buttons to perform tasks on a home server. 过去几天我一直在尝试创建一个带有按钮的网页,以便在家庭服务器上执行任务。

At the moment I have a python script that generates a page with buttons: 目前我有一个python脚本生成一个带按钮的页面:

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

Then a python script which runs said command and outputs to an iframe on the page: 然后是一个python脚本,它运行所述命令并输出到页面上的iframe

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

This does output the entire finished output after the command is finished. 这会在命令完成后输出整个完成的输出。 I have also tried adding the -u option to the python script to run it unbuffered. 我也尝试在python脚本中添加-u选项以使其无缓冲运行。 I have also tried using the Python subprocess as well. 我也尝试过使用Python subprocess If it helps the types of commands I am running are apt-get update , and other Python scripts for moving files and fixing folder permissions. 如果它有助于我运行的命令类型是apt-get update ,以及其他用于移动文件和修复文件夹权限的Python脚本。

And when run from normal Ubuntu server terminal it runs fine and outputs in real time and from my research it should be outputting as the command is run. 当从普通的Ubuntu服务器终端运行时它运行正常并实时输出,并且从我的研究中它应该在命令运行时输出。

Can anyone tell me where I am going wrong? 谁能告诉我哪里出错了? Should I be using a different language to perform this function? 我应该使用其他语言来执行此功能吗?

EDIT Simplified example: 编辑简化示例:

initial page: 初始页面:

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

script that creates button: 创建按钮的脚本:

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

script that should run command: 应该运行命令的脚本:

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

I havent tested the above simplified example so unsure if its functional. 我没有测试上面的简化示例,因此不确定它是否具有功能性。

EDIT: 编辑:

Simplified example should work now. 简化示例现在应该可以使用。

Edit: 编辑:

Imrans code below if I open a browser to the ip:8000 it displays the output just like it was running in a terminal which is Exactly what I want. 下面的Imrans代码,如果我打开浏览器到ip:8000,它会显示输出,就像它在终端中运行一样,这正是我想要的。 Except I am using Apache server for my website and an iframe to display the output. 除了我使用Apache服务器为我的网站和iframe显示输出。 How do I do that with Apache? 我如何使用Apache做到这一点?

edit: 编辑:

I now have the output going to the iframe using Imrans example below but it still seems to buffer for example: 我现在使用下面的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.

Is that just how it is supposed to work? 这是应该如何工作的吗?

EDIT 19-03-2014: 编辑19-03-2014:

any bash / shell command I run using Imrans way seems to output to the iframe in near realtime. 我使用Imrans方式运行的任何bash / shell命令似乎都是近乎实时地输出到iframe。 But if I run any kind of python script through it the output is buffered then sent to the iframe. 但是,如果我通过它运行任何类型的python脚本,输出将被缓冲,然后发送到iframe。

Do I possibly need to PIPE the output of the python script that is run by the script that runs the web server? 我是否可能需要PIPE运行Web服务器的脚本运行的python脚本的输出?

You need to use HTTP chunked transfer encoding to stream unbuffered command line output. 您需要使用HTTP chunked传输编码来传输无缓冲的命令行输出。 CherryPy 's wsgiserver module has built-in support for chunked transfer encoding. CherryPy的wsgiserver模块内置了对分块传输编码的支持。 WSGI applications can be either functions that return list of strings, or generators that produces strings. WSGI应用程序可以是返回字符串列表的函数,也可以是生成字符串的生成器。 If you use a generator as WSGI application, CherryPy will use chunked transfer automatically. 如果您使用生成器作为WSGI应用程序,CherryPy将自动使用分块传输。

Let's assume this is the program, of which the output will be streamed. 我们假设这是程序,其输出将被流式传输。

# slowprint.py

import sys
import time

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

This is our web server. 这是我们的网络服务器。

2014 Version (Older cherrpy Version) 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 Version 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())

Start the server with python webapp.py , then in another terminal make a request with curl , and watch output being printed line by line python webapp.py启动服务器,然后在另一个终端用curl发出请求,并观察输出是否逐行打印

curl 'http://localhost:8000'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM