旅好きエンジニアのメモ

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

goのフレームワーク ginの"gin-scaffold"を入れようとしたらエラーが出た。("hg": executable file not found in $PATH)

ginの"gin-scaffold"を入れようとしたらなんかエラーがでた。

$ go get github.com/dcu/gin-scaffold
package bitbucket.org/pkg/inflect: exec: "hg": executable file not found in $PATH
go: missing Mercurial command. See https://golang.org/s/gogetcmd

Mercurialというバージョン管理システムを入れないとダメみたい。(gitみたいなもの)

ちなみに"hg"はMercurialのコマンドです。

gitでリポジトリ入れる時"git clone リポジトリ"って打つ時の"git"の部分。

おそらくこれで入れれます。

なんかgit入れてなくてもエラー出るらしいですが、まぁ殆どの人はgit入れているので大丈夫でしょう。

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ベースでやったほうがだいぶ楽なんじゃと思ったりしています。

rails2で'ruby-debug'(デバッグ)を使う時の注意

下記のgemでdebug(デバッグ)する時、だいたいgem入れて
gem 'ruby-debug'

自分の止めたいところで
debugger
をコードの中に入れるみたいな感じで書いていると思います。

そして、サーバーの立ち上げはいつも通りで。。。

bundle exec script/server

はい、最後これ駄目ですね。

正解はoptionを下記のようにつけることでデバッグできるようになります。

bundle exec script/server --debugger

ブログ書くのは良いけど、一応自分でみんな動かしているのかな?
バージョンと動くものを書くのが大事だと思いますね。。。

もしかしたら、普通のサーバー立ち上げでもできる方法があるのか?

rails5でapiを作成する方法

apiの改修することはあれども今までapiの作成を初めからしたことなかったので 簡単に作った時のメモをしておきます。

環境

ruby 2.4.2p198 Rails 5.1.4 sqlite3(初期設定のものを使っています)

アプリ作成

まず、適当にrails アプリ作りましょう。

rails new webapp

例として著者(Articles)を検索するapiを作成します。

マイグレーションファイル

マイグレーションファイルはこんな感じです db/migrate/20170808181112_create_articles.rb

class CreateArticles < ActiveRecord::Migration[5.0]
  def change
    create_table :articles do |t|
      t.string :title
      t.text :content
      t.index [:title,:content]
      t.timestamps
    end
  end
end

migrateしてテーブル作りましょう

rails db:migrate
モデル

モデルを書きましょう。(特にvalidation checkとかは書いてません。active record 使うためだけに書いてます) models/article.rb

class Article < ActiveRecord::Base
end
ルーティング

ルーティングはこんな感じでv1とかバージョニング管理できるようにしています。 routes.rb

Rails.application.routes.draw do
  namespace :api, {format: 'json'} do
    namespace :v1 do
      namespace :article do
        get "/" , :action => "index"
      end
    end
  end
end
コントローラー

最後にコントローラーです。一応タイトルで検索できるようにしています。 controllers/api/v1/article_controller.rb

module Api
  module V1
    class Api::V1::ArticleController < ApplicationController
      def index
          @article = Article.where("title = ?", params[:title])
          render json: @article
      end
    end
  end
end

ちなみにキャッシュ作れるのでこっちのほうが早くなります。

module Api
  module V1
    class Api::V1::ArticleController < ApplicationController
      def index
          @article = Rails.cache.fetch('article', expires_in: 60.seconds) do
            Article.where("title = ?", params[:title])
          end
          render json: @article
      end
    end
  end
end

"params[:title]"は渡ってくるパラメータです。params[]はrailsでうまくやってくれているので 例えば以下のように検索すれば params[:title]は"sample"になります。 http://localhost:3000/api/v1/article?title=sample

以下だと、 params[:title]は"sample" params[:content]は"aaa"になります。 http://localhost:3000/api/v1/article?title=sample&content=aaa

データを入れる

では、サーバーを立ち上げる前にデータを入れてみましょう。 以下コマンドでコンソールに入ります。

rails c

コンソールでデータを1件だけ作ります。

data=Article.new
data.title = "sample"
data.content = "aaa"
data.save!

先程作ったデータがあるか確かめます。

Article.first
確認

最後にサーバーを立ち上げてチェックしましょう。

rails s

ブラウザ(cheromeとか)で以下のurlを打ってみると先程いれたデータがjsonで返ってくるのが確認できるはずです。 http://localhost:3000/api/v1/article?title=sample

まとめ

rails5はapiだけの機能のアプリも作れますのでそちらでアプリを作っても良いかもしれません。 そのときの作り方はオプションでapi付けるだけです。

rails new weapp --api

これを機にapi開発をやってみてはいかがでしょうか。

rails4からrails5でインデックスの貼り方が変わった?

index貼りたいけどrails5になったらadd_indexで貼れなくて戸惑いましたw

rails4なら作られたテーブルに関してこんな感じ

class AddIndexToTestTables < ActiveRecord::Migration
  def change
    add_index :test_tables, :name
    add_index :test_tables, :name2
  end
end

rails5になるとcreate table時にこんな漢字で作るらしい。

class CreateTestTables < ActiveRecord::Migration[5.0]
  def change
    create_table :test_tables do |t|
      t.string :name
      t.string :name2
      t.index :name
      t.index :name2
    end
  end
end

indexの追加は以下のように配列でも可能です。

t.index [:name,:name2]

ちなみに、rails5はrakeコマンド基本的には使わないらしいですね。。。 (使えるっぽいですが。。。)

rails4ではこうですが。

rake db:migrate

rails5ではrailsコマンドっぽいです

rails db:migrate

いやぁ、バージョン移行するって大変ですね。。。

参考は下記ページ http://parrot.hatenadiary.jp/entry/2016/05/29/112331

pythonで配列追加の処理速度の違い

pythonで配列追加の処理速度を比べてみました。

"append"を使う方法
import time
def process():
    result = []
    start_time = time.time()
    for _ in range(10000000):
        result.append("test")
    processing_time = time.time() - start_time
    return processing_time

In [5]: process()
Out[5]: 0.8140008449554443
"+="を使う方法
import time
def process():
    result = []
    start_time = time.time()
    for _ in range(10000000):
        result += "test"
    processing_time = time.time() - start_time
    return processing_time
In [8]: process()
Out[8]: 1.365239143371582

rubyとか普段使っていたら記号とか使いがちですが、 ここはスタンダードにappendを使うほうが倍ぐらい早い感じでした。