パパエンジニアのポエム

奥さんと娘ちゃんへの愛が止まらない

Elixirで株価をスクレイピングする

開発ブログに再挑戦。
Elixir習得のため、株価スクレイピングアプリをElixirで書いてAWSで運用するまでを一旦の目標にする。

開発環境を構築する

OS無しノートPCにUbuntu入れた。スペック低いけど、プログラミングかブラウジングしかしないので問題ない。

Elixirをインストールする

公式見ながらコマンド実行。
Installing Elixir - Elixir

wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb
sudo apt-get update
sudo apt-get install esl-erlang
sudo apt-get install elixir

これでスッとインストール出来るはず。

Mixを使いプロジェクトを作成する

Mixという便利なプロジェクト管理ツールを使い、Supervisor作成オプション付きでプロジェクトを作成する。

mix new stock_scraping --sup

ライブラリの依存関係を解決する

mix.exsに使用するライブラリを追記する。
使用するライブラリは以下。

最終的にコマンドラインで実行するためescriptを使う。
escriptの実行モジュール記載を忘れないこと。
実際のmix.exsこちら(ファイル名を表示する方法が分からん)。

defmodule StockScraping.Mixfile do
  use Mix.Project

  def project do
    [app: :stock_scraping,
     version: "0.1.0",
     elixir: "~> 1.4",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     escript: [main_module: StockScraping],
     deps: deps()]
  end

  def application do
    [extra_applications: [:logger],
     mod: {StockScraping.Application, []}]
  end

  defp deps do
    [
      {:timex, "~> 3.1"},
      {:httpoison, "~> 0.11.2"},
      {:floki, "~> 0.17.0"},
      {:certifi, "1.1.0", override: true},
      {:idna, "4.0.0", override: true},
      {:tzdata, "0.1.8", override: true},
    ]
  end
end

コマンドを実行しライブラリをダウンロードする。

mix deps.get

これでプロジェクトのセットアップは完了。

ロジックを実装して株価をスクレイピングする

escriptで実行されるStockScrapingモジュールを実装し、実際に株価をとってくる。
関数型言語書いたことないし、Elixirの文法もよくわからない中、気合で書いたので相当汚いはず笑。
現状その汚さすら理解できない状態のstock_scraping.exこちら。
(ここはこう書けド素人!!!みたいな意見貰えるとありがたい)

defmodule StockScraping do
  use Timex

  def main(args) do
    HTTPoison.get!("https://info.finance.yahoo.co.jp/ranking/?kd=33&mk=2&tm=d&vl=b")
    |> parse
  end

  defp parse(%{status_code: 200, body: body}) do
    parse_datetime(body)
    parse_volume(body)
  end

  defp parse_datetime(body) do
    date_list = Floki.find(body, "div.dtl")
    |> Enum.at(0)
    |> elem(2)
    |> Enum.at(1)
    |> String.replace(~r/[^0-9]/, ",")
    |> String.split(",", trim: true)

    year = Enum.at(date_list, 0) |> String.to_integer
    month = Enum.at(date_list, 1) |> String.to_integer
    day = Enum.at(date_list, 2) |> String.to_integer
    updttime = Timex.to_datetime({year, month, day}, "Asia/Tokyo")
  end

  defp parse_volume(body) do
    Floki.find(body, "tr.rankingTabledata")
    |> Enum.each(fn(x) ->
      element = elem(x, 2)
      rank = get_value(element, 0)
      code = get_code(element)
      market = get_value(element, 2)
      name = get_value(element, 3)
      price = get_value(element, 5)
      volume = get_value(element, 6)
      volume_average = get_value(element, 7)
      volume_rate = get_value(element, 8)
      end
    )
  end

  defp get_value(element, index) do
    Enum.at(element, index)
    |> elem(2)
    |> hd
  end

  defp get_code(element) do
    Enum.at(element, 1)
    |> elem(2)
    |> Enum.at(0)
    |> elem(2)
    |> hd
  end
end

escriptを使ってビルドする

ビルドコマンド実行。

mix escript.build

通ればルートにstock_scrapingというEarlangVM上で実行可能なバイナリファイルが生成される。

escriptを使ってバイナリファイルを実行する

バイナリを実行する。

./stock_scraping

f:id:yuki-toida:20170605134816p:plain

出力された、プログラムがちゃんと動くと嬉しい。
これで一旦値がとれるところまではいけたので、次回MySQLにこいつを突っ込む。