9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Flaskでオシャレなボートレース予想サイトをつくりあげる

Last updated at Posted at 2020-06-11

はじめに

この記事は、自身で製作しWeb公開にまで至ったボートレース3連単予測サイト「きょう、ていの良い予想は当たるだろうか」の内部コード解説となります。今回はFlaskによるWebアプリケーション作成に関してまとめていきます。
予測モデル作成であったり、そのほかの情報はこちらをご覧ください。

※コードの書き方は我流なので、アドバイスいただけると有り難いです。

##ポンチ絵を描いてみる
普段こういったことをしないもので、新鮮でしたね。お酒を飲むと絵がサクサク進んでいきました。笑
image.png

コンセプトですが

  • シンプル。
  • 情報がOpenになっている
  • スタバで開いても違和感なし

スタバユーザーの私としては最後の一文が超重要です。要は賭け事っぽさを極力排除して、お金の匂いがないサイトを作りたかったんですね。なぜならば、ボートレースファンの方に限らず、いろんな方に見て欲しかったから..!! こういった思いが酔いが回るほど溢れ出てきて、絵を描いている最中はとても楽しかったです。

そしてFlaskで実装していく..ためのフォルダ構成

まずはじめに、FlaskでWebアプリケーションを作る上で個人的に重要と思った、ファイル構造をお見せします。

image.png image.png

要点をまとめると

  • app.pyをParentディレクトリ上に置き、app.pyにてFlaskベースの記述を行う
  • htmlファイルはtemplatesフォルダに
  • cssや画像、予測結果などの資料はstaticフォルダ階層に保存していきます。

いろいろなやり方があるとは思いますが、まずはこの構成がスタンダードなのかな、と感じています。

Flaskで実装していく!!

基本的に、レース予想や昨日の結果はcsvファイルで保存し、app.pyでそれらを読み込むだけ、としております。なので、比較的シンプルな構成になったかなぁと思っております。大した事ないコードなので、そのまま掲載します。

app.py

import pandas as pd
import datetime
from flask import Flask, render_template
import os
import time

app = Flask(__name__)

##pathがどこにあるか確認
#path=os.getcwd()
#print(path)

##日付取得
os.environ["TZ"] = "Asia/Tokyo"
time.tzset()
tday=datetime.date.today()
yday= tday - datetime.timedelta(days=1)
d_tday=tday.strftime('20%y%m%d')
d_yday=yday.strftime('20%y%m%d')

##本日のレース予測
#d_tday= '20200612' #特別に設定したいとき 
df_pred = pd.read_csv('mysite/static/report/predict_'+d_tday+'.csv')
pred_num_tday = len(df_pred)
header = df_pred.columns
record = df_pred.values.tolist()

##昨日の予測結果
#d_yday= '20200612' #特別に設定したいとき
df_ans = pd.read_csv('mysite/static/report/result_'+d_yday+'.csv')
df_ans = df_ans.fillna("")
header_ans = df_ans.columns
record_ans = df_ans.values.tolist()
pred_num = len(df_ans)
hit_num = len(df_ans[df_ans["Result"]=="Hit"])
hit_ratio = round(hit_num/pred_num*100,1)
pay = 100*pred_num
getmoney = df_ans["Payoff"].sum()
pay_return = round(getmoney/pay*100,1)

if hit_ratio >= 10:
    msg = "的中率10%超えるなんて..昨日は良い日でしたね"
elif hit_ratio > 6:
    msg = "なんともネタにもしにくい的中率.."
else:
    msg = "こういう日もあるよね。前を向いて歩こう"

if pay_return > 100:
    msg2 = "今日はちょっと良いビールでも買いましょうか"
elif pay_return > 75:
    msg2 = "お金を稼ぐって大変ですね"
else:
    msg2 = "涙の数だけ強くなれるよ"


##各ページへのレンダリング
@app.route('/')
def top_page():
    return render_template('top_page.html')

@app.route('/thissite')
def this_site():
    return render_template('this_site.html')

@app.route('/disclaimer')
def disclaimer():
    return render_template('disclaimer.html')

@app.route('/prediction')
def prediction():
    return render_template('prediction.html', tday=tday,header=header,record=record,pred_num=pred_num_tday)

@app.route('/result')
def result():
    return render_template('result.html', yday=yday,header=header_ans,record=record_ans,msg=msg,msg2=msg2,\
                          pred_num=pred_num,hit_num=hit_num,\
                           hit_ratio=hit_ratio,pay=pay,getmoney=getmoney,\
                          pay_return=pay_return)

#テスト用のページ if any


if __name__ == '__main__':
    app.run(host='0.0.0.0',debug=True)

前半部分はcsvファイルを取得して、データを簡単に処理しているだけです。
Flaskのキモはレンダリングの所でしょうか。あるページにアクセスする際に、変数を渡す事でそれぞれのページに与えたい情報を反映していく事ができました。

さくっと、HTMLの中身も

中身の解説ではないですが、

  • Bootstrapマジ便利!
  • {% block content %}{% endblock %}を使い、他htmlがlayout.htmlを組み込む事で、統一感を持ったサイトができあがりました。
layout.html
<html>

<head>
    <!-- BootStrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    <link rel="stylesheet" type="text/css" href="../static/css/layout.css">
    
    <title>
        きょう、ていの良い予想は当たるだろうか?
    </title>
    <meta http-equiv="content-type" charset="utf-8">
    <link rel="shortcut icon" href="../static/images/favicon_1.ico">
</head>

<body>
    <nav class="navbar navbar-expand-sm navbar-light bg-light mt-3 mb-3">
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav4" aria-controls="navbarNav4" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <a class="navbar-brand" href="/">DoYouHaveNiceBoat?</a>
        <div class="collapse navbar-collapse justify-content-end">
            <ul class="navbar-nav">
                <li class="nav-item">
                    <a class="nav-link" target=”_blank” href="https://twitter.com/df_ngo">Twitter</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" target=”_blank” href="https://qiita.com/NGOhiroshi/items/7bcbf01df7c32c93d655">Qiita</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/thissite">このサイトについて</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="/disclaimer">利用規約</a>
                </li>
            </ul>
        </div>
    </nav>
    <div class="jumbotron">


        {% block content %}{% endblock %}

    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>


</body>

</html>

できた!!!

是非、みてやってください。→きょう、ていの良い予想は当たるだろうか
余力があれば是非、予想をもとに舟券を買ってみてください。私が予測モデルを改善していくモチベーションになります。笑

見た目はどうですかね、、個人的にはオシャレだと思っています。スタバで開いてても違和感ないことは私自身で実証しました。笑

image.png

##さいごに....Webアプリをつくる..って大変なんだな

言うは易く行うは難し、でしたね。ポンチ絵のイメージを具現化するのに、時間は一瞬で溶けていきました。笑
なんか微妙に、字の大きさが..位置が..の連続でした。(勉強不足なのは言うまでもありませんが)
ただ、私らしくない粘り腰を見せ、無事に完成したので本当に良かったです。シロートは、まずは黙ってBootstrap!かもしれないですね。

公開されたときの、「世界とつながったのか..!!」感は確かに感じることができたのでトライする価値は確実にあると思います。楽しいけど寝不足に悩む1週間でした。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?