Python Flask 实时更新日期

7
我正在使用Python Flask和JavaScript构建Web应用程序。我是JavaScript的初学者。
我现在的流程如下:
在Flask Python代码中, 1. 我通过网页抓取数据(每分钟更新的数字数据)。 2. 使用数据计算某些内容并得到最终数字。 3. 制作包含最终数字的列表 4. 通过将列表添加到Flask页面定义中,将列表提供给页面 5. 现在在HTML中使用{{ data|safe }}标签捕获列表
6. 使用JavaScript制作图表。
问题是: 在步骤1中,我获取的数据每分钟更新一次。例如,该网页上现在有15个数据点。我从该网页解析最后10个数据点,然后将它们放入我的Python列表中,然后执行以下步骤,在我的网页上制作图表。一分钟后,在数据源网页上,将有16个数据点可用,我需要获取最后10个数据点。在这种情况下,我需要再次运行Python代码以获取最新的10个数据点,以便在我的网页上制作图表。
因此,我需要始终运行整个Python代码,即整个Flask app init.py文件,并重新渲染我的网页以查看更新后的图表。如果我不在服务器上重新运行init.py文件,则即使过了10分钟或2小时,我也只会永远看到我第一次解析的数据。
我应该如何运行Flask并始终获取更新后的数据,而无需每次都重新运行Flask init.py?
我想过使用time.sleep(60),以便每1分钟运行一次Flask app python文件。但是,当我的代码计算更多内容时,这确实需要很长时间。并不真正起作用。
我该如何解决这个问题?
我应该使用time.sleep吗?还是有更好的方法?
2个回答

11
这是一个经典的“推送”更新问题。您的Web服务器已更新了信息,您希望频繁地更新(或“推送”)到Web客户端前端。
正如PJ Santoro建议的那样,您可以重复轮询服务器(例如每10秒钟):“是否有新数据?没有。好的。是否有新数据?没有。好的。是否有新数据?是的,它在这里!太棒了!是否有新数据?...." 这种方法效率较低,但对于低数据量,您可能永远不会遇到该问题。
更有效的更新系统将使服务器仅在准备好新数据时发送更新信号。有两种主要方法可以实现这一点:
  1. 长轮询,也称为反向 AJAXComet。您的网页在服务器 URL(例如 /update_data)上打开一个 AJAX 请求,并设置一个非常长的超时时间(比如 30 分钟或一小时)。当服务器有数据时,它会通过等待的 AJAX 连接发送数据。这种方法存在一些复杂性,包括在服务器端管理并发(历史上 Python 不擅长处理此类问题),以及即使最大超时时间(我上次使用这种技术时约为 1 小时)可能在没有数据的情况下过期,需要一些错误处理来管理这个问题。如果您想尝试长轮询 / 反向 AJAX,这里有一个使用 Flask 的示例

  2. WebSockets。WebSockets 是一种更为新颖的交互式和“推送”更新服务器和客户端之间的方式。它们被广泛使用;像 Jupyter Notebook 这样的项目就广泛依赖它们。它们非常高效,并且非常适合这种增量更新客户端状态的方式,而且代码通常比反向 AJAX 等后期修改要简单得多。但是... WebSockets 也有复杂性。例如,在 Flask 服务器端管理并发仍然是一个重要的问题。如果您想将 WebSockets 作为您的更新机制,请参考 这个示例,了解如何在 Flask 中使用它们。

无论你使用哪种方法,如果随时间传输的数据增长,你还需要构造每次更新所传输的数据,使其成为增量更新。不管管道有多好,如果每次更新传输数千个数据点,速度就会变慢。但是,长轮询和WebSockets管道至少可以让你在实时更新能力方面走得更远。

谢谢你的回答,我很感激。所以如果我使用WebSocket,我就不需要重新启动Apache2服务来手动重新运行Flask Python代码了吗? - minjunkim7767
第一个问题是“我怎么才能玩杂耍?”虽然不是很容易,但还是可以做到的。这里加上了“...在骑单轮车的同时?”建议您仅使用Flask解决实时更新问题。如果添加了并发、池化和与外部Web服务器的协调等*许多*复杂性,那么它可能无法解决。在尝试双后空翻带扭转之前,先学会侧手翻吧。 - Jonathan Eunice

1

在理想情况下,您可以将其分为2个应用程序:

  • 从Web中提取和解析数据(不需要暴露给Web)

  • 通过Web应用程序向用户交付数据

您可以使用某种CI工具(例如Jenkins)来监视并将外部数据添加到数据库中,然后使用Flask应用程序将这些预处理数据提供给用户。

如果步骤1-6相对较快,您可以在Flask中设置XHR端点,然后使用setInterval() javascript函数定期调用它,以告诉您的应用程序更新数据。例如:

setInterval(function() {
    var req = new XMLHttpRequest();
    req.open('GET', '/refresh_data?time=234', true);
    req.onreadystatechange = function(e) {
        if(req.readyState !== 4) {
            return;
        }
        if ([200, 304].indexOf(req.status) === -1) {
            console.warn('Error! XHR failed.');
        }
        else {
            data = JSON.parse(e.target.responseText);
            processData();
            updateChart();
        }
    };
    req.send();
}, 10000);  // time in milliseconds (e.g. every 10 seconds)

并且有一个像这样的Flask端点:

@app.route('/refresh_data')
def refresh_data():
    time = requests.args.get('time', type=int)
    if not time:
        return jsonify({status: 'error: incorrect parameters'})
    data = requests.get('http://api.getmoredata.com?time=%s' % time)
    # process the results...
    return jsonify({status: 'success', data: data})

最好有一种图表,它有一个refresh()方法,您可以通过它传递新数据并继续添加...(例如,我喜欢使用D3等工具进行此类操作)。

我可能会从init.py代码中删除这部分内容,但对于“第一次加载”来说,这也许是可以接受的。Flask应用程序(例如任何Web应用程序)响应HTTP请求,在请求之间服务器上没有什么持久存在的东西,所以time.sleep()对您来说不起作用... 如果您想在服务器上运行持久性代码,则需要查看像celery这样的东西来管理后台任务。


谢谢!在Python中,解析数据、分析数据以及生成最终数据集(将显示在我的网页上)大约需要5分钟。 - minjunkim7767
谢谢!在Python中,解析数据、分析数据并生成最终数据集(将显示在我的网页上)大约需要5分钟。这意味着如果我重新启动服务apache2,则需要大约5分钟才能使用新的数据集加载网页。我不希望用户等待那么长时间。我应该如何设置XHR端点?你能具体教我吗?我应该把脚本放在哪里?http://api.getmoredata.com/~~~应该是什么?有没有可行的例子? - minjunkim7767
你也可以考虑使用类似 flask-socket.io 这样的工具,来使用 socket.io 实现实时连接...这可能更符合你的使用情况。 - abigperson
如果您不希望用户等待那么长时间来获取数据,您需要将爬取与Web应用程序分开... 老实说,这是一个非常庞大的范围,所以我认为您只需要开始进行研究并尝试一些不同的方法。我建议您看看像jQuery这样的东西,它具有很好的XHR / AJAX请求的便利方法。 - abigperson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接