如何设计一个在可变用户输入上运行长时间运行脚本的Web应用程序?

时间:2016-12-20 08:52:28

标签: python web-applications flask

说明

我正在设计一个网络抓取网络应用程序,它接受用户输入(主要是带有item_id的网址),将其传输到我的网页抓取脚本,将从网页上抓取的数据保存到数据库中。 我正在使用flask,python和mysql

问题:

现在,用户可以在csv中上传一些带有item_id的网址然后想要更改一些网址,原因可能是他们发现某个项目与其网址不匹配,在这种情况下我提供了一个网络表单使用item_id和url作为最终用户的输入,以使用其item_id上传新网址。

问题在于,当用户首先上传大型csv文件时,我会启动一个线程来对输入运行web-scraping脚本并将数据中的已删除数据保存起来,这应该花费相当长的时间,因为它的大小输入。后来当用户上传一些网址更改时,我会再次启动一个线程,在这些较小的输入上运行相同的网页抓取脚本,这比第一次运行所需的时间要短得多。这样,第二次运行将结束并保存在我的数据库中的数据,只是被第一次和较慢的运行覆盖。

期望的结果:

最终目标是正确管理数据输入,以便使用以后上传的网址,并将这些页面上的数据存储在我的数据库中。

我得到的是:

使用后来上传的网址,并将数据写入数据库,但之后上传的和错误网址的数据会覆盖这些网址。

我的想法:

  1. 也许我可以确保第二次运行只在第一次运行完成后运行。但我使用python线程来接收用户输入并运行我的脚本。并且线程不会那样工作。

  2. 不是在用户输入上运行脚本,也许我可以在我的应用程序之上构建数据库层,当用户上传一些新数据时,我将它传输到数据库。并以某种方式让我的脚本监听数据库表中的更改,并在这些更改上运行脚本。但我不知道如何实现这一点。

1 个答案:

答案 0 :(得分:2)

您可以尝试celery并将该线程作为芹菜任务运行。每次运行新的celery任务时,都会将任务ID和用户存储在数据库中。然后,当您进行第二次运行时,您可以等待第一个任务结束:

@app.task()
def celery_task(user):
    first_task_id = get_first_task_id(user)  # Get id from the db
    if first_task_id is not None:  # First task is still running
        app.AsyncResult(first_task_id).get()

    # Do your second operation
    # Remove task_id from db