[Python初心者向け]Bottleの使い方


[Python初心者向け]Bottleの使い方

Python 3大フレームワークの1つ "Bottle"。

今回は、 Bottle の基本情報を抑えて、簡単な Webアプリケーションを作ってみたいと思います。

本稿は、 Python の基礎を習得済みの方を対象としています。予め、ご了承ください。
目次
  1. Python初心者向け_Bottleの使い方
  2. Bottleとは
  3. Bottleを扱う様子の動画
  4. Bottleをインストール
  5. BottleでHelloWorld
  6. Bottleでログイン・プログラム
  7. Bottleで計算プログラムのサンプル
  8. Bottleで株価データを取得する例
  9. ポートエラー対策(OSError: [Errno 98] Address already in use)
  10. まとめ

Python初心者向け_Bottleの使い方

Bottleとは

image

http://bottlepy.org/docs/dev/

"Bottleボトル" は、Python製の Webフレームワークで、 「Python で Webサイト」、 「Python で Webアプリ」 と考えた時に一番最初に登場してくるモノ。 Bottle は、 2009年ドイツ人のエンジニア Marcel Hellkampさんが 27歳?の時に開発したモノで、 GitHub上で MIT ライセンスで公開されています。

フレームワークというと "複雑なファイル構造" "たくさんの機能" といったイメージがありますが、こちらの Bottle は必要最低限の機能のみ。 "シンプル"、 "早い" "軽量" に開発されている特徴があります。とはいいましても、 Bottle の動きを制御するメインファイル bottle.py は、 4,427行からなるスゴイプログラム。

また参考までに他の Python Webフレームワークと比較すると、イメージ的には Bottle は "どんぶり" や "ラーメン" といった感じ。 一品料理といいますか、単発的なアプリ開発の利用に長けています。他の Flask は、定食、 Django は フルコース といった感じで、それぞれにメリット・デメリットが。

それでは実際に Bottle をローカル環境で実行してみましょう。

Bottleを扱う様子の動画

本稿でご紹介するプログラムを実行する様子です。本テキストと合わせてご参照ください。

本稿で使用するコード: GitHub

Bottleをインストール

今回は "ファイル操作" と "コマンド操作" 両方が行える Visual Studio Code を使って作業していきます。

まずはテスト用のディレクトリを作成し、仮想環境を構築。それから pip install していきます。

上図のコードを見る

python3 -m venv myenv
source myenv/bin/activate
pip list
pip install --upgrade pip

仮想環境の作成ができたら、 Bottle公式ページにも書いてある pip install を実行。

上図のコードを見る

pip install bottle
pip list

もう Python の標準ライブラリにした方がいいんじゃないか、というぐらいサクッと入ると思います。

【Anaconda の仮想環境に bottle をインストールする場合】

conda install -c conda-forge bottle

pip install に比べると時間がかかりました。
https://anaconda.org/conda-forge/bottle

BottleでHelloWorld

上図のコードを見る

from bottle import Bottle, run

app = Bottle()

@app.route('/hello')
def hello():
    return "Hello World!"

run(app, host='localhost', port=8080)

参考ドキュメント: http://bottlepy.org/docs/dev/tutorial.html#quickstart-hello-world

それでは Bottle の公式ドキュメントで紹介されている Hello World から始めてみましょう。

hello.py という任意の Python ファイルを作成し、ドキュメントに書かれているコードをコピペ。ファイルを保存して、プログラムを実行してみます(下図)。

すると http://localhost:8080 にアクセスしてください、とメッセージが出るのでアクセスしてみると上図のようにエラーが。最初は焦りますが、大丈夫です、 URL を http://localhost:8080/hello に変更してみてください(下図)。

するとプログラムに書いている通り "Hello World" という文字が表示。このような形で Bottle を使う場合は、出力先を明示的に書く必要がありますね。 Bottle は "WSGI" という Webサーバー・ゲートウェイを使っているためこのような形で、 これが Apacheサーバーだったらディレクトリが表示されたりしますよね。

WSGI は、 Bottle 以外の Flask や Django などでも使われていますので、慣れておくとよさそう。

さて参考ドキュメントを進めていくと、次は /hello/<name> という書き方が。

上図のコードを見る

from bottle import route, run

@route('/')
@route('/hello/<name>')
def greet(name="Stranger"):
    return template('Hello {{name}}, how are you?', name=name)

run(host='localhost', port=8080, debug=True)

新しい Pythonファイル name.py を作成し、先ほど同様コードをコピペして実行してみます。

するとまたエラーが、エラー文を見てみますと、

NameError: name 'template' is not defined

どうも "template" がないとのこと。公式ドキュメントのコードをコピペしているだけなのにエラーになるのはチョット焦りますが、下図のように import 部分に "template" を足すとエラーを解決できます。

上図のコードを見る

from bottle import route, run, template

@route('/')
@route('/hello/<name>')
def greet(name="Stranger"):
    return template('Hello {{name}}, how are you?', name=name)

run(host='localhost', port=8080, debug=True)

5行目の name='Stranger' という部分が、表示画面に出力されている様子が確認できます。これは 6行目の return 文で template() が使用され、 greet() 関数の引数が割り当てられているため。このように template() と 引数を使うことで、ページ内の文字を "動的" に扱えますね。

そして greet() 関数内の引数は、ルートにも割り当てることができ、

<name> = name = 'Stranger'

という関係に。ユーザー管理画面などでよく URL 内にユーザー名があって、管理画面にユーザー名がある Webサイトってありますよね、それと同じような仕組み。ユーザー管理以外にも、株価や商品を管理したい時にこうした Web構成って扱いやすそうです。

ルート設定が、 //hello/<name> でかぶっていましたので、下記のように別処理をするようにセットしてみました(下図参照)。

上図のコードを見る

from bottle import route, run, template

@route('/')
def hello():
    return "Hello World!"

@route('/hello/<name>')
def greet(name="oshima"):
    return template('Hello {{name}}, how are you?', name=name)

run(host='localhost', port=8080, debug=True)

ちなみにプログラムで登場してくる def hello():def greet(): などの関数名、これは任意の名称で hello() でなくても h() でも動作します。自分で解りやすいように関数名設定しておくといいですね。


Bottleでログイン・プログラム

上図のコードを見る

from bottle import get, post, request

@get('/login')
def login():
    return '''
        <form action="/login" method="post">
            Username: <input name="username" type="text" />
            Password: <input name="password" type="password" />
            <input value="Login" type="submit" />
        </form>
    '''

@post('/login')
def do_login():
    username = request.forms.get('username')
    password = request.forms.get('password')
    if check_login(username, password):
        return "<p>Your login information was correct.</p>"
    else:
        return "<p>Login failed.</p>"

run(host='localhost', port=8080, debug=True)

再び参考ドキュメントを進めていくと次は、ログインに関するサンプル。今まで同様に新しく Python ファイルを作成し、コードをコピペ、そして実行。すると今度は run がないとのこと。

NameError: name 'run' is not defined

上図のコードを見る

from bottle import get, post, request, run

@get('/login')
def login():
    return '''
        <form action="/login" method="post">
            Username: <input name="username" type="text" />
            Password: <input name="password" type="password" />
            <input value="Login" type="submit" />
        </form>
    '''

@post('/login')
def do_login():
    username = request.forms.get('username')
    password = request.forms.get('password')
    if check_login(username, password):
        return "<p>Your login information was correct.</p>"
    else:
        return "<p>Login failed.</p>"

run(host='localhost', port=8080, debug=True)

import 文に run を加えて実行すると、今度はエラーなくプログラムが実行できました(上図参照)。そして Username と Password 欄に任意の文字を入力して、ログインボタンを押してみると...

エラーになって、エラー文を確認すると

NameError: name 'check_login' is not defined

これはプログラム 17行目の check_login() 関数が設定されていないためのエラー。 check_login() は、ログインの入力事項が正しいかどうか確認する関数で、自分でセットする必要が。本来はデータベース内のデータと整合する必要が出てきますが、今回は簡易的に以下のように処理。

上図のコードを見る

from bottle import get, post, request, run

@get('/')
def login():
    return '''
        <form action="/login" method="post">
            Username: <input name="username" type="text" />
            Password: <input name="password" type="password" />
            <input value="Login" type="submit" />
        </form>
    '''

@post('/login')
def do_login():
    username = request.forms.get('username')
    password = request.forms.get('password')
    if "username" == username and "password" == password:
        return "<p>OKOKOK</p>"
    else:
        return "<p>❌.</p>"

run(host='localhost', port=8080, debug=True)

【17行目】
if "username" == username and "password" == password:

すると今度は、 ログイン画面で Username と Password に usernamepassword と入力するとログインに成功。 このプログラムは、ユーザー管理をはじめ、Webページにパスワードを設けたい時にも応用できるでしょう。

Bottleで計算プログラムのサンプル

上図のコードを見る

from bottle import get, post, request, run

@get('/')
def circle_area():
    return '''
        <form action="/calc" method="post">
            半径は何cm? <input name="radius" type="text" />
            <input value="計算" type="submit" />
        </form>
    '''

@post('/calc')
def circle_area():
    r = request.forms.get('radius')
    print(type(r))
    calc = int(r) * int(r) * 3.14
    return "円の面積:" + str(calc) + "cm2"

run(host='localhost', port=8080, debug=True)

先ほどのログイン・プログラムを応用すると、入力に対してのリアクションを得ることができそう。試しに円の面積を計算してくれるプログラムを作成してみました(上図参照)。

まず円の半径を入力するプログラムが 3〜10行目で、計算および計算結果出力部分が 12〜17行目。入力値の半径は、変数 radius に割り当てられて、 計算ボタンの "submit" を押すと、 action="/calc" method="post" によって 14行目のプログラムに radius が渡されます。 そして 14行目で radius は 変数 r に代入されて、 16行目で計算。その計算結果は、 17行目で出力という形。

今回は円の面積だけですが、他の計算式なども足すとチョットした演算アプリが作れますね。

Bottleで株価データを取得する例

上図のコードを見る

from bottle import route, run, request
import requests
import json

@route('/')
def hello():
    return "こんにちは"

@route('/225')
def greet():
    response = requests.get('https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=^N225&interval=5min&apikey=T8ST9ZM5WP7JNMNG')
    data = json.loads(response.text)
    print(data.keys())
    data = data["Time Series (5min)"]
    latest_date = sorted(data.keys())[-1]
    stock_price = data[latest_date]["4. close"]
    return "アメリカ東部時間: " + latest_date + "の 日経225 の最新株価: " + stock_price

run(host='localhost', port=8080, debug=True)

Bottleで入力や演算ができると、 API を使ってデータ取得もできないか、気になりますよね。試しに 日経225 の株価データを取得するプログラムを作成してみました(上図参照)。

APIの取得については、こちらの動画を参照いただくとして、結果的に少々タイムラグがあるものの株価データを取得できました。

こうしたデータを応用すれば、株価上昇ランキングや割安銘柄ランキングなどチョットした Webアプリを作れそうですね。

ポートエラー対策(OSError: [Errno 98] Address already in use)

Bottle のプログラムを実行すると http://localhost:8080 が開くわけですが、プログラムの閉じ方を誤ると、次に Bottle プログラムを実行した時にポートエラーがでます。

  • 正しいプログラムの終了ボタン Ctrl + Cボタン
  • よく間違える終了ボタン Ctrl + Zボタン

  • ポートエラー文 [Errno 98] Address already in use

ポートエラーについては、違うポート番号を割り当てたりいくつかの解決方法はありますが、 以下のコマンドを実行すると 8080 を強制終了できます。

kill -9 $(lsof -t -i:8080 -sTCP:LISTEN)

AIエンジニアに必要なスキルが身に付く

無料カウンセリングはこちら

まとめ

Pythonの Bottle、シンプルとは言うけれども、いろいろ使えて楽しいですよね。ただページ数が増えてきたり、データベースが絡んでくるとやや扱いにくいかもしれません。単発的な機能ではなく、複数の機能、プログラムを実行したい場合は、 Flask や Django の方が扱いやすいかもしれないですね。

"Pythonの基礎はマスターしたけれど、その先がない..." "Pythonは社会人に人気って言うけれど、副業には向かないのではないか..." と思われている方、今回の Bottle がヒントになるのではないでしょうか? 単に Bottle を試すだけなら Pythonanywhere などの Webサービスも便利。

「イヤイヤ、 Python の参考書買ったけれども、開いた瞬間に眠くなる...」 「Python自体の設定ができない...」 と 手 と 時間 が止まっている方、学習環境、一度見なおしてみませんか?

一人では難しいならプロ、つまりプログラミング・スクールに頼ってみるというのがスジ、ではないでしょうか? 「イヤイヤ、そんなにお金をかけられない」 「時間がない」 、いろいろあると思いますが、テクノロジーの進化は止まっている私達を待ってくれません、置いていかれます...

今後も安心して仕事や生活に専念していきたいというのなら、ちょっと勇気をだして、やろうとした Python、やり遂げてみませんか? オンラインスクールの CodeCamp では、無料体験を通じて、スクールの価値を体感頂いております。 "無料体験" ご興味ある方は、 公式ページ よりチェックしてみてください。

昨今のプログラミング・ニーズの高まりを受けて、無料体験枠が埋まっている日もあります。予め、ご了承ください。


オシママサラ
この記事を書いた人
オシママサラ
まずは7日間お試し!人気プログラミング講座を無料公開中
オンライン・プログラミングレッスンNo.1のCodeCamp