2012-06-05 52 views
10

好吧,我設法讓它工作得如何我想要的(儘管有些/大多數人可能會不同意這種方法)。我按照下面的建議使用了Flask。可能被認爲是「錯誤」的部分是404檢查循環。這是不適當的設計,並導致一些瀏覽器的「卡住腳本」錯誤,如果它繼續太久。但是,我想運行的腳本不會持續足夠長的時間,因爲這是一個問題。創建一個執行python腳本的超鏈接(或按鈕),然後在腳本完成時重定向

感謝您的幫助,請讓我知道如果您有任何其他建議。

瓶應用:

import threading 
import subprocess 
import os 
import sys 
from flask import Flask 
from flask import render_template, abort 
app = Flask(__name__) 
app.debug = True 

def run_script(): 
    theproc = subprocess.Popen([sys.executable, "run_me.py"]) 
    theproc.communicate() 

@app.route('/') 
def index(): 
    return render_template('index.html') 

@app.route('/generate') 
def generate(): 
    threading.Thread(target=lambda: run_script()).start() 
    return render_template('processing.html') 

@app.route('/is_done') 
def is_done(): 
    hfile = "templates\\itworked.html" 
    if os.path.isfile(hfile): 
     return render_template('itworked.html') 
    else: 
     abort(404) 

if __name__ == "__main__": 
    app.run() 

processing.html:

<!DOCTYPE html> 
<html> 
<head> 
    <script src="/static/jquery.min.js"></script> 
</head> 

<body> 
<p>Processing...</p> 
<script> 
    setInterval(function() 
    { 
     var http = new XMLHttpRequest(); 
     http.open('HEAD', "is_done", false); 
     http.send(); 
     if (http.status==200) 
      window.location.replace("is_done"); 
    },2000); 
</script> 
</body> 
</html> 

原題:

我是一個初級/中級Python程序員和一個開始web開發人員,所以請溫柔。 我想要什麼: 用戶點擊一個超鏈接,並被帶到一個類似「處理...」的中間網頁。在後臺(在服務器上),此鏈接觸發一個處理文件並創建新網頁的python腳本。完成腳本後,用戶將重定向到新創建的頁面。 我有: 我有一個腳本來完成處理並吐出一個新頁面。我沒有想到的是如何觸發python腳本,然後在腳本完成時觸發重定向。我看過像django和cgi腳本這樣的web框架。但我還沒有發現任何我覺得符合法案的東西。我很可能錯過了一些完全明顯的東西,所以我非常感謝任何幫助。 謝謝。

+0

您所描述的內容需要將全新的Web內容寫入磁盤上的文件,然後進行提供。這很不尋常。標準流程更像是:1.點擊按鈕並觸發來自服務器的頁面請求。 2.請求頁面的PHP後端處理請求中的querystring/form/cookie信息,並在請求的頁面中生成動態內容。 3.頁面發送給用戶。你確定這不是你想要的嗎? – jatrim

+0

我很確定。我知道我在嘗試的是不尋常的。這就是爲什麼我需要幫助。 :) – bem3ry

+0

你的暫停功能真的非常糟糕和有害,並浪費CPU週期大的時間。改爲使用'setTimeout'。此外,您的版本僅適用於生成一個文件,並且不會同時訪問您的網頁的多個人員,他們可能會嘗試同時生成該文件。也許在運行腳本之前檢查文件是否已經存在。 – mensi

回答

6

一個簡單的方法來解決這個問題的辦法是使用一個簡單的web框架,像瓶打造的Web部件超濾系統。在魔術鏈接的請求處理程序中,您需要生成腳本並跟蹤它。查看腳本是否完成並將其轉發給用戶的一個簡單方法是定期發送ajax請求以檢查完成情況。

因此,例如瓶的網站可能看起來像:

import threading 
import subprocess 
import uuid 
from flask import Flask 
from flask import render_template, url_for, abort, jsonify, request 
app = Flask(__name__) 

background_scripts = {} 

def run_script(id): 
    subprocess.call(["/path/to/yourscript.py", "argument1", "argument2"]) 
    background_scripts[id] = True 

@app.route('/') 
def index(): 
    return render_template('index.html') 

@app.route('/generate') 
def generate(): 
    id = str(uuid.uuid4()) 
    background_scripts[id] = False 
    threading.Thread(target=lambda: run_script(id)).start() 
    return render_template('processing.html', id=id) 

@app.route('/is_done') 
def is_done(): 
    id = request.args.get('id', None) 
    if id not in background_scripts: 
     abort(404) 
    return jsonify(done=background_scripts[id]) 

而且index.html

<a href="{{ url_for('generate') }}">click me</a> 

而且processing.html

<html> 
<head> 
<script src="/static/jquery.js"></script> 
<script> 
    function ajaxCallback(data) { 
     if (data.done) 
      window.location.replace("http://YOUR_GENERATED_PAGE_URL"); 
     else 
      window.setTimeout(function() { 
       $.getJSON('{{ url_for('is_done') }}', {id: {{ id }} }, ajaxCallback); 
      }, 3000); 
    } 
    $(document).ready(function(){ 
     ajaxCallback({done=false}); 
    }); 
</script> 
</head> 
<body> 
    Processing... 
</body></html> 

這是目前所有未經測試的代碼,但我希望你對如何解決這個問題有一些想法米同時請記住,只有當您從一個進程提供頁面時,這纔會起作用,因此如果您設置了Apache和mod_wsgi,請確保進程組中只有一個進程。

如果您需要更復雜的解決方案,您可能需要查看消息隊列等。

+0

好的...事情看起來好多了。 :)我沒有得到的唯一工作是腳本完成的重定向。它似乎永遠不會重定向。 – bem3ry

+0

@ user1438165您可能想要編輯您的問題以顯示您當前擁有的內容以及問題的具體位置。 – mensi

+0

請參閱上面的內容,使用我使用的方法進行更新。你的代碼幫助了很多。謝謝。 :) – bem3ry

0

兩個simplish的方式來做到這一點:

1)使用AJAX來輪詢服務器。每10秒檢查一次完成情況,或者任何你認爲合適的時間間隔。例如。當腳本正在處理時,它會寫入文件或數據庫,無論它指示完成百分比以及以某種方式識別該進程(如果您有多個腳本同時運行,則需要知道哪一個是Bob的哪一個是Suzy的)。

2)禁用輸出緩衝並將輸出流傳輸到客戶端。這比第一個選項簡單。基本上,運行腳本,並在處理時可以輸出JavaScript代碼來說,更新進度指示器。您需要禁用輸出緩衝,或者手動刷新緩衝區,否則您的客戶端可能不會立即收到輸出結果(指標更新只有在客戶端達到100%時纔會顯示)。谷歌如何在任何設置(例如PHP,Django)上運行它。

0

你想要什麼是可能的,但它確實是關於3個問題。

第一個問題是,你如何從PHP創建一個新文件。我無法真正回答這個問題。你需要做什麼,可能取決於你想創建什麼樣的文件以及爲什麼。

第二個問題是,您如何讓用戶知道這種情況正在發生,以及第三個問題是您如何重定向到新頁面。我個人認爲,獲得勝利的最短路線可能是讓你的客戶端JavaScript向創建新內容的服務器頁面或CGI模塊發出AJAX請求。

  1. 點擊按鈕,向PHP頁面發出ajax請求,生成新的內容頁面。
  2. 顯示您的繁忙指標。
  3. 讓請求的頁面返回新頁面的URL作爲其內容。
  4. 當請求完成通過JavaScript重定向到返回的URL。

作爲web開發新手,最簡單的事情可能是查看jQuery,它是AJAX功能。這裏的包裝使得上述操作變得非常簡單。當然,你也可以用其他主要的javascript框架或直接的javascript來做同樣的事情。

參考:

+1

也許我不理解。 PHP頁面不會生成我的新內容。 Python確實如此。也許我錯過了什麼? – bem3ry

+0

我的大腦用PHP切換python。別問 - 抱歉。無論如何,我的經驗是像PHP或asp.net這樣的後端服務器語言。在這種情況下,服務器腳本可以調用您的phython代碼來創建頁面。但取決於你的網絡服務器,你也應該能夠直接運行Python作爲一個從你的網頁調用的CGI模塊。結果應該大致相同。 – jatrim

2

這可能是太重型你的解決方案,但假設你不能用「創建服務器上的文件」部分做掉,這被認爲是Web開發的「最佳實踐」的解決方案:

使用像Flask或Django這樣的Web框架來提供頁面。當用戶請求通過請求啓動作業(最好是POST請求,因爲GET請求不應導致明顯的副作用)時,框架將向Celery等延遲任務系統發送消息。然後,用戶會看到一個頁面,表明該作業已提交。

此時,您可以使用ajax輪詢服務器並查看作業何時完成,但通常您不希望這是您查看作業是否完成的唯一方法。如果連接由於任何原因而中斷,例如,如果用戶錯誤地關閉瀏覽器或標籤(非常常見),則努力將被浪費,並且用戶將不得不重新開始該過程。如果可能的話,你應該有一個與用戶溝通的備用方式;這可能是網站上其他地方出現的一條閃光消息,一個自動完成的「作業完成」電子郵件,一個顯示最近完成的作業的主頁上的一個框,等等。這取決於用戶是否已登錄以及如何登錄長時間工作需要/是否有創建文件之外的副作用。

最後,您可以允許用戶通過該用戶的工作結果唯一的URL訪問該頁面。請務必通知用戶該URL是否無限期有效,例如,如果該文件將在計時器上被刪除。

相關問題