2012-06-05 40 views
10

Va bene, sono riuscito a farlo funzionare come voglio (anche se alcuni/molti potrebbero non essere d'accordo con il metodo). Ho usato Flask come raccomandato di seguito. La parte che potrebbe essere considerata "errata" è il ciclo di verifica 404. Non è una progettazione corretta e genera un errore di "script bloccato" in alcuni browser se continua per troppo tempo. Tuttavia, lo script che voglio eseguire non dura abbastanza a lungo per essere un problema.Creare un collegamento ipertestuale (o pulsante) che esegue uno script python e quindi reindirizza al termine dello script

Grazie per l'aiuto e per favore fatemi sapere se avete altri suggerimenti.

Flask App:

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> 

domanda originale:

io sono un principiante/programmatore Python intermedio e uno sviluppatore web che inizia quindi per favore essere gentile . Cosa voglio: Un utente fa clic su un collegamento ipertestuale e viene indirizzato a una pagina Web intermedia che dice qualcosa come "Elaborazione in corso ...". In background (sul server) questo link attiva uno script python che elabora un file e crea una nuova pagina web. Al termine dello script, l'utente viene reindirizzato alla pagina appena creata. Cosa ho: Ho uno script che esegue l'elaborazione e sputa una nuova pagina. Quello che non ho capito è come attivare lo script Python e quindi attivare il reindirizzamento al completamento dello script. Ho esaminato framework web come django e scripting cgi. Ma non ho trovato nulla che ritenga adatto al conto. È molto probabile che mi manchi qualcosa di completamente ovvio, quindi apprezzerei davvero qualsiasi aiuto. Grazie.

+0

Quello che stai descrivendo richiede la scrittura di contenuti web nuovi di zecca su un file su disco e poi servirlo. Questo è abbastanza insolito. Il flusso standard sarebbe più simile a: 1. fare clic sul pulsante e avviare la richiesta di pagina dal server. 2. il backend PHP per la pagina richiesta elabora le informazioni querystring/form/cookie nella richiesta e genera contenuto dinamico nella pagina richiesta. 3. la pagina viene inviata all'utente. Sei sicuro che non è quello che vuoi? – jatrim

+0

Sono sicuro. So che quello che sto tentando è insolito. Ecco perché ho bisogno di aiuto. :) – bem3ry

+0

La tua funzione di pausa è davvero pessima e dannosa e spreca grandi cicli di CPU. Usa invece 'setTimeout'. Inoltre, la tua versione funziona solo per generare un file e non tiene conto di più persone che visitano la tua pagina allo stesso tempo, potrebbero provare a generare il file contemporaneamente. Forse controlla se il file esiste già prima di eseguire lo script. – mensi

risposta

6

Un modo semplice per affrontare questo problema sarebbe quella di utilizzare un framework web semplice come Flask per costruire la parte web uf sistema. Nel gestore della richiesta per il tuo link magico, dovrai generare il tuo script e tenerne traccia. Un modo semplice per vedere se il tuo script è fatto e inoltrarlo al tuo utente è di inviare periodicamente una richiesta Ajax per verificare il completamento.

Così, per esempio il sito Flask potrebbe apparire come:

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

E il index.html:

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

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

Questo è tutto il codice non testato in questo momento ma spero che tu abbia qualche idea su come affrontare questo problema m. Inoltre, tieni presente che ciò funzionerà solo se pubblichi la pagina da un processo, quindi se imposti Apache e mod_wsgi, assicurati che ci sia un solo processo nel gruppo di processi.

Se è necessaria una soluzione più complessa, è possibile controllare le code dei messaggi e simili.

+0

Ok ... le cose stanno andando molto meglio con questo. :) L'unica cosa che non ho ancora funzionato è un reindirizzamento sul completamento dello script. Non sembra mai reindirizzare. – bem3ry

+0

@ user1438165 potresti voler modificare la tua domanda per mostrare cosa hai attualmente e dove si trova esattamente il problema. – mensi

+0

Vedi sopra, aggiornato con il metodo che ho usato. Il tuo codice ha aiutato molto. Grazie. :) – bem3ry

0

Due modi simplish per farlo:

1) Utilizzare ajax interroga il server. Controlla il completamento ogni 10 secondi o qualsiasi intervallo tu ritenga appropriato. Per esempio. mentre lo script è in fase di elaborazione, scrive su un file, o database, qualunque sia per indicare la percentuale di completamento e identifica il processo in qualche modo (se hai più script in esecuzione contemporaneamente vorrai sapere qual è Bob e quale è di Suzy).

2) Disabilitare il buffer di output e trasmettere l'output al client. Questo è più semplice della prima opzione. Fondamentalmente, esegui lo script e mentre viene elaborato puoi generare un codice javascript per dire, aggiornare un indicatore di progresso. È necessario disabilitare il buffering dell'output o svuotare manualmente il buffer altrimenti il ​​client potrebbe non ricevere immediatamente l'output (l'aggiornamento dell'indicatore potrebbe essere visibile al client solo quando raggiunge il 100%). Google come farlo su qualsiasi configurazione (ad es. PHP, Django) stai eseguendo.

0

Quello che vuoi è possibile, ma sono davvero circa 3 problemi.

La prima domanda è, come si crea un nuovo file da PHP. Non posso davvero rispondere a questo. Quello che devi fare, probabilmente dipende dal tipo di file che stai cercando di creare e perché.

La seconda domanda è: come fai sapere all'utente che questo sta accadendo, e il terzo è come reindirizzare alla nuova pagina.

Personalmente, penso che il percorso più breve verso la vittoria, è probabilmente quello di avere il tuo javascript lato client fare una richiesta AJAX alla pagina del server o modulo CGI che crea il tuo nuovo contenuto.

  1. Al clic del pulsante, effettuare una richiesta Ajax alla pagina PHP che genera la nuova pagina di contenuto.
  2. Presenta l'indicatore di occupato.
  3. La pagina richiesta restituisce l'URL della nuova pagina come suo contenuto.
  4. Quando la richiesta completa il reindirizzamento all'URL restituito tramite javascript.

Come qualcuno nuovo per lo sviluppo web, la cosa più semplice da fare potrebbe essere quella di cercare in jQuery ed è una funzionalità AJAX. I wrapper ci rendono abbastanza facile fare quanto sopra. Ovviamente si può fare lo stesso con qualsiasi altro framework javascript o javascript.

Per riferimento:

+1

Forse non sto capendo. Una pagina PHP non genera il mio nuovo contenuto. Python lo fa. Forse mi manca qualcosa? – bem3ry

+0

Il mio cervello ha cambiato python con PHP. Non chiedere - Scusa. In ogni caso, la mia esperienza è con i linguaggi del server di backend come PHP o asp.net per fare cose come questa. In questo caso, lo script del server potrebbe chiamare il tuo codice phython per creare la pagina. Ma a seconda del tuo server web, dovresti essere in grado di eseguire il Python direttamente come un modulo CGI chiamato dalla tua pagina web. Il risultato dovrebbe essere più o meno lo stesso. – jatrim

2

Questo è probabilmente troppo pesante una soluzione per voi, ma assumendo non si può fare via con la "creazione di un file sul server" parte, questo è considerato una soluzione "best practice" in sviluppo web:

Usa un framework web come Flask o Django per servire le pagine. Quando l'utente richiede che il lavoro venga avviato tramite una richiesta (preferibilmente una richiesta POST perché le richieste GET non dovrebbero causare effetti collaterali significativi), il framework invia un messaggio a un sistema di attività ritardate come Celery. L'utente viene quindi mostrato una pagina che dice che il lavoro è stato inviato.

A questo punto è possibile utilizzare ajax per eseguire il polling del server e vedere quando il lavoro è completato, ma in genere non si vuole che questo sia l'unico metodo per vedere se il lavoro è completato. Se la connessione viene interrotta per qualsiasi motivo, ad esempio se l'utente chiude erroneamente il browser o la scheda (molto comune), lo sforzo verrà sprecato e l'utente dovrà riavviare il processo.Dovresti avere un modo di backup di comunicare con l'utente se possibile; potrebbe trattarsi di un messaggio flash visualizzato altrove sul sito, di un'e-mail automatica "conclusa per lavoro", di una casella nella home page che mostra i lavori completati di recente, ecc. Quanto è pratico e importante dipende dal fatto che l'utente abbia effettuato l'accesso e come a lungo il lavoro prende/se ha effetti collaterali diversi dalla creazione di un file.

Infine è possibile consentire all'utente di accedere alla pagina tramite un URL unico per i risultati del lavoro dell'utente. Assicurati di informare l'utente se quell'URL non sarà valido indefinitamente, ad esempio se il file verrà cancellato su un timer.

Problemi correlati