Создайте гиперссылку (или кнопку), которая выполняет python script, а затем перенаправляет, когда script завершает

Хорошо, мне удалось заставить его работать, как я хочу (хотя некоторые/большинство может не согласиться с методом). Я использовал Flask, как рекомендовано ниже. Часть, которая может считаться "неправильной", - это контрольная петля 404. Это неправильный дизайн и приводит к ошибке "застрявшей script" в некоторых браузерах, если она продолжается слишком долго. Тем не менее, script, который я хочу запустить, длится недолго, чтобы это было проблемой.

Спасибо за помощь и, пожалуйста, дайте мне знать, если у вас есть другие предложения.

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>

Оригинальный вопрос:

Я начинающий программист на Python и начинающий веб-разработчик, поэтому, пожалуйста, будьте осторожны. Что я хочу: Пользователь нажимает гиперссылку и переносится на промежуточную веб-страницу, которая говорит что-то вроде "Обработка...". В фоновом режиме (на сервере) эта ссылка запускает python script, который обрабатывает файл и создает новую веб-страницу. По завершении script пользователь перенаправляется на вновь созданную страницу. Что у меня есть: У меня есть script, который обрабатывает и выдает новую страницу. Я не понял, как запустить python script, а затем запустить перенаправление при завершении script. Я просмотрел веб-фреймворки, такие как django и cgi-скрипты. Но я не нашел ничего, что, по моему мнению, соответствовало бы счету. Это очень возможно, я просто пропустил что-то совершенно очевидное, поэтому я очень признателен за любую помощь. Спасибо.

Ответ 1

Простым способом решения этой проблемы будет использование простой веб-структуры, такой как Flask, для создания веб-части вашей системы. В обработчике запросов для вашей магической ссылки вам нужно будет запустить ваш script и отслеживать его. Простой способ проверить, выполнен ли ваш script и передать его вашему пользователю, периодически отправлять запрос ajax для проверки завершения.

Итак, например, веб-сайт Flask может выглядеть так:

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, убедитесь, что в группе процессов есть только один процесс.

Если вам нужно более сложное решение, вы можете посмотреть очереди сообщений и т.п.

Ответ 2

Это, вероятно, слишком тяжелое решение для вас, но, полагая, что вы не можете покончить с частью "создания файла на сервере", это считается решением "лучшей практики" в веб-разработке:

Используйте веб-фреймворк, например Flask или Django, для обслуживания страниц. Когда пользователь запрашивает запуск задания через запрос (предпочтительно запрос POST, поскольку запросы GET не должны вызывать существенные побочные эффекты), среда отправляет сообщение в отложенную систему задач, такую ​​как Celery. Затем пользователю показана страница с сообщением о том, что задание было отправлено.

В этот момент вы можете использовать ajax для опроса сервера и посмотреть, когда задание будет завершено, но обычно вы не хотите, чтобы это был ваш единственный способ увидеть, завершено ли задание. Если соединение по какой-либо причине прерывается, например, если пользователь ошибочно закрывает браузер или вкладку (очень часто), усилия будут потрачены впустую, и пользователю придется снова начать процесс. У вас должен быть резервный способ связи с пользователем, если это вообще возможно; это может быть флэш-сообщение, которое появляется в другом месте на сайте, автоматическое "заполненное задание" письмо, поле на главной странице, которое показывает недавно завершенные задания и т.д. Насколько практично и важно это зависит от того, зарегистрирован ли пользователь и как длительность выполнения задания/имеет ли он побочные эффекты, кроме создания файла.

Наконец, вы можете разрешить пользователю получать доступ к странице через URL-адрес, уникальный для результатов работы этого пользователя. Обязательно сообщите об этом пользователю, если этот URL не будет действительным на неопределенный срок, например, если файл будет удален по таймеру.

Ответ 3

Два простых способа сделать это:

1) Используйте ajax для опроса сервера. Проверяйте до завершения каждые 10 секунд или любой промежуток времени, который вы считаете нужным. Например. в то время как script обрабатывает, он записывает в файл или базу данных, как бы это ни было, чтобы указать процент завершения, а также определить процесс каким-то образом (в случае, если несколько сценариев работают одновременно, вы захотите узнать, какой из них это Боб, а другой - Сьюзи).

2) Отключите буферизацию вывода и передайте результат клиенту. Это проще, чем первый вариант. В принципе, запустите script, и по мере его обработки вы можете вывести код javascript, чтобы сказать, обновить индикатор прогресса. Вам нужно отключить буферизацию вывода или вручную сбросить буфер, иначе ваш клиент может не получить результат сразу (обновление индикатора может быть видимым только клиенту, когда он достигает 100%). Google, как это сделать при любой настройке (например, PHP, Django), которую вы запускаете.

Ответ 4

То, что вы хотите, возможно, но это действительно около 3 проблем.

Первый вопрос: как создать новый файл с PHP. Я не могу ответить на этот вопрос. Что вам нужно сделать, возможно, зависит от того, какой файл вы пытаетесь создать и почему.

Второй вопрос: как сообщить пользователю, что это происходит, а третий - как перенаправить на новую страницу.

Лично я считаю, что самый короткий путь к победе - это, вероятно, чтобы ваш клиентский javascript сделал запрос AJAX на страницу сервера или модуль CGI, который создает новый контент.

  • В щелчке на кнопке сделайте запрос ajax на страницу PHP, которая создает новую страницу контента.
  • Представьте индикатор занятости.
  • Попросите запрошенную страницу вернуть URL-адрес новой страницы в качестве ее содержимого.
  • Когда запрос завершает перенаправление на возвращаемый URL через javascript.

Как кто-то новый для веб-разработки, самой простой задачей может быть просмотр jQuery и его функциональность AJAX. Обертки там делают довольно легким сделать выше. Конечно, вы можете сделать то же самое с любыми другими основными фреймворками javascript или с прямым javascript.

Для справки: