旅好きエンジニアのメモ

旅のこと映画、統計、会計、プログラミングなど、気の向くままに語ります

bottleでファイルダウンロード機能を追加する

bottleでファイルダウンロード機能を追加するのは結構簡単です

とりあえず下記のような感じでダウンロード出来るようになります・

ファイル構成

  app
  ├── controller
  │     └── static.py
  │
  └── static
         ├── csv
         │   └── sample.csv
         └── img
             └── samle.jpg

htmlタグ

<a href="/download/csv/sample.csv" download="sample.csv">sample.imgをダウンロード</a>

controller/static.py

from bottle import route, static_file

@route('/download/:path#(csv|img)\/.+#')
def download_static(path):
    return static_file(path, root='app/static', download=True)

スクレイピングで文字化けを防ぐ方法

下記が使用するライブラリ(chardet)です。

pypi.org

chardetは文字コードを検出するライブラリで検出して取得したデータにdecodeをすると文字化けを解消できます。

sampleは日経のページです。

import urllib3
import chardet

url = "http://www.nikkei.com/"
http = urllib3.PoolManager()
r = http.request('GET', 'http://www.nikkei.com/')
r.data
guess = chardet.detect(r.data)

unicode_data = r.data.decode(guess['encoding'])

vue.jsのデリミタ(delimiter)を変更する方法 sampleとしてjinja2を使用

フロントエンドのフレームワークと既存のテンプレートエンジンのデリミタ(delimiter)って被ってしまった。。。

ちなみにデリミタ(delimiter)とは、"フィールド区切り文字"のことです。 具体的には railsのerbの<% hogehoge %>とか jinja2の{{ hogehoge }}とか bladeの{{ hogehoge }}とかです。

erbだと<% %>の中にrubyのコードが書けます。 これをデリミタといいます。

さて、 vue.jsのデリミタも実はjinja2やbladeと同じく{{ }}なんです。

ですので、jinja2とvue.jsをそのまま使用するとコンフリクトが生じてしまうのです。

そこで、解決策としてデリミタを変更するという方法があります。(ここからはjinja2をsampleに書きます。)

jinja2のデリミタかvueのデリミタどちらかを変更すればよいのです。

jinja2のデリミタを変更するのはフレームワークに依存してしまうケースがあるので、完結に変更するにはvue.jsがおすすめです。

下記コードは{{ }}から[[ ]]にデリミタを変更しています。

hoge.js

new Vue({
  el: '.js-component01',
  delimiters: ['[[', ']]'], //ここにデリミタの変更を記述
  data: {
    text: 'hogehoge'
  }
});

python側ではbottleを使用しています。

run.py

from bottle import route, run
from bottle import TEMPLATE_PATH, jinja2_template as template

@route('/top')
def main():
    return template('top', hoge = "pythonの結果")

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

top.html

<div class="js-component01">
  <p>[[hoge]]</p>
</div>
<div>
  {{hoge}}
</div>

テンプレートでは同じ変数hogeでもvueで設定したものとpythonで設定したもので、異なる値が表示されるようになっています。

ちなみにデリミタを変更せずに行うと、python側が優先されます。

binanceから日足を取得するスクリプトを書きました(python)

仮想通貨のコイン間での値動きの相関を調べてみたいと思い、まずはbinanceからデータを取得するpythonスクリプトを書いてみました。

実装には下記のライブラリを使用させてもらいました。(作者の方は他のwrapperも作っていて意欲的な感じがします!)

github.com

ちなみに以下が書いてみたスクリプトです。
ソースコードは自分用に書いているので汚ないです。。。

from binance.client import Client
from datetime import datetime

class Binance(object):
    def __init__(self, api_key, api_secret):
        self.client = Client(api_key, api_secret)

    def get_bars(self, bar_duration, start, end):
        kline_list = []
        for ticker_combination in self.ticker_combinations():    
            klines = self.client.get_historical_klines(ticker_combination, bar_duration, start, end)
            klines = self.format_klines(klines)
            kline_list.append({"ticker_combination":ticker_combination, "klines":klines})
        return kline_list

    def ticker_combinations(self):        
        combinations = self.client.get_all_tickers()
        ticker_combination_list = []
        for combination in combinations:
            ticker_combination_list.append(combination['symbol'])
        return ticker_combination_list

    def format_klines(self, klines):
        klines = list(map(lambda x: [self.format_timestamp(x[0]),x[1],x[2],x[3],x[4],x[5],self.format_timestamp(x[6]),x[7],x[8],x[9],x[10],x[11]], klines))
        return klines

    def format_timestamp(self, timestamp):
        time = datetime.fromtimestamp(timestamp/1000)
        return time

利用方法

api_key, api_secretはbinanceで取得してください (binanceは香港の仮想通貨取引所です。)

start = "1 Dec, 2017"  
end = "1 Jan, 2018"  
bar_duration = "1d"  

bi = Binance(api_key, api_secret)  
bi.get_bars(bar_duration, start, end)  

分析のデータがほしい方はぜひ使ってみてください。

pythonでjwt使おうとしたらライブラリで詰まった件について(入れなおせばいいんだ!)

jwtって

そんな人は下記記事が参考になります。
今回はエラーの対処法のみです

qiita.com

ライブラリ似過ぎな件

①Pyjwt

github.com

②jwt

github.com

はい、こいつらの共存が悪影響を及ぼします。。。

名前空間でも影響しあってるのかな?
そこまで調べる気力はないので気になる人は自分で調べてください!

エラー内容

下記コマンド打つと"jwtは使えねーよ"(すいません、エラー内容消してしまいました。。。)
みたいな感じになりました.

sign = jwt.encode(auth_payload, api_secret, 'HS256')

解決法

まぁ、解決法は下記参考でなおりました!!(ちゃんとエラー内容書いてるよ)

stackoverflow.com

jwtもpyjwtもどっちも消して入れなおせよってことです

pip uninstall JWT  
pip uninstall PyJWT  
pip install PyJWT

pythonでapiからデータを取得する方法 (urllib3)

はてさて、pythonapiからデータするときみなさんはどんなライブラリを使いますでしょうか?

urllib? urllib2 urllib3?

ってライブラリ多いですね。
ちなみに、"urllib"は"https"でデータを取得できない場合もあります。

なので、個人的なオススメは"urllib3"です。

インストール
pip install urllib3

pypi.python.org

urlにつなぐ
import urllib3
http = urllib3.PoolManager()
r = http.request('GET','http://httpbin.org/get')

つながったか確認してみましょう

r.status

データの中身を見てみましょう

r.data
パラメータを追加

urlの後にfieldsオプションにこんな感じに書くだけです。
下記だと"http://httpbin.org/get?arg=value&arg2=value2"になります。

r = http.request('GET','http://httpbin.org/get',fields={'arg': 'value', 'arg2': 'value2'})

djangoでpandas使うのは簡単だった

pandas使ってデータ分析しているサイトがよくあって、 私も参考にしているのですが大体csv使ってませんか?

少ないデータだったらcsvで良いと思うんですけど、 apiスクレイピングデータ取るときってdbに突っ込みませんか?

djangoのormでデータをdbにつっこんで、そのまま分析するほうが効率的な気がします。 そもそも、csvからデータ抜くの整形の処理やタイトルつけたりめんどくさいです。

そんなときは、"django-pandas"で楽をしちゃいましょう。

https://github.com/chrisdev/django-pandas

インストール
pip install django-pandas

サンプルは自分で作っているビットコインの足(日足とか分足とか)みたいなものです。

model

モデルはこんな感じです

class BitcoinTicker(models.Model):
    bc_id = models.IntegerField('bc_id', unique =True)
    high = models.DecimalField('high', max_digits=25, decimal_places=10, blank=True, null=True)
    low = models.DecimalField('low', max_digits=25, decimal_places=10, blank=True, null=True)
    volume = models.DecimalField('volume', max_digits=25, decimal_places=10, blank=True, null=True)
    timestamp = models.DateTimeField('timestamp')
pandasデータフレームへの変換
from app.models import BitcoinTicker
from django_pandas.io import read_frame
bitcoin_ticker = BitcoinTicker.objects.all()
df_bitcoin_ticker = read_frame(bitcoin_ticker)

カラムhighのデータが有るか確かめてみましょう。

df_bitcoin_ticker.high

こんな感じで簡単にできます。

最近はデータ分析にdjangoベースでやったほうがだいぶ楽なんじゃと思ったりしています。