2012-06-05 68 views
10

Bien, logré que funcionara como yo quisiera (aunque algunos/la mayoría podrían estar en desacuerdo con el método). Utilicé Flask como se recomienda a continuación. La parte que podría considerarse "incorrecta" es el ciclo de verificación 404. No es un diseño apropiado y provoca un error de "script pegado" en algunos navegadores si continúa durante demasiado tiempo. Sin embargo, el script que quiero ejecutar no dura lo suficiente como para que sea un problema.Crear un hipervínculo (o botón) que ejecuta una secuencia de comandos python y luego redirige cuando la secuencia de comandos completa

Gracias por la ayuda y háganos saber si tiene alguna otra sugerencia.

Frasco Aplicación:

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> 

pregunta original:

Soy un/programador Python intermedio principiante y un desarrollador web que comienza así que por favor ser suave . Lo que quiero: Un usuario hace clic en un hipervínculo y se lo lleva a una página web intermedia que dice algo así como "Procesando ...". En el fondo (en el servidor), este enlace desencadena una secuencia de comandos python que procesa un archivo y crea una nueva página web. Al completar la secuencia de comandos, el usuario se redirige a la página recién creada. Lo que tengo: Tengo un script que procesa y escupe una nueva página. Lo que no he descubierto es cómo activar el script de python y luego desencadenar el redireccionamiento al finalizar el script. He visto frameworks web como django y cgi scripting. Pero no he encontrado nada que me parezca adecuado. Es muy posible que me esté perdiendo algo completamente obvio, así que realmente agradecería cualquier ayuda. Gracias.

+0

Lo que está describiendo requiere escribir un nuevo contenido web en un archivo en disco y luego servirlo. Esto es bastante inusual El flujo estándar sería más parecido a: 1. hacer clic en el botón y activar la solicitud de página del servidor. 2. El backend de PHP para la página solicitada procesa la información querystring/form/cookie en la solicitud y genera contenido dinámico en la página solicitada. 3. la página se envía al usuario. ¿Estás seguro de que no es lo que quieres? – jatrim

+0

Estoy seguro. Sé que lo que intento es inusual. Es por eso que necesito ayuda. :) – bem3ry

+0

Su función de pausa es realmente muy mala y dañina y desperdicia los ciclos de la CPU a lo grande. Use 'setTimeout' en su lugar. Además, su versión solo funciona para generar un archivo y no cuenta para varias personas que visitan su página al mismo tiempo, pueden intentar generar el archivo al mismo tiempo. Quizás verifique si el archivo ya existe antes de ejecutar el script. – mensi

Respuesta

6

Una forma sencilla de hacer frente a este problema sería el uso de un marco simple de la tela como Frasco para construir la pieza de la tela uf su sistema. En el controlador de solicitud para su enlace mágico, necesitaría generar su secuencia de comandos y realizar un seguimiento de ello. Una manera simple de ver si su script está listo y transmitirlo a su usuario es enviar periódicamente una solicitud ajax para verificar la finalización.

Así, por ejemplo, el sitio web Frasco podría ser así:

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

Y el index.html:

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

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

Este es todo el código no probado en el momento , pero espero que tengas una idea de cómo abordar este problema metro. También tenga en cuenta que esto solo funcionará si sirve la página desde un proceso, por lo que si configura Apache y mod_wsgi, asegúrese de que solo haya un proceso en el grupo de procesos.

Si necesita una solución más compleja, es posible que desee consultar las colas de mensajes y similares.

+0

Ok ... las cosas se ven mucho mejor con esto. :) Lo único que no he trabajado es una redirección en la finalización del script. Simplemente parece que nunca redirige. – bem3ry

+0

@ user1438165 es posible que desee editar su pregunta para mostrar lo que tiene actualmente y dónde exactamente está el problema. – mensi

+0

Ver arriba, actualizado con el método que utilicé. Tu código ayudó mucho. Gracias. :) – bem3ry

0

Dos maneras de hacer esto simplish:

1) el uso de AJAX para sondear el servidor. Verifique que se complete cada 10 segundos o el intervalo que considere apropiado. P.ej. mientras el script está procesando, escribe en un archivo, o base de datos, cualquiera que sea para indicar el porcentaje de finalización así como identificar el proceso de alguna manera (en caso de que tenga varios scripts en ejecución simultáneamente, querrá saber cuál es el de Bob y cuál es el de Suzy).

2) Inhabilita el almacenamiento en búfer de salida y transmite la salida al cliente. Esto es más simple que la primera opción. Básicamente, ejecute el script y mientras se procesa, puede generar un código javascript para decir, actualizar un indicador de progreso. Debe desactivar el almacenamiento en búfer de salida o vaciar manualmente el búfer; de lo contrario, su cliente podría no recibir el resultado de inmediato (la actualización del indicador solo puede ser visible para el cliente cuando llegue al 100%). Busca cómo hacerlo en cualquier configuración (por ejemplo, PHP, Django) que estés ejecutando.

0

Lo que quiere es posible, pero en realidad se trata de 3 problemas.

La primera pregunta es, ¿cómo se crea un nuevo archivo de PHP. Realmente no puedo responder a esto. Lo que debe hacer, probablemente dependa del tipo de archivo que intenta crear y por qué.

La segunda pregunta es, cómo le informa al usuario que esto está sucediendo, y la tercera es cómo se redirige a la nueva página.

Personalmente, creo que la ruta más corta hacia la victoria, es probablemente tener su javascript en el lado del cliente hacer una solicitud de AJAX a la página del servidor o módulo de CGI que crea su nuevo contenido.

  1. Al hacer clic en el botón, realice una solicitud AJAX a la página PHP que genera su nueva página de contenido.
  2. Presente su indicador de ocupado.
  3. Haga que la página solicitada devuelva la URL de la nueva página como su contenido.
  4. Cuando la solicitud completa la redirección a la URL devuelta mediante javascript.

Como persona nueva en el desarrollo web, lo más fácil es buscar en jQuery y su funcionalidad AJAX. Las envolturas allí hacen que sea bastante fácil hacer lo anterior. Por supuesto, usted puede hacer lo mismo con cualquiera de los otros marcos principales de JavaScript o directamente con Javascript.

Como referencia:

+1

Tal vez no estoy entendiendo. Una página PHP no genera mi nuevo contenido. Python lo hace. Tal vez me estoy perdiendo algo? – bem3ry

+0

Mi cerebro cambió pitón con PHP. No preguntes, lo siento. En cualquier caso, mi experiencia es con lenguajes de servidor back-end como PHP o asp.net para hacer cosas como esta. En este caso, la secuencia de comandos del servidor podría llamar a su código phython para hacer la creación de la página. Pero dependiendo de su servidor web, también debería poder ejecutar el Python directamente como un módulo CGI llamado desde su página web. El resultado debería ser aproximadamente el mismo. – jatrim

2

Ésta es probablemente demasiado pesado una solución para usted, pero suponiendo que no puede acabar con la "creación de un archivo en el servidor" parte, esto se considera una solución "mejores prácticas" en el desarrollo web:

Utilice un marco web como Flask o Django para mostrar páginas. Cuando el usuario solicita que el trabajo se inicie a través de una solicitud (preferiblemente una solicitud POST porque las solicitudes GET no deberían causar efectos secundarios significativos), el marco envía un mensaje a un sistema de tareas retrasado como Apio. Luego, se muestra una página que dice que el trabajo ha sido enviado.

En este momento puede usar ajax para sondear el servidor y ver cuándo se completa el trabajo, pero normalmente no desea que sea su único método para ver si el trabajo se ha completado. Si la conexión se interrumpe por algún motivo, por ejemplo, si el usuario cierra el navegador o la pestaña por error (muy común), se desperdiciará el esfuerzo y el usuario tendrá que volver a iniciar el proceso.Debe tener una forma alternativa de comunicarse con el usuario si es posible; esto podría ser un mensaje instantáneo que aparece en otro lugar del sitio, un correo electrónico automatizado de "finalización del trabajo", un cuadro en la página principal que muestra los trabajos completados recientemente, etc. Qué práctico e importante es esto depende de si el usuario está conectado y cómo Cuánto dura el trabajo/si tiene efectos secundarios además de la creación de un archivo.

Finalmente, puede permitir que el usuario acceda a la página a través de una URL única para los resultados de trabajo de ese usuario. Asegúrese de informar al usuario si esa url no será válida indefinidamente, por ejemplo, si el archivo se eliminará en un temporizador.

Cuestiones relacionadas