2022年10月30日日曜日

 


Flask

https://aiacademy.jp/media/?p=57  参照

ふlaskとは

Flask(フラスコ/フラスク)はPythonのWebアプリケーションフレームワークで、小規模向けの簡単なWebアプリケーションを作るのに適しています。
Webフレームワークとは、ウェブサイトやウェブアプリケーションを作るための機能を提供し、ウェブフレームワークを使わない時よりもより容易にWebアプリケーションを作ることができるものです。
ちなみに、PythonにはいくつものWebアプリケーションフレームワークがあり、
例えば、Djnago(ジャンゴ)やpyramid、bottleなど他にもありますが、
この章では、学習コストの低いFlaskを扱って行きます。

Flaskのインストール

pip install flask

Mac OSの方は、ターミナルを起動し、Windowsの方はコマンドプロンプト(cmd)を起動し、上記のpipコマンドにてflaskをインストールしてください。
インストールが終えたら、実際にインストールが成功したか確認します。

確認のため、Pythonの対話型シェルを起動します。
起動するには、pythonコマンドを入力&実行することで、Pythonの対話型シェル(インタラクティブシェル)に切り替えます。
それでは、以下のコードを実行してみましょう。

python

Pythonの対話型シェル(インタラクティブシェル)で入力&実行する部分は>>>の後からです。
次の>>>部分は入力してなくて大丈夫です。

>>> import flask
>>> flask.__version__
'0.12'

バージョンが表示されればインストール成功です。
ターミナルやコマンドプロンプトは一旦閉じて終了してください。
※ターミナルやコマンドプロンプトを終了する場合は、そのまま閉じるか、exit()コマンドを用いることでも終了可能です。
※表示されるバージョンはインストールした時期によってテキストと異なる場合がございます。


 

Flaskを動かしてみる

実際にFlask(フラスク)を動かしていきましょう。
下のプログラムをflask_sample.pyという名前でDesktop(デスクトップ)に保存してください。

from flask import Flask
app = Flask(__name__, static_folder='.', static_url_path='')
@app.route('/')
def index():
    return app.send_static_file('index.html')

app.run(port=8000, debug=True)

※Windows OSをご利用の方で、上記コードがエラーとなる場合、
port番号の部分、debugの部分を次のようにしてみてください。

app.run(port=12345, debug=False)

次に、index.htmlファイルを作ります。
拡張子はHTMLファイルですので、「.html」になります。
この際、index.htmlを保存するディレクトリはflask_sample.pyと同じ階層であることに注意してください。
HTMLに関しては、ドットインストールのHTMLなどを利用し予習してみてください。

<!DOCTYPE html>
<html lang="ja">
<head>
    <title>初めてのFlaskアプリケーション</title>
</head>
<body>
<p>Flask</p>
</body>
</html>

では、ターミナルまたはコマンドプロンプト上で、flask_sample.pyのあるディレクトリまでcdコマンドを用いて移動してみましょう。
*この時、先ほどFlaskのバージョンを表示しているターミナルやコマンドプロンプトは一旦閉じて、再度ターミナルもしくはコマンドプロンプトを起動し、cdコマンドにより移動してください。

移動方法は、cdコマンドを利用します。
Macの方は、ターミナル、Windowsの方はコマンドプロンプト(cmd)を起動します。

cd ~/Desktop

で移動出来ます。
上記コマンドは、Desktopに保存したflask_sample.pyがある想定です。

では、移動出来ましたら次のコマンドでflask_sample.pyを実行しましょう。

python flask_sample.py

ターミナルもしくはコマンドプロンプトに、様々な出力があり、サーバーが起動した状態になります。
localhost:8000にアクセスし、上記の画面が表示されればOKです。

次に、hello関数を実装してみましょう。
*Windowsユーザーの方で、app.run()の引数に、port番号を指定した場合、(例えば、app.run(port=12345, debug=False)など)『localhost:数字』の数字の部分を指定したport番号に変えて実行し直してみてください。

以下のコードをapp.run(port=8000, debug=True)の上に追加します。
この時一番最後の行のapp.run(port=8000, debug=True)の上に記述してください。

@app.route('/hello/<name>')
def hello(name):
    return name

上記コードはブラウザのURLにてlocalhost:8000/hello/python
と入力し、ブラウザにアクセスすると、次のように画面に表示されます。
(*上記リンクを飛ぶと環境によっては、真っ白いページになる場合がありますので、その場合リロード(再読み込み)してみてください。)

@app.routeの関数内の<・・・>の部分に任意の名前(ここでは)を記述することで、その名称を次の関数(ここではhello関数)にてroute内の<・・・>で記述した値を引数として利用することが可能になります。
今回は’/hello/’としましたが、<・・・>の・・・の部分は自由な名称をつけることが可能です。

次にルーティングの説明です。
ルーティングとは、URLとFlaskの処理を対応づけることで、URLと関数を紐付けることが出来ます。
Flaskでルーティングを記述するには、route()を用います。
flask_sample.pyの全体像は次のようになります。

import os
from flask import Flask, url_for

app = Flask(__name__)

# ルーティング
@app.route("/hello")
def hello_world():
    return "Hello world"

@app.route("/")
def index():
    return url_for("show_user_profile", username="ai_academy")

@app.route("/user/<username>")
def show_user_profile(username):
    return "UserName: " + str(username)

@app.route("/post/<int:post_id>")
def show_post(post_id):
    return "Post" + str(post_id)


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

プログラムの解説を致します。
まずは、何もrouting設定しなかった場合、show_user_profile()という16行目で定義した関数が走ります。
引数では、username=”ai_academy”が渡され、表示は以下のようになります。
http://127.0.0.1:8000/

次に以下のURLにアクセスしてください。
http://127.0.0.1:8000/user/AI
ここでURLの中にある、AIの部分を変えて挙動を確認してください。

次に、 http://127.0.0.1:8000/hello では、Hello World!が出力されるのをみてください。

次に、型を指定したURL参照をしてみましょう。数値123を他の値に変えることで参考にできます。
URLは http://127.0.0.1:8000/post/123 をみてください。

flask側で型を固定してあるので、違う型のものを入れるとエラーが出るかと思います。
URLは http://127.0.0.1:8000/post/test をみてください。

サーバ側のプログラムをPython(Flask)で記述することで、動的な処理ができるようになります。
なお、「動的な動き」という表現はよく聞きますが、対照的なものとして、「静的な動き」という表現があります。
例えばhtmlファイル(index.html等)は静的なファイルですので、記述されたことが表示されるだけで、動的な動きはしません。
こちらに何かしらの値を、サーバー側から出力させたいときに動的な動きをさせる必要があります。

https://aiacademy.jp/bootcamp/


render_templateによる読み込み

Flaskでは、render_template関数を使う方法でも、htmlファイルを表示させ、htmlファイルに簡単に値を入れることができます。
render_templateを使う場合には、importによる記述と、templatesフォルダを新たに作成しそこにhtmlファイルを置きます。
render_templateを用いる際には、templatesフォルダを作成する必要があり、作成していないとhtmlファイルを読み込むことが出来ませんのでご注意ください。

まずは、階層を以下のように作ってください。

- app.py(flaskでサーバー処理を行うpythonファイル)
- templates(HTMLファイルが沢山入るフォルダ)
    └ index.html
    └form.html

app.pyを以下の内容を記述し、保存してください。

from flask import Flask,render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', message="花子さん")

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

※Windows OSをご利用の方で、上記コードがエラーとなる場合、
port番号の部分、debugの部分を次のようにしてみてください。

app.run(port=12345, debug=False)

また、Jupyter Notebookを用いてFlaskを動作させる場合、
合わせて、if name == “main“:の部分をコメントアウトし次のようにしてみてください。

from flask import Flask,render_template

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', message="花子さん")

app.run(port=12345, debug=Falase)

続いて、templatesフォルダ内にindex.htmlを作成して以下コードを記述し、保存してください。

<!DOCTYPE html>
<html>
<head>
  <title>flask練習</title>
</head>
<body>
  <h1>こんにちは{{ message }}</h1>
</body>
</html>

では、再度ファイルの構成を確認してみましょう。
上記で作成したコードは次のようになっていますでしょうか?

- app.py(flaskでサーバー処理を行うpythonファイル)
- templates(HTMLファイルが沢山入るフォルダ)
    └ index.html

上記の構成であれば、app.pyを起動し動作確認してみましょう。

Mac OSの方は、ターミナルを起動し、Windowsの方はコマンドプロンプト(cmd)を起動し、以下のコマンドを実行してみましょう。

python app.py

その後、ターミナル(もしくはコマンドプロンプト)の方に、次のようなログが出力されていれば、OKです。

 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Running on http://127.0.0.1:8000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 284-231-902

http://127.0.0.1:8000/にアクセスしてみると、以下のように出力がされるはずです。

このように簡単に静的ファイル(htmlファイルで作成したページのこと)にサーバー側から値を出力することに成功しました。

htmlで入力されたデータをpythonで扱う

例えば、以下のようなログイン画面を見たことはないでしょうか?

こういったログイン機能では、LoginID(もしくはユーザー名など)とPasswordの正しい値を入力すると、次の画面に遷移し、正しくない入力をすると、「正しく入力をしてください」などと表示されます。
実現方法としては、HTML上に入力された値をサーバーサイドにPOSTで送ることによって、その値がデータベースのものと正しいかどうか参照することによって、機能は実装できます。
POSTとは、HTTP通信の、データを送る際の手段の一つです。
HTTP通信については深くはここでは触れませんので、詳しくは、こちらをご覧ください。

では、どのようにデータをflask側に送れば良いのでしょうか?
データを送る際には、formタグの中にinputタグを入れればOKです。実際にコードを見てみましょう。

<!DOCTYPE html>
<html>
<head>
  <title>form練習</title>
</head>
<body>
  <form method="POST">
    <input type="text" name="id" placeholder="userID">
    <input type="password" name="pwd" placeholder="Password">
    <input type="submit" value="送信">
  </form>
</body>
</html>

このファイルをform.htmlなどで出力をさせると以下のようになります。

次に、こちらのファイルから受け取ったデータをpythonで扱えるようにしましょう。
flaskで作るので、templatesフォルダに今作成したform.htmlを入れてください。
さらに、そのrender_templatesの上の階層にlogin.pyというファイルを作り以下のように記述してください。

また現状の構成は次の通りです。

- app.py(flaskでサーバー処理を行うpythonファイル)
- login.py(今作成したlogin.py)
- templates(HTMLファイルが沢山入るフォルダ)
    └ index.html

app.pyは先ほど作成したファイルですので、この後は使用しません。

次のコードはこれから作成するlogin.pyの中身です。

from flask import Flask, request,render_template

app = Flask(__name__)

# login処理です
@app.route('/', methods=['GET', 'POST'])
def form():
    # 2回目以降データが送られてきた時の処理です
    if request.method == 'POST':
        print("POSTされたIDは?" + str(request.form['id']))
        print("POSTされたPASSWORDは?" + str(request.form['pwd']))
        return render_template('form.html')
    # 1回目のデータが何も送られてこなかった時の処理です。
    else:
        return render_template('form.html')

# アプリケーションを動かすためのおまじない
if __name__ == "__main__":
    app.run(port = 8000, debug=True)

ここで、このlogin.pyを先ほどと同じ方法で実行し、起動してましょう。
その後、ブラウザの画面http://127.0.0.1:8000/では、次のような表示になります。
その画面のテキストフィールドの中に、何かしらの値を入れて送信ボタンを押してみてください。

ターミナルやコマンドプロンプト上では以下のように出力がされます。

これで、HTMLに入力された値もpythonで扱えるようになりました。

Webサービスの構成とAPIサーバー

近年Webサービスを作る上で、幾つか異なる役割を持ったサーバ構成になっています。
例えば、ユーザー情報を管理するDBサーバや、APIサーバー、またはWebサーバーや画像サーバなどで構成されています。
APIサーバはクライアントからHTTPもしくはHTTPSリクエストを受けとり、そのリクエストのパラメータに従って処理を行い、DBサーバーから情報を受け取り、クライアントにレスポンスを返します。

Web API (JSON API)

ここでは、Flaskを使ってWeb APIを作ってみます。
まずはイメージをして頂きたいので、簡単なものを作ってみます。
ファイル名は任意で構いません。(login_api.pyなど好きな名前で作成してください)

from flask import Flask
import flask

app = Flask(__name__, static_folder='.', static_url_path='')

@app.route('/')
def index():
    return app.send_static_file('index.html')

@app.route("/mypage")
def mypage():
    # login = False
    login = True
    if login is False:
        return flask.jsonify({
            "code" : 400,
            "msg"  : "Bad Request"
        })

    user_data = {"user_name": "ai_academy"}
    return flask.jsonify({
        "code": 200,
        "msg" : "OK",
        "result": user_data
    })


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

上記コードを記述出来ましたら、以下コマンドを実行してください。

python login_api.py

変数loginの初期状態がTrueですので、ここでは既にログインをしていることを意味しています。
ですので、ログイン成功したことを意味するjsonが出力されています。

では、変数loginの値をFalseにしてみてください。

このように、JSONの出力が変わっていることが確認できます。
上記プログラム内でflask.jsonifyというのを使用していますが、
これはPythonの辞書型をJSONの文字列に変換し、必要なレスポンスヘッダー等も自動で設定してくれます。

まとめ

この記事では、Flaskとは何か?またFlaskの基礎を学び、HTMLにデータをどのように渡すか、どのようにHTMLで入力された値を扱うかを学びました。
本記事で学んだFlaskと合わせて、この記事では解説しておりませんが、HTML/CSS/JavaScriptを合わせることでWebアプリケーションを作ることが可能です。
Webアプリケーションの制作をしてみた方は、是非Web開発にチャレンジしてみてください。

2022年9月12日月曜日

magick packet

 


https://irukanobox.blogspot.com/2017/08/raspberry-pipython3pc.html  参照

Raspberry PiとPython3でPCを起動する

多くのPCにはWake On LAN(WOL)という機能があって、ネットワーク越しにマジックパケットという指定のパケットを送ると、PCの電源を入れることができる。Raspberry PiからPython3でマジックパケットを送り、Windows10 PCの電源を入れてみる。

Raspberry PiのOSはRaspbian Jessie、Python3のバージョンは以下の通り。


Windows機側でWOLを有効にするにはBIOS/UEFIとOSのLANコントローラドライバの設定が必要で、その方法についてはWake On LANでコンピュータを起動する を参照。

マジックパケットというのは、6個の0xFFとパケットを受信する側のMACアドレス16個からなる計102バイトのデータを含むパケット。MACアドレスがAA:BB:CC:11:22:33の場合、FFFFFFFFFFFFAABBCC11223344AABBCC...のようなイメージになるが、実際はバイナリデータなので、Python3のprintで出力すると、「b'\xff\xff\xff\xff\xff\xff\xaa\xbb\xcc\x11"3\xaa\xbb\xcc\x11"3\xaa\xbb\xcc...」のように、\x~とASCII文字が混在したものになる。

パケットの送り方は特に決まっていないが、UDPとブロードキャスト、ポート番号は7か9を使うのが一般的らしい。ブロードキャストアドレスには、255.255.255.255とIPアドレスのホスト部のビットがすべて1のアドレスがあるが、ルータを越える必要がなければ255.255.255.255で問題ないので、ここでは255.255.255.255を使う。

MACアドレスがAA:BB:CC:11:22:33の端末にマジックパケットを送るPython3のコード。
sample.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import socket
import binascii
 
# MACアドレス
MACADDR = 'AA:BB:CC:11:22:33'
# ブロードキャストアドレス
BCADDR = '255.255.255.255'
# 宛先ポート番号
PORT = 7
 
macstr = ''.join(MACADDR.split(':'))
mdata = 'FF' * 6 + macstr * 16
# 16進数表記の文字列を表すバイナリデータに変換
mdata = binascii.unhexlify(mdata)
 
# ソケットの作成
# 第一引数: アドレス (およびプロトコル) ファミリーを示す定数
# socket.AF_INETのときは(host, port)
# 第二引数: ソケットタイプ、UDPならSOCK_DGRAM、TCPならSOCK_STREAM
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
# ブロードキャストを使用するための設定
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
 
# ソケットにデータを送信
s.sendto(mdata, (BCADDR, PORT))
 
s.close()

Windows PCをスリープ状態にして、Raspberry PiのPython3で上記スクリプトを実行すると、Windows PCがスリープからめでたく復帰。

LANコントローラによっては、シャットダウンした状態でもマジックパケットを受け取れるものもあるらしいが、残念ながら家のPCではできなかった。

MACアドレスを引数として渡せるようにして、MACアドレスチェックを追加したスクリプトを作成。(2017.9.30)
"""
Send magic(WOL) packet
"""
import socket
import binascii
import sys
import re
# Broadcast address
BCADDR = '255.255.255.255'
# Port
PORT = 7
def macstr(macaddr):
"""
Check the validity of the MAC address
"""
if len(macaddr) == 17:
maclist = macaddr.split(':')
if len(maclist) == 6:
if len(list(filter(lambda x: re.match('^[0-9a-fA-F]{2}', x), maclist))) == 6:
return ''.join(maclist)
print('Invalid MAC address: ' + macaddr)
exit()
def main():
params = sys.argv
if len(params) != 2:
print('Usage: python3 wol.py [MAC address]')
print('e.g.')
print('python3 wol.py AA:BB:CC:11:22:33')
exit()
mdata = 'FF' * 6 + macstr(params[1]) * 16
print('Sending a magic packet to ' + params[1])
# Convert into binary data represented by hexadecimal string
mdata = binascii.unhexlify(mdata)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.sendto(mdata, (BCADDR, PORT))
s.close()
if __name__ == '__main__':
main()
view rawwol.py hosted with ❤ by GitHub