frisk_server

FlaskでWebページを表示しよう

今日の目標!

今日作るもの

今回は、川柳を表示するシンプルなWebページを作るよ。

senryu_site

まだ上五、中七、下五の登録などはできないけど、まずは、Pythonで作ったWebページが自分のブラウザに表示されるところまで進めよう!

Webサイトはどうやって表示される?

Webサイトを見るとき、ブラウザの中に最初からページが入っているわけじゃないんだ。

ブラウザがWebサーバーへ「このページを見せて!」とお願いし、WebサーバーがHTMLなどのデータを返してくれる

かえってきたHTMLはとても見づらいので、人間がわかりやすいようにきれいに表示してるのは、ブラウザの役目。

request_response

HTML、CSS、Python、Flaskの役割

今回登場する4つには、それぞれ別の役割があるよ。

名前 主な役割 今回担当すること
HTML ページの内容と構造を作る 見出し、説明文、川柳を書く
CSS ページの見た目を整える 色、文字の大きさ、余白を決める
Python データを処理する サイト名やメッセージを用意する
Flask ブラウザとPython・HTMLをつなぐ URLに合ったPythonの関数を動かし、HTMLを返す

人間の顔にたとえると、HTMLの仕事は、お正月の福笑いみたいに、かおのパーツを置くところをざっくり設定する感じ。

CSSは、その顔にお化粧などをして、おしゃれしたりかわいくしたりする感じ

pythonやflaskの力で、その人を歌ったり踊ったりさせて、アイドルみたいに人をひきつけるサイトになっていくわけ。

html_girl

Flaskは、ブラウザから来たお願いを受け取り、必要なPythonの処理とHTMLを結び付ける案内役なんだ。

FlaskはPythonのWebフレームワーク。PythonでWebサイトを作るために必要な機能をまとめて用意してくれる。

HTMLって何?

HTMLは、Webページに「これは大見出し」「これは文章」「これは画像」と、内容の意味や構造を付けるための言語なんだ。

HTMLは、次のように<と>で囲まれたタグを使って書くよ。

<h1>川柳ひろば</h1>
<p>みんなの川柳を楽しむサイトです。</p>
<button>川柳を作る</button>

HTMLファイルをそのまま見ると、英語や記号が混ざった文字に見えるよね。

ブラウザの役割

ブラウザはタグの意味を読み取り、タグそのものは表示せず、次のようなWebページに変えてくれるよ。

See the Pen Untitled by ricky-sensei (@ricky-sensei) on CodePen.

CSSがない状態では、ブラウザが用意している基本の見た目で表示されるから、ぶっちゃけかなり味気ない感じのサイトになる。みんなが普段見ているおしゃれなサイトは、CSSの力を借りているわけだ

with_and_without_css

阿部寛のホームページ 俳優の阿部寛さんのホームページは、HTMLのみってわけじゃないけど、重いjavascriptやCSSなどの装飾を極力使わず、どんなに回線が遅くても爆速で表示されるサイトとして、よくネタにされる
阿部寛のホームページ

ブラウザはHTMLやCSSなどの文字を読み取って、人間が見やすいように表示する役割を持ってるよ。

ブラウザにはいろんな種類があって、それぞれ特徴があるよ。

browser

HTMLを表示する他にも、お気に入りのサイトをまとめておいたり、一度見たサイトを覚えておいたり、快適にインターネットを見ることができる機能がたくさんある。

開始タグと終了タグ

多くのHTMLタグは、開始タグと終了タグで内容を挟むよ。

<h1>川柳ひろば</h1>

終了タグには/が付くよ。

タグにはそれぞれ役割があって、それぞれのタグの機能を組み合わせて使っていくよ

タグ 役割
<h1> ページで一番大きな見出し
<p> 文章のまとまり
<button> ボタン
<a> 別のページへ移動するリンク
<img> 画像

終了タグがないタグもある

HTMLタグには、次の2つのパターンがあるよ。

  1. 開始タグと終了タグがあるタグ
  2. 開始タグだけで、終了タグがないタグ

<h1>や<p>は、表示する文字を間に挟むから、開始タグと終了タグをセットで書くんだ。

<h1>川柳ひろば</h1>
<p>みんなの川柳を楽しむサイトです。</p>

一方、<img>や<br>のように、文字を間に挟まないタグもあるよ。これらは、終了タグを書かずに使うよ。 HTMLを勉強していくと出てくるから、今は覚えなくても全然OK

<img src="senryu.png" alt="川柳の画像">

<p>風吹けば<br>宿題ぜんぶ<br>飛んでいけ</p>

HTML全体の形

HTMLは、基本的にこういう形になっているよ。

html_structure

VSCodeでラクしよう!

VS Codeには、HTMLを素早く書くための**Emmet(エメット)**という機能が入っているよ。すべてのタグを手で書かなくても、Emmetに手伝ってもらえるんだ。

!でHTML全体を作ろう

index.htmlを開いて、何も書かれていない行に半角の!を入力してみよう。

!

!またはEmmet Abbreviationと書かれた候補が表示されたら、その候補を選んでEnterキーかTabキーを押してみてね。

!
 ↓ Emmetの候補を選ぶ
<!DOCTYPE html>
<html lang="en">
    ...
</html>

HTML全体のひな形が一度に作られるよ。<html lang="en">となっていたら、日本語のページでは<html lang="ja">へ変更しよう。

タグ名とTabキーで補完しよう

タグを1つ書きたいときは、<や>を全部手で入力しなくても大丈夫だよ。タグ名だけを入力して、Tabキーを押してみよう。

h1
 ↓ Tabキー
<h1></h1>
p
 ↓ Tabキー
<p></p>

開始タグと終了タグが自動で作られ、文字を入力する場所へカーソルが移動するよ。

候補が出ないときは、ファイル名が.htmlで終わっているか確認してみよう。VS Codeの画面右下にHTMLと表示されているかも確認してね。

サーバーって何?

サーバーをわかりやすく説明すると、「24時間365日、みんなの要求に応え続けるために、電源つけっぱなしで働き続けているパソコン」のこと

例えばみんなのパソコンで素晴らしいウェブサイトをHTMLなどを使って作ったとして、それをどうやってみんなに見てもらうか考えてみよう。

まずはウェブサイトを見に来る人のパソコンから、みんなのパソコンの中のHTMLを見に来れるように設定しなくちゃいけないけど、それができたとして、ウェブサイトって基本いつでも見られるようにしなくちゃいけないよね。でもそれだと、みんなのパソコンを24時間つけっぱなしにしなくちゃいけない。実際、マインクラフトで友達とマルチプレイ(LANに公開)するときは、ワールドを作成するパソコンがサーバーとなっているから、そのパソコンでマイクラを終了したり電源を切ったりすると、他の参加者も接続が切れたりする。

でもウェブサイトの場合はそれだと困る。じゃあどうするかというと、24時間365日電源つけっぱなしの「サーバー」というパソコンに、HTMLを入れといて、いつでもアクセスできるようにしとけばいい。

実際に自分でウェブサイトを作るときは、まずは自分のパソコンで開発して、出来上がったらサーバーに公開することになるよ。

みんなが遊んでるオンラインゲームのサーバーは世界中のどこかにあるパソコンのことで、そのパソコンが頑張ってくれているから、世界中のプレイヤーと対戦できたりするわけ。

server

今回はflaskテストサーバーという、パソコン内(ローカル)の開発者用サーバーを使ってHTMLを見てみるよ。

準備しよう

フォルダを作ろう

2_flaskフォルダの中に、1_flask_web_pageフォルダを作る。

最初は、次のような構成にしよう。

1_flask_web_page
└── app.py

app.pyには、Flaskを動かすPythonコードを書いていくよ。

ファイル名をflask.pyにすると、インストールしたFlaskと名前が重なってエラーの原因になる。今回はapp.pyという名前にしよう。

Flaskをインストールしよう

VS Codeで1_flask_web_pageフォルダを開き、ターミナルで次のコマンドを実行してみよう。

python -m pip install flask

インストールできたか確認しよう。

python -m pip show flask

Flaskの名前やバージョンが表示されたら、準備完了だよ!

最初のFlaskアプリを作ろう

app.pyへ次のコードを書く。

from flask import Flask


app = Flask(__name__)


@app.route("/")
def show_index():
    return "<h1>Hello, Flask!</h1>"


if __name__ == "__main__":
    app.run(debug=True, port=8000)

テストサーバーを起動しよう

ターミナルで次のコマンドを実行してみよう。

python app.py

次のような表示が出れば、Flaskのテストサーバーが起動できているよ。

 * Serving Flask app 'app'
 * Debug mode: on
 * Running on http://127.0.0.1:8000

ブラウザで次のURLを開こう。

http://127.0.0.1:8000

画面に大きくHello, Flask!と表示されたら成功!

Pythonコードを読んでみよう

Flaskを読み込む

from flask import Flask

インストールしたflaskライブラリから、Flaskを使えるようにしているよ。

Flaskアプリを作る

app = Flask(__name__)

この行で、Flaskアプリの本体を作ってappへ入れているんだ。

__name__は、FlaskがHTMLやCSSなどのファイルを探す場所を判断するために使われるよ。細かい仕組みは、今は覚えなくてOK!

URLと関数を結び付ける

@app.route("/")
def show_index():

@app.route("/")は、URLの/と、その下にあるshow_index()関数を結び付けているよ。

/はWebサイトの一番最初のページ、つまりトップページを表すんだ。

ブラウザが「/」をリクエスト
              ↓
      show_index()を実行

このように、URLと関数を結び付ける設定をルートというよ。

HTMLを返す

return "<h1>Hello, Flask!</h1>"

関数が返した文字列は、Flaskからブラウザへのレスポンスになるんだ。

ブラウザは<h1>をHTMLの大見出しとして読み取り、大きな文字で表示してくれるよ。

ブラウザ → Flask → show_index() → HTMLをreturn → ブラウザ

テストサーバーを起動する

if __name__ == "__main__":
    app.run(debug=True, port=8000)

python app.pyでapp.pyを直接実行したとき、app.run()がFlaskのテストサーバーを起動するよ。

if __name__ == "__main__":は、「このファイルが直接実行されたときだけ、その下の処理を動かす」という意味だよ。詳しい仕組みは、今は覚えなくてOK!

HTMLとCSSを別ファイルにしよう

短いHTMLならPythonの文字列として書けるけれど、本物のWebページはもっと長くなるよね。

そこで、HTMLとCSSを役割ごとのファイルへ分けてみよう。

最終的なフォルダ構成は、次のようになるよ。

1_flask_web_page
├── app.py
├── templates
│   └── index.html
└── static
    └── style.css

フォルダ名はtemplateではなくtemplates、staticはすべて小文字にしよう。

HTMLを作ろう

templatesフォルダを作り、その中にindex.htmlを作る。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ site_name }}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <main class="card">
        <p class="label">MY SENRYU SITE</p>
        <h1>{{ site_name }}</h1>
        <p class="description">{{ description }}</p>

        <div class="senryu">
            <p>古池や</p>
            <p>リッキーやっぱり</p>
            <p>イケメンだ</p>
        </div>

        <p class="message">{{ message }}</p>
    </main>
</body>
</html>

{{ site_name }}などの二重波かっこは、Pythonから受け取ったデータをHTMLへ表示するための書き方だよ。

Pythonのsite_name
        ↓
HTMLの{{ site_name }}
        ↓
ブラウザに「川柳ひろば」と表示

この仕組みを提供しているものをJinja(ジンジャ)テンプレートというんだ。今回は、二重波かっこでデータを表示できることだけ覚えればOK!

CSSを作ろう

staticフォルダを作り、その中にstyle.cssを作る。

* {
    box-sizing: border-box;
}

body {
    min-height: 100vh;
    margin: 0;
    display: grid;
    place-items: center;
    font-family: sans-serif;
    color: #263238;
    background: #e8f5e9;
}

.card {
    width: min(90%, 640px);
    padding: 48px 32px;
    text-align: center;
    background: #ffffff;
    border: 4px solid #66bb6a;
    border-radius: 24px;
    box-shadow: 0 12px 30px rgba(38, 50, 56, 0.15);
}

.label {
    margin: 0;
    color: #388e3c;
    font-size: 14px;
    font-weight: bold;
    letter-spacing: 0.15em;
}

h1 {
    margin: 8px 0 12px;
    font-size: 40px;
}

.description {
    margin-bottom: 32px;
    color: #607d8b;
}

.senryu {
    padding: 24px;
    background: #f1f8e9;
    border-radius: 16px;
    font-size: 28px;
    font-weight: bold;
    line-height: 1.5;
}

.senryu p {
    margin: 4px;
}

.message {
    margin: 28px 0 0;
    color: #388e3c;
    font-weight: bold;
}

HTMLの<link>に書いた次の部分が、FlaskへCSSファイルのURLを作ってもらう命令だよ。

{{ url_for('static', filename='style.css') }}

ブラウザはHTMLを受け取った後、このURLを使ってCSSも取得するんだ。

① ブラウザが「/」をリクエスト
② Flaskがindex.htmlを返す
③ ブラウザが「/static/style.css」をリクエスト
④ Flaskがstyle.cssを返す
⑤ ブラウザがHTMLにCSSを適用して表示する

PythonからHTMLへデータを渡そう

app.pyを次のコードへ変更しよう。

from flask import Flask, render_template


app = Flask(__name__)


@app.route("/")
def show_index():
    site_name = "川柳ひろば"
    description = "みんなの言葉で、楽しい川柳を作ろう"
    message = "PythonとFlaskで作ったよ!"

    return render_template(
        "index.html",
        site_name=site_name,
        description=description,
        message=message,
    )


if __name__ == "__main__":
    app.run(debug=True, port=8000)

render_template()は、templatesフォルダにあるHTMLを読み込み、ブラウザへ返すための関数だよ。

return render_template(
    "index.html",
    site_name=site_name,
    description=description,
    message=message,
)

右側はPythonの変数、左側はHTMLで使う名前になっているよ。

Python                         HTML
site_name="川柳ひろば"   →   {{ site_name }}
description="みんなの…"  →   {{ description }}
message="Pythonと…"      →   {{ message }}

テストサーバーが動いている状態で、ブラウザを再読み込みしよう。

HTMLとCSSでデザインされた川柳ページが表示されたら完成だよ!

全体の流れを確認しよう

ここまでの処理を一つにつなげると、次のようになるよ。

① ブラウザで http://127.0.0.1:8000/ を開く
                         ↓
② Flaskのテストサーバーが「/」へのリクエストを受け取る
                         ↓
③ @app.route("/")と結び付いたshow_index()を実行する
                         ↓
④ Pythonでsite_name、description、messageを用意する
                         ↓
⑤ render_template()がindex.htmlへデータを渡す
                         ↓
⑥ Flaskが完成したHTMLをブラウザへ返す
                         ↓
⑦ ブラウザがstyle.cssも取得する
                         ↓
⑧ HTMLにCSSを適用して画面を表示する

改造ミッション

ミッション1:HTMLを変えよう

index.htmlに直接書かれている川柳を、自分で考えたものへ変更しよう。

<div class="senryu">
    <p>ここに上五</p>
    <p>ここに中七</p>
    <p>ここに下五</p>
</div>

変更したら、ブラウザを再読み込みして確認してみよう。

ミッション2:CSSを変えよう

style.cssの色を変更しよう。

変更しやすい場所はここ。

body {
    background: #e8f5e9;
}

.card {
    border: 4px solid #66bb6a;
}

好きな色へ変更して、自分のサイトらしい見た目にしてみよう。

ミッション3:Pythonから渡す文章を変えよう

app.pyの3つの変数を変更しよう。

site_name = "川柳ひろば"
description = "みんなの言葉で、楽しい川柳を作ろう"
message = "PythonとFlaskで作ったよ!"

Pythonの変数を変えると、HTMLの{{ site_name }}などの表示が変わるよ。実際に変更して確かめてみよう。

発展ミッション:2つ目のページを作ろう

早く終わった人は、app.pyのif __name__ == "__main__":より上へ、次のルートを追加しよう。

@app.route("/about")
def show_about():
    return "<h1>このサイトについて</h1><p>川柳を楽しむサイトです。</p>"

ブラウザで次のURLを開く。

http://127.0.0.1:8000/about

/と/aboutで別の関数が実行され、別のページが表示されるか確かめてみよう。

うまく動かないとき

No module named 'flask'と表示される

Flaskが、今使っているPython環境にインストールされていないかもしれないよ。

python -m pip install flask

をもう一度実行してみよう。

TemplateNotFoundと表示される

次を確認しよう。

CSSが反映されない

次を確認しよう。

Address already in useと表示される

別のプログラムが8000番ポートを使っているかもしれないよ。

先に起動したFlaskが別のターミナルに残っていないか確認しよう。それでも使えない場合は、先生の指示に従ってapp.pyのポート番号を変更してみよう。

if __name__ == "__main__":
    app.run(debug=True, port=8001)

変更後、もう一度app.pyを実行してみよう。

python app.py

この場合は、ブラウザで次のURLを開く。

http://127.0.0.1:8001

テストサーバーを停止しよう

授業の最後に、Flaskを実行しているターミナルを選び、Ctrl+Cを押す。

ターミナルへ文字を入力できる状態に戻ったら、テストサーバーは停止できているよ。

サーバーを停止した後にページを再読み込みすると、ブラウザはFlaskへ接続できなくなるよ。実際に確かめてみてね。

まとめ

次回は、HTMLフォームから送った句をFlaskで受け取るよ。

POSTで句をPythonのリストへ保存し、GETで画面に表示してみよう!

参考資料