Flask-RESTfulにおける文字化け対策
flask-restfulで日本語を扱うときに、日本語が文字化けするのでその対処法。
例えば、以下のようなAPIを作成してアクセスした場合
#!/usr/bin/env python # coding: utf-8 from flask import Flask from flask_restful import Resource, Api app = Flask(__name__) api = Api(app) class HelloWorld(Resource): def get(self): return {'hello': 'ワールド'} api.add_resource(HelloWorld, '/') if __name__ == '__main__': app.run(debug=True) || >|python| @api.representation('application/json') def output_json(data, code, headers): resp = make_response(json.dumps(data, ensure_ascii=False), code) resp.headers.extend(headers) return resp
以下のように表示される。
{ "hello": "\u30ef\u30fc\u30eb\u30c9" }
そこで、文字化け対策する場合は、以下のようなコードの追加を行う。
#!/usr/bin/env python # coding: utf-8 from flask import Flask, make_response #モジュールの追加 from flask_restful import Resource, Api, reqparse #モジュールの追加 import json #モジュールの追加 app = Flask(__name__) api = Api(app) @api.representation('application/json') #追加 def output_json(data, code, headers): resp = make_response(json.dumps(data, ensure_ascii=False), code) resp.headers.extend(headers) return resp class HelloWorld(Resource): def get(self): return {'hello': 'ワールド'} api.add_resource(HelloWorld, '/') if __name__ == '__main__': app.run(debug=True)
すると
{"hello": "ワールド"}
と無事正確に表示される。
どうやら、上記のoutput_jsonで、jsonのアウトプットを設定できるミドルウェアが組めるみたい。
詳しくは参考記事で。
参考記事
ニコ動のごちうさ1話のコメントでword2vecで遊んでみた
ふと、ごちうさ1話のコメントから、いわゆる"ごちうさ難民"の人工知能を作れないかと思い行動。
今回は、趣旨が違って、拾ったコーパスをword2vecに通したらどうなるかのお遊びだけ。
コーパス
ニコニコ動画のコメントはドワンゴより以下のようなデータが提供されています。
が、ごちうさ1話のコメントを取るには古すぎたので、自分でスクレイピングしました。
その際に普通にスクレイピングしても取れなさそうなので、Seleniumを使いました。
スクレイピングの方法としては
- ログインが必要になるので、自分のアカウントでログイン
- ごちうさ1話の動画へ移動
- コメントが読み込まれるまで待機
- コメントが読み込まれたらスクロールしながらコメントのDOM情報をMongoDBに保存
という手順をSeleniumで組みました。このクローラーを1日に1回のペースで回し、約35000件のコメントを保存しました。
なおコメントに加えて、コメントの投稿時間や、コメントの投稿した再生時間も保存してあります。
ソースコードは以下に用意しました。READMEとかまだできていないですが参考にしていただければと。
githubの src/gochi_usa_scrape.py が実行スクリプトとなっています。(環境変数にユーザー名のパスワードの設定必要あり)
スクレイピングに関して
今回行った成果は、以下を参考にしたうえで行いました。
robots.txtの内容も確認いたしました。
当成果に対して何か問題があればご連絡お願いします。
Webスクレイピングの注意事項一覧 - Qiita
Webスクレイピングの法律周りの話をしよう! - Qiita
niconico利用規約 - niconico
分かち書き
こういうデータを使う際には決まって文を単語に分ける分かち書きという作業が必要があります。
その際には、形態素解析器mecabと、すげえmecabの辞書mecab-ipadic-neologdを用いました。
この辞書、アニメの単語とか本当に理解してすごいです。
mecabのインストール
brew install mecab brew install mecab-ipadic
また、python3で処理をしたので以下のようにライブラリをインストール
pip install mecab-python3
mecab-ipadic-neologd
以下の記事を参考にしてインストール
mecabはインストール済みなので
git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git cd mecab-ipadic-neologd ./bin/install-mecab-ipadic-neologd
python上でmecab-ipadic-neologdを使う場合は
mt = MeCab.Tagger('-Ochasen -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd')
と、タガーを定義する際に引数に辞書を指定する必要があります。
また、今回のコーパスは複数行にわたるAAが顕著に見られました(しかも各行が分けられて撮ってきている)
よって、形態素解析及び分かち書きの際は、文中の"記号"が6割以上超えた場合にコーパスから排除するという処理を行いました。
コードしてはこんな感じ。sent_parser関数が文の分かち書きで、parser関数が複数の文をまとめて分かち書きできる。
#!/usr/bin/env python # coding: utf-8 import MeCab def surface_iter(node): #「文頭」を無視 node = node.next while node.next: yield (node.surface, node.feature) node = node.next def sent_parser(sentence): dic = '/usr/local/lib/mecab/dic/mecab-ipadic-neologd' config = '-Ochasen' config += " -d {}".format(dic) mt = MeCab.Tagger(config) mt.parse('') node = mt.parseToNode(sentence) parsed = surface_iter(node) try: parsed = list(parsed) surfaces, features = zip(*parsed) new_surfaces = [sur for sur, fea in parsed] n_kigou = len([x for x in features if '記号' in x]) score = n_kigou / len(features) return new_surfaces if score < 0.6 else [] except ValueError: # zipに失敗したものは排除。 return [] def parser(docs): parsed = map(sent_parser, docs) parsed = [x for x in parsed if x] return parsed
word2vec
gensimのword2vecを使って類似度計算を行いました。
word2vecによって、単語をベクトル表現することができ、コサイン類似度で単語の類似度を調べることができます。
"word2vec"についてわからない人は、ググると出てくるので是非ググってください。有名なモデルです。
類似度計算の際は、上記のコードの関数で分かち書きした単語列の頭に投稿した再生時間を示す記号を投入。
(例えば、再生時間01:00に投稿されたものはTM_01という記号を入れる)
具体的に、コードにするとこんな感じ(x['time'][:2]がコメントの投稿した再生時間(分単位)、x['parsed']は分かち書きしたコメント)
[['TM_' + x['time'][:2]] + x['parsed'] for x in result]
こういう細工をすることで、各再生時間で使われる単語を見ることができてニヤニヤできますw
ちなみに、各コメントを3つにコピーしてかさ増ししました。
word2vecにかけて、類似度計算をしてみた結果。
川の類似度。表示結果は川と類似する単語です。川に対して詳しい。
EUの類似度。類似する単語がめっちゃタイムリー。
濃度の類似度。空気と関係していたり薄くなったり不穏。
TM_16のデータをかさ増ししていないモデルの結果で。この時間は弾幕が濃い。
同じくかさ増しせずにTM_22。線路へほっぴんジャンプ♪
TM_○○の類似度はかさ増ししない方が面白い結果が出ました。
cordovgaのチュートリアル
cordovaのチュートリアル(下記)をやってみましたが、うまくいかなかった点が幾つかあったのでメモ。
インストール
npm -g cordova
プロジェクト作成
cordova create workshop com.yourname.workshop Workshop
cordova createに続く引数はそれぞれ、プロジェクトのディレクトリ、プロジェクトの識別子、プロジェクト名です。
プラットフォーム設定
cd workshop cordova platforms add ios cordova platforms add android
プラグインの設定
そのまま入力してもうまくいかなかったので、ググったらURLから直接とってくる必要があるとのこと。
cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-device.git cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-console.git
iOSのエミュレート
OSXの場合は、Xcodeが必要となります。インストールし忘れて手詰まった。
インストールした後も、起動して初期設定しないとうまくいかないので注意。
cordova emulate ios
Androidのエミュレート
Android SDKが必要となります。私は、Android SDKは Android Studioからダウンロードしました。
Android Studioをインストールして起動。その後、PreferenceでAndroidのSDKの項へ移動してSDKパスを確認。
下記の画像でハイライトされている項です。
確認したパスは、以下のように~/.bash_profileに追加。
### Android SDK export ANDROID_HOME=/path/to/Android/sdk
その後エミュレートのコマンド
cordova emulate android
を叩いても
Hint: Open the SDK manager by running: /Users/yterazawa/Library/Android/sdk/tools/android You will require: 1. "SDK Platform" for android-23 2. "Android SDK Platform-tools (latest) 3. "Android SDK Build-tools" (latest)
とエラーが出るので、指示通り処理を実行。また、一覧にandroid-23がなかった場合。設定の
Appearance & Behavior > System Settings > Android SDK
よりインストール。私の勘違いで、一覧にあるのかもしれない。
しかし、上記の処理をしてもエラー。
Error: No emulator images (avds) found. 1. Download desired System Image by running: /Users/yterazawa/Library/Android/sdk/tools/android sdk 2. Create an AVD by running: /Users/yterazawa/Library/Android/sdk/tools/android avd HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver
また上記の作業を実行したらエミュレータが起動しました。
その他
後は、チュートリアルのページの通りに手順を踏んでうまくいきました。
話が変わりますが、cordova上で、react-routerが使えない。下記を参考にしてもうまくいかなかったので誰か教えてくれると幸いです。
pythonのWebアプリをデプロイするためのIaaS入門に必要になった知識
さくらインターネットさんのさくらのクラウド2万円無料券があったのと、line botを作りたくなったり、elasticsearchが使いたくなったのでさくらのクラウドを使用。
そこで、IaaSを使うのに、Unixサーバの知識とかいろいろ必要で苦労したのでやったことをまとめ。とりあえずAWS使ったほうが楽そうだった...
ちなみに、今回はUbuntu16.04を使いました。
ここで説明する知識は
です。最小限の公開ならばSSL証明書は必要ないですが、line botの作成に必要になったので記載。ページの信頼性の向上もできますし、覚えて損はないかと。
(2016/6/19追記:経験したトラブルへの対策も書きました)
サーバー設立
nginxを使用。
sudo apt install nginx
インストールしたサーバーのIPにアドレスに接続すれば、Welcome to nginx!のページが表示されるはず。
サーバーの設定には、/etc/nginx/nginx.confという設定ファイルや/etc/nginx/conf.d/以下、/etc/nginx/site-enable/以下にある設定ファイルを編集・作成で。
ちなみに、nginxを使った時に面倒だったのがnginxの再起動や停止など。頻繁に使いました。エイリアス書くと楽かも。
sudo nginx # 起動 sudo nginx -s stop # 停止 sudo nginx -s reload # 再起動
systemdの使い方
サーバーなどの自動起動に使いました。
よく使うコマンドや実際にsystemdを使った例を記載します。
よく使ったコマンド
sudo systemctl restart # systemctlの再起動
elasticsearchの自動起動
ubuntu16.04でもaptでインストールしたelasticsearchに専用の設定ファイルも用意されているので
systemctl enable elasticsearch.service
で稼働可能に。詳しい適用の仕方は以下のURLにて。
サーバーアプリ公開(python)
pythonだとgunicornを使うのがクッソ楽だった。ちなみに今回使ったpythonのバージョンはは2.7.11。
gunicornのインストールはpipで。ちなみにvirtualenvは使っていません。
sudo pip install gunicorn
例えば、bottleなんかでサーバーを作る際は下記のようなコードを書きます。
#!/usr/bin/env python # coding: utf-8 from bottle import request, route, default_app @route('/') def hello(): return 'Hello world!' app = default_app()
このコードを /var/www/app.py として保存した場合、
systemdでgunicornを自動起動させるスクリプトは下記のようになりますね。
#!/bin/bash PID=/var/run/gunicorn.pid if [ -f $PID ]; then rm $PID; fi cd /var/www/app.py exec gunicorn app:app --pid=${PID}
runapp.shという名前で保存したスクリプトをsystemdで自動起動をさせるスクリプトを書く
[Unit] Description=gunicorn After=syslog.target [Service] ExecStart=/path/to/runapp.sh Restart=always KillSignal=SIGQUIT Type=notify StandardError=syslog NotifyAccess=all [Install] WantedBy=multi-user.target
設定ファイルの書き方はどこかから参考にしたのですが、どこか忘れた・・・参考記事さんごめんなさい。
無料DNS
サーバードメインが決まらなかったので、freenomという無料のDNSサービスを利用。こちらもお試しに使いたかったので。
さくらのクラウドのサーバ一覧より、発行してもらうサーバの詳細画面に移動し、NIC項へ移動、そこでIPアドレスを確認することができます。
登録には数分かかります。しばらくしたら、発行したドメインより、サーバのホームページに移動できるはずです。
SSL証明書
試したかっただけなので、無料のSSL証明書を発行。Let's encryptを使いました。
ちなみに、Line bot を制作するのに、Let's encryptは使えないとのことでしたが、2016年6月時点ではLet's encrpytの証明書でもbotが作れました。
SSL証明書の取得にはホスト名が必要なので、freenomなどであらかじめ取っておきましょう。
インストール
git clone https://github.com/certbot/certbot.git
証明書作成コマンド。事前にnginxやapacheなどサーバーを止めないと実行できません。作成の際に規約の同意が聞かれます。
./certbot-auto certonly --standalone --email admin@example.com -d example.jp -d www.example.jp
証明書の作成が完了すると、メッセージが表示されます。
そのメッセージ内の'Your certificate and chain have been saved at' の後に書いてあるパスが証明書の保存場所ですね。
んで、nginxの設定
server { listen 443 ssl; ssl_certificate /etc/letsencrypt/live/example.jp/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.jp/privkey.pem; ssl_prefer_server_ciphers on; ssl_ciphers ECDHE+RSAGCM:ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:!aNULL!eNull:!EXPORT:!DES:!3DES:!MD5:!DSS; server_name www.example.jp; access_log /var/log/nginx/app_access.log; location / { proxy_pass http://127.0.0.1:8000; # gunicornで立ち上げたサーバーのポート proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
記憶が曖昧なので、下記の参考記事読んだ方がいいかも...
参考
トラブル
急にサーバーに接続できなくなった
以下のスクリプトを作成して実行。
ファイヤウォールのルールをリセットとあるが本当にこんなことをしていいのだろうか?
#!/bin/sh echo "Flushing iptables rules..." sleep 1 iptables -F iptables -X iptables -t nat -F iptables -t nat -X iptables -t mangle -F iptables -t mangle -X iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT
その他
Arduinoをシミュレータで入門してみた
IoTには興味あるけど、実際に機器を買うまでモチベーションが至らなかったので、シミュレータから入った話。
ラズパイとWebの力で何かしたい、でも実際に何ができるかわからないから、名古屋版IoT縛りの勉強会! IoTLT vol1 - connpass に参加して聴講。
どうやら電子工作でのWebはArduino + esp8266の方が簡単らしい、ということでArduinoから入ることにしました。
123d circuits
Bring ideas to life with free online Arduino simulator and PCB apps | 123D Circuits by Autodesk
入門するにあたって使ったシミュレータです。
123d circuitsは、ウェブ上で動くシミュレータで、作った回路やコードを公開できます。
どうやら、パーツを壊すこともできるみたいで、「抵抗間違えてArduinoやパーツがお釈迦になった」なんていうハプニングも未然に防げるとか。
使ってみた感想、というか簡単な考察はこんな感じ。
メリット
デメリット
- Arduinoの基本的なライブラリしか読めない。外部ライブラリを使いたければそのソースコードをコピペしろとのこと。
- 動作が妙に遅い。シミュレータないの一秒が一秒以上であることがが普通。
- esp8266でアクセスして、取得した結果がやけにおかしい。思った通りの情報を受け取れない。
- pythonで書けない(憤怒)。巷ではpythonでArduinoが書けるというらしいが、シミュレータにそんなものはサポートされているわけなかった。
以上のように、気軽に電子工作ができて共有もできるうえに、Wifi通信もシミュレートできる一方、
さすがになんでもかんでも作れるわけではない。そこについては、まあ仕方ないと割り切りましたが、さすがにWebから取得したレスポンスのメッセージが変ってのは腑に落ちませんね・・・
しかし、シミュレータ上で回路が落ちていたり、それを編集できるので、とりあえずArduino本体やパーツを買って、作りたい回路を見つけたorできたら早速作るのもアリですね。
で、シミュレータで遊んで作ったものを以下に記載します
制作物
ArduinoでWebAPIにアクセスして、取得した結果をLCDに表示させてみました。
回線だけは完全に丸パクリ。配線はその上で必要最低限分勉強しただけで、コードを変えてみたって感じです。
とりあえずHTTPリクエストの結果まんま(?)LCD上に表示させました。
動かしてみたらわかりますが、JSONのデータらしいものが表示されます。どうも結果の挙動がおかしいです。
そのせいで、肝心な欲しいデータだけを抽出しようにも全くできない状態。
本当は、クライアント端末からLEDやモーターを操作したかったのに、謎の取得結果のせいで実現できない状態に。
今後は、原因究明をするか、諦めて本番で作るかですかねー・・・
esp8266への接続
esp8266での接続では、ssidを "Simulator Wifi" で、パスワードは未入力("")で接続ができます。
つまり、123d circuitsでWifiに接続するまでなら、こんな感じに書ける。
(他人のコードのコピペですが・・・)
String ssid = "Simulator Wifi"; // SSID to connect to String password = ""; // Our virtual wifi has no password (so dont do your banking stuff on this network) void setup() { // Start our ESP8266 Serial Communication Serial.begin(115200); // Serial connection over USB to computer Serial.println("AT"); // Serial connection on Tx / Rx port to ESP8266 delay(10); // Wait a little for the ESP to respond // Connect to 123D Circuits Simulator Wifi Serial.println("AT+CWJAP=\"" + ssid + "\",\"" + password + "\""); delay(10); // Wait a little for the ESP to respond }
その他
123d circuitsでdweet.ioという、簡単にWebAPIを作れるものを使いたかったです。(使ったけど)
これは、認証も登録もなしで簡単にWebAPIが作れるというもので、プロトタイプには超うってつけです。
URLやパラメータで簡単にデザインできます。
FlaskでRESTfulAPIを作ってみた
pythonでRESTfulAPIを簡単に書けないかなと思ったら、flaskでもできそうということで試してみた。
Flask-RESTful — Flask-RESTful 0.2.1 documentation
javascriptからajaxを使うにあたって、クロスドメイン制約が邪魔になる時もあると思いますが、CORSの設定もできるみたいです。
例えば、monaca(以下参照)を使ってアプリを作る時とかに使えそうですね。
というわけで、CORSを適用したRESTfulAPIをつくってみました。
#!/usr/bin/env python # coding: utf-8 from flask import Flask, request, jsonify from flask_restful import Resource, Api from flask_restful.utils import cors # 初期設定 app = Flask(__name__) api = Api(app) class Count(Resource): cache = 0 # GET時の挙動の設定 @cors.crossdomain(origin='*') def get(self): Count.cache = Count.cache + 1 send_msg = jsonify(num=Count.cache) return send_msg api.add_resource(Count, '/count/') if __name__ == '__main__': app.run()
挙動としては count/ にアクセスするとバッファのカウンタを1足して返す挙動をとります。
で、APIにアクセスする方をjsfiddleで書いてみました。
挙動がおかしいですが、基本カチカチボタンを押すとカウンターに値が加算されます。
anaconda環境でflaskで開発したサーバーをherokuに上げる
pythonのリハビリとpython3覚えるために。
というかanacondaとherokuにはまだ慣れていないので要点だけメモ
割りと参考記事パクってつまんだだけです
1.仮想環境構築
conda create -n flask-in-heroku flask gunicorn
2.Procfileの用意
サーバーファイル名が main.py の場合
cat 'web: gunicorn main:app --log-file -' > Procfile
3.モジュールリストの用意
conda list -e > conda-requirements.txt
4.heroku上でアプリの作成
heroku create --buildpack https://github.com/kennethreitz/conda-buildpack.git
これでプッシュしてサーバーが動いていればok
参考: