首页 > 解决方案 > 重置 Flask render_template 输出

问题描述

我目前正在为 Battlefy 网站制作解析器,以快速提取结果并将其转换为 wikicode。

网站:http ://tomshoe02.pythonanywhere.com/scraper

实际操作示例:https ://i.imgur.com/1lj98cP.png

要解析的示例链接:https ://dtmwra1jsgyb0.cloudfront.net/stages/6000c862d9155d46db7f41ca/rounds/1/matches

完整的 app.py:https://pastebin.com/J2nsfmFa

app.py 代码片段:

@app.route("/", methods=["GET", "POST"])
@app.route("/lol", methods=["GET", "POST"])
@app.route("/scraper", methods=["GET", "POST"])
def scraper():
    form = BattlefyForm()
    if form.validate_on_submit():
        url = form.matchhistory.data
        result = jloader(url)
        '''
        #result = url
        result = subprocess.check_output([sys.executable,
            "{}/stuff.py".format(directory), url]).decode('iso-8859-1')
        '''
        return render_template("scraper.html", form=form, result=result)
    return render_template("scraper.html", form=form)

每次我在不重新加载 Web 应用程序的情况下提交时,新结果都会显示在旧结果中。是否有一个模块可以用来清除会话缓存并重置网站的状态,而无需在每次提交要解析的新 URL 时完全重新加载应用程序?

标签: pythonflaskjinja2

解决方案


I disagree with Akib. It doesn't matter whether a redirect is carried out after the form data has been received or the entire page is re-rendered and sent as a response from the server.
After each call, regardless of whether via POST or GET request, the entire page is reloaded and rendered. This could be reduced using ajax. However, this does not cause your issue.

The problem is not within your route, but within your stuff.py module.
You use global variables to save the results extracted from the loaded JSON files in lists.
The first solution would be to empty these lists every time jloader(url) is called. But that doesn't completely solve the problem.
If several users start calls at the same time, this would lead to unexpectedly incorrect results. Since the previous request could not be completed if the list were emptied again and filled with further results.
In addition, global variables should be avoided as long as they are not absolutely necessary.
Because of the reasons listed, I advise you not to use the global variables and to keep the lists as local variables within the function, which are kept for each request and are returned at the end.

This is an approach how you could make your code clearer and do without global variables. I have only rewritten excerpts of your code. I think you can add the rest yourself.

import requests
from collections import namedtuple
from datetime import datetime
import gspread

class Match(namedtuple('Match', ['team_a', 'team_b', 'score_a', 'score_b'])):

    @property
    def winner(self):
        if self.score_a > self.score_b:
            return self.team_a
        elif self.score_a < self.score_b:
            return self.team_b
        return None

    def fmt(self):
        return '{{'\
            f'MatchSchedule|team1={self.team_a}|team2={self.team_b}'\
            f'|team1score={self.score_a}|team2score={self.score_b}'\
            f'|winner={self.winner}|date=...|time=...|timezone=PST|'\
            'dst=yes|vod1=|stream='\
            '}}'

def _get(data, key_path, default=None):
    tmp = data
    for k in key_path.split('.'):
        try:
            tmp = tmp[k]
        except KeyError:
            return default
    return tmp


def get_matches(url, team_alias={}):
    data = requests.get(url).json()

    for item in data:
        top_team = _get(item, 'top.name', _get(item, 'top.team.name'))
        low_team = _get(item, 'bottom.name', _get(item, 'bottom.team.name'))
        top_score = _get(item, 'top.score')
        low_score = _get(item, 'bottom.score')

        # Test for results that are None and react accordingly. 
        # The date and time queries are missing here. 

        top_team = team_alias.get(top_team, top_team)
        low_team = team_alias.get(low_team, low_team)

        match = Match(top_team, low_team, top_score, low_score)
        yield(match)

def get_teams():
    gc = gspread.service_account(filename='credentials.json')
    sh = gc.open_by_key('1N7wnIRWJRbULKychJU-EOyisuZBX1rgXwdW91Keki4M')

    col_name = worksheet.col_values(1)
    col_alias = worksheet.col_values(2)

    return dict(zip(col_name, col_alias))

def load_data(url):
    '''Use this instead of jloader(url).'''
    team_alias = get_teams()
    return '\n'.join(match.fmt() for match in get_matches(url, team_alias))

def main():
    url = 'https://dtmwra1jsgyb0.cloudfront.net/groups/5f60cffb30d29b119e36b42b/matches'
    dat = load_data(url)
    print(dat)

if __name__ == '__main__':
    main()
``

推荐阅读