15

そのため、私が構築しなければならないコンソール上で実行されるPythonプログラムがすでにセットアップされています。Javascriptを使用してアプリケーションのWebGUIインターフェイスを構築します。どのように私は:

a。元のコードに触れることなく、このPythonプログラムの入出力を処理してください。

b。Javascript呼び出しを介してコンソールライン入力をPythonプログラムに送信します。生のHTTPリクエスト/AJAXを調べましたが、Pythonプログラムへの入力としてそれを送信する方法が正確にわかりません。

4

4 に答える 4

6

javascriptから外部Pythonプログラムにデータを透過的に渡すには、WebSocketプロトコルを使用してサーバーとjavascriptを接続し、stdin/stdoutを使用してサーバーから外部プログラムと通信します。

Pythonプログラムの例を次に示しますclient.py

#!/usr/bin/env python
"""Convert stdin to upper case."""
for line in iter(raw_input, 'quit'):
    print line.upper()

hello world websocketの例のコードを使用してサーバーを作成しました。各着信接続で新しいプロセスを作成し、すべての入力データをプロセスのstdinにリダイレクトする方法について回答します。

#!/usr/bin/python
"""WebSocket CLI interface."""
import sys
from twisted.application import strports # pip install twisted
from twisted.application import service
from twisted.internet    import protocol
from twisted.python      import log
from twisted.web.server  import Site
from twisted.web.static  import File

from txws import WebSocketFactory # pip install txws


class Protocol(protocol.Protocol):
    def connectionMade(self):
        from twisted.internet import reactor
        log.msg("launch a new process on each new connection")
        self.pp = ProcessProtocol()
        self.pp.factory = self
        reactor.spawnProcess(self.pp, sys.executable,
                             [sys.executable, '-u', 'client.py'])
    def dataReceived(self, data):
        log.msg("redirect received data to process' stdin: %r" % data)
        self.pp.transport.write(data)
    def connectionLost(self, reason):
        self.pp.transport.loseConnection()

    def _send(self, data):
        self.transport.write(data) # send back


class ProcessProtocol(protocol.ProcessProtocol):
    def connectionMade(self):
        log.msg("connectionMade")
    def outReceived(self, data):
        log.msg("send stdout back %r" % data)
        self._sendback(data)
    def errReceived(self, data):
        log.msg("send stderr back %r" % data)
        self._sendback(data)
    def processExited(self, reason):
        log.msg("processExited")
    def processEnded(self, reason):
        log.msg("processEnded")

    def _sendback(self, data):
        self.factory._send(data)


application = service.Application("ws-cli")

_echofactory = protocol.Factory()
_echofactory.protocol = Protocol
strports.service("tcp:8076:interface=127.0.0.1",
                 WebSocketFactory(_echofactory)).setServiceParent(application)

resource = File('.') # serve current directory INCLUDING *.py files
strports.service("tcp:8080:interface=127.0.0.1",
                 Site(resource)).setServiceParent(application)

Webクライアントの部分sendkeys.html

<!doctype html>
<title>Send keys using websocket and echo the response</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js">
</script>
<script src="sendkeys.js"></script>
<input type=text id=entry value="type something">
<div id=output>Here you should see the typed text in UPPER case</div>

およびsendkeys.js

// send keys to websocket and echo the response
$(document).ready(function() {
    // create websocket
    if (! ("WebSocket" in window)) WebSocket = MozWebSocket; // firefox
    var socket = new WebSocket("ws://localhost:8076");

    // open the socket
    socket.onopen = function(event) {
    socket.send('connected\n');

    // show server response
    socket.onmessage = function(e) {
        $("#output").text(e.data);
    }

    // for each typed key send #entry's text to server
    $("#entry").keyup(function (e) {
        socket.send($("#entry").attr("value")+"\n");
    });
    }
});

それを試すには:

  • この要点をダウンロード
  • インストールtwistedtxws

    $ pip install twisted txws
    
  • 走る:

    $ twistd -ny wscli.py
    
  • 訪問http://localhost:8080/

  • クリックしsendkeys.htmlて何かを入力します

于 2012-07-30T20:58:13.757 に答える
6

a. プログラムの入出力を処理するには: Pexpect。使い方はかなり簡単で、配布されているいくつかの例を読むだけで、基本を理解するのに十分なはずです。

b. Javascript インターフェース:

さて、私は gevent を使用しています。これは組み込みの WSGI サーバーです。( WSGIサーバー別の)とは何かを調べてください)。このプログラムは状態を保持するため、セッション ID を JavaScript クライアントに返し、pexpect セッションをグローバル変数またはその他のコンテナーに保存して、プログラムの入出力を完了できるようにすることで、開いているセッションを管理できることに注意してください。複数の独立した AJAX リクエストにまたがる。ただし、それはそれほど単純ではないので、あなたに任せます。

私の例で行うことは、選択したものをクリックした後、いくつかの POST リクエストを入れることだけです。(一部の変数が設定されていないため、実際には機能しません。設定してください。)

関連する部分は次のとおりです。

<!-- JavaScript -->
<script src="jquery.js"></script>
<script type="text/javascript">
function toPython(usrdata){
    $.ajax({
        url: "http://yoursite.com:8080",
        type: "POST",
        data: { information : "You have a very nice website, sir." , userdata : usrdata },
        dataType: "json",
        success: function(data) {
            <!-- do something here -->
            $('#somediv').html(data);
        }});
$("#someButton").bind('click', toPython(something));
</script>

次に、サーバー:

# Python and Gevent
from gevent.pywsgi import WSGIServer
from gevent import monkey
monkey.patch_all() # makes many blocking calls asynchronous

def application(environ, start_response):
    if environ["REQUEST_METHOD"]!="POST": # your JS uses post, so if it isn't post, it isn't you
        start_response("403 Forbidden", [("Content-Type", "text/html; charset=utf-8")])
        return "403 Forbidden"
    start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
    r = environ["wsgi.input"].read() # get the post data
    return r

address = "youraddresshere", 8080
server = WSGIServer(address, application)
server.backlog = 256
server.serve_forever()

プログラムがオブジェクト指向の場合、これを統合するのはかなり簡単です。編集: オブジェクト指向である必要はありません。そして、いくつかの Pexpect コードを含めました

global d
d = someClass()
def application(environ, start_response):
    # get the instruction
    password = somethingfromwsgi # read the tutorials on WSGI to get the post stuff
    # figure out WHAT to do
    global d
    success = d.doSomething()
    # or success = funccall()
    prog = pexpect.spawn('python someprogram.py')
    prog.expect("Password: ")
    prog.sendline(password)
    i = prog.expect(["OK","not OK", "error"])
    if i==0:
        start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
        return "Success"
    elif i==1:
        start_response("500 Internal Server Error", [("Content-Type", "text/html; charset=utf-8")])
        return "Failure"
    elif i==2:
        start_response("500 Internal Server Error", [("Content-Type", "text/html; charset=utf-8")])
        return "Error"

私が提案する別のオプションは、Nginx + uWSGI です。もしよろしければ、その例もいくつか挙げることができます。これにより、Web サーバーをセットアップに組み込む利点が得られます。

于 2012-07-30T19:42:50.223 に答える
1

json モジュールと一緒にFlaskが必要になるでしょう。

Djangoも別のオプションですが、ニーズに対して高レベルすぎる可能性があります。

于 2012-07-30T18:13:05.393 に答える
1

これは、ラッピングするアプリケーションの種類と、GUI オプションがアプリケーション コマンドにどのように変換されるかによって異なります。ただし、ここには 2 つの目標があります。

  1. プログラムの出力を読み取って入力できるようにするラッパーを作成します。

  2. GUIイベントを受信し、それらをコマンドに変換して「ラッパー」に渡すWebサーバーを作成する

私はあなたがする必要があるようなことをしました。

  1. 基本的に、ソケット ストリームを目立たないコマンドに変換する必要があります。このためのデファクト ツールはexpectであり、そのラッパーのいずれかです (私はpexpect、Python ラッパーを使用しており、良い経験がありました)。

  2. この部分は単純ではないかもしれません。問題は、基礎となるプログラムが永続的に実行されていることです。そのため、リクエスト全体でプログラムについて知るために、Web サーバーはステートフルである必要があります。もう 1 つのオプションは、Web サーバーが単純にプロセスに再接続してコマンドを発行し、stdout ストリームで検出されたときに応答を返すことですが、プロセスの速度によっては応答時間が長くなる可能性があります。プログラムは。また、AJAX リクエストが非同期であるのに対し、基になるプログラムは同期であるという不一致もあります。そうです、これは非常に複雑になる可能性があります。それは本当にあなたのプログラムに依存します。プログラムと GUI がどのようなものかについて詳細を追加していただけると助かります。

于 2012-07-30T18:51:38.193 に答える