mcommit's message

ソフトウェア開発の仕事をしているsimotinといいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

Elixir入門 ~10日目 Elixirでお宝データをゲットしてみた・mix,HTTPoisonの使い方とか~

Elixirを勉強する上で、肩慣らしにお宝画像のデータを集めるスクリプトを書いてみたいという記事を書いたけどmixの使い方がよく分からなかったので、憂さ晴らしにRubyでやりたいことを明確化していた。

mcommit.hatenadiary.com

何事もやるべきことを明確にして、小さな一歩を踏み出すことが重要だ。あとは、このRubyで書いたコードをElixirに変換するだけという状態だ。

今日は改めてmixとHTTPoisonの使い方とか調べてみてようやくElixirでもお宝をゲットする方法が分かった。

お宝データゲットを支える技術

お宝データにたどり着くまでに必要な技術要素は、ざっくり言うと

  1. HTTP(S)通信
  2. 正規表現
  3. ファイル出力(バイナリ)

の3要素だ。

それぞれの実現方法を調べてみる。

HTTP(S)通信

これには mix と HTTPoison の力を借りる。

mix の使い方

プロジェクトを作るときは、

mix new フォルダ名 --module モジュール名

とするらしい。

プロジェクト名のルールとして mix new で作るモジュール名の標準的なルールとして -(ハイホン)は使えないらしい。アンスコはok。

--module は省略できるので

mix new フォルダ名

でもよい。モジュール名は大文字で始まるというルールなので

mix new hoge

だとモジュール名は Hogeになる。

--module をつけるのはモジュール名明確に指定したいとき

mix new hoge --module HOGE

のような場合らしい。

とりあえず今回の場合は、お宝データということで

mix new treadure_data

とした。

mix.exs の編集

HTTPoison を使いたい。

github.com

を参考に mix.exsを修正する。

mix new して修正した mix.exs

defmodule TreadureData.Mixfile do
  use Mix.Project

  def project do
    [
      app: :treadure_data,
      version: "0.1.0",
      elixir: "~> 1.5",
      start_permanent: Mix.env == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      applications: [:httpotion],
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
        {:httpotion, "~> 3.0.2"}
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
    ]
  end
end

注意点

HTTPoison を使いたいのにどういうわけかHTTPotionというライブラリのGithubを長いこと見ていた。

github.com

これはもしや似たような名前を付けて自分のライブラリを使わせようとする罠か!?見事にはまってしまった。


もう一度言う。


HTTP通信に使いたいのは httpoison

紛らわしいのは httpotion


言いたいことも言えないこんな世の中は ぽいぞん


俺は俺をだますことなく mix.exs を修正したら依存しているモジュールを取得するコマンド mix deps.get をたたく。

おや!?誰か部屋に入ってきたようだ。えっ!?JASRA*!")(#'&H`*+KIL")#J・・・・・

・・・

・・・

・・・

どうもちょっとした手違いでたたくコマンドが増えた。

$ pkill -KILL -f JA*RAC

が必要だったみたいだ。

気を取り直して、mix deps.get はRubyでいうbundle install 的なことだろう。

$ mix deps.get
Resolving Hex dependencies...
Dependency resolution completed:
  certifi 2.0.0
  hackney 1.9.0
  httpoison 0.13.0
  idna 5.1.0
  metrics 1.0.1
  mimerl 1.0.2
  ssl_verify_fun 1.1.1
  unicode_util_compat 0.3.1
* Getting httpoison (Hex package)
  Checking package (https://repo.hex.pm/tarballs/httpoison-0.13.0.tar)
  Using locally cached package
* Getting hackney (Hex package)
  Checking package (https://repo.hex.pm/tarballs/hackney-1.9.0.tar)
  Using locally cached package
* Getting certifi (Hex package)
  Checking package (https://repo.hex.pm/tarballs/certifi-2.0.0.tar)
  Using locally cached package
* Getting idna (Hex package)
  Checking package (https://repo.hex.pm/tarballs/idna-5.1.0.tar)
  Using locally cached package
* Getting metrics (Hex package)
  Checking package (https://repo.hex.pm/tarballs/metrics-1.0.1.tar)
  Using locally cached package
* Getting mimerl (Hex package)
  Checking package (https://repo.hex.pm/tarballs/mimerl-1.0.2.tar)
  Using locally cached package
* Getting ssl_verify_fun (Hex package)
  Checking package (https://repo.hex.pm/tarballs/ssl_verify_fun-1.1.1.tar)
  Using locally cached package
* Getting unicode_util_compat (Hex package)
  Checking package (https://repo.hex.pm/tarballs/unicode_util_compat-0.3.1.tar)
  Using locally cached package

HTTPoison の動作確認

HTTPoison を入手できたら動作確認をする。

$ iex -S mix

で mix で指定したライブラリを読み込んだ状態で iex が起動する。

res = HTTPoison.get! "https://www.yahoo.co.jp/"

でyahooにアクセスしてみると問題なくアクセスできた。

res.body で bodyのデータ、 res.status_code でステータスが参照できる。

これでお宝データゲットを支える技術のうちHTTP通信については解決した。

正規表現

Elixirの正規表現Regex クラスを使うらしい。
Rubyだと文字列クラスに scan メソッドが用意されているが Elixir の場合は Regex クラスに scan メソッドがある。
使い方はRubyとそんなに変わらないみたいだ。

ファイル出力

ファイル出力に必要なことはここを参照した。

12 入出力 - IO - Elixir

パターンマッチで結果を受け取るやり方にはまだ馴染んでいないのであとで復習する。
バイナリの書き込みはぱっと見、 IO.binwrite がそれっぽい。

その他

Elixirでの printfデバッグは、

IO.inspect 変数名

を使うらしい。Rubyの p デバッグとか、PHPの var_dump 相当。

自分の場合、Rubyだと

a = 123
puts "a:#{a}"


みたいに式展開をよくやるけどElixirにも式展開とかあるんだろうか。これも宿題だ。

ソースはどこに書くのか

mix new を実行するといろいろなファイルやフォルダが自動で生成される。

mix を使うHello Worldとしてイントロダクションを読んでおく必要がある。

elixir-lang.org

肝心のソースファイルは lib 以下に配置するらしい。
lib というフォルダ名に若干の違和感を感じる(src とかじゃだめなんだろうか)がまぁそれは置いておくとして

libフォルダ内には

プロジェクト名.ex(今回の場合 treadure_data.ex)

というファイルが自動生成されていてここからコードを書いていく感じらしい。

Elixir でお宝をゲットするコード

というわけでお宝ゲットまでには学ぶべきことが多かったけど、各々の技術要素について調べながら適当に書いてみたら動いた。

宝の地図をここで広げておこう。

defmodule TreadureData do
  @moduledoc """
  Documentation for TreadureData.
  """

  @doc """
  Hello world.

  ## Examples

      iex> TreadureData.hello
      :world

  """
  def get_treadure_data do
     IO.puts "Let's 69'n roll!"
     HTTPoison.start
     res = HTTPoison.get! "http://umihiro.hateblo.jp/entry/20170925/1506349877"
     urls = Regex.scan(~r/https:\/\/lh3.googleusercontent.com\/.*JPG/, res.body)
     Enum.map(urls, fn(url) ->
         treadure_data = HTTPoison.get! url
         filename = List.last(String.split(hd(url), "/"))
         {:ok, file} = File.open filename, [:write]
         IO.binwrite file, treadure_data.body
         File.close file
       end
     )
     IO.puts "Alright, get out of here..."
  end
end

TreadureData.get_treadure_data

get_treadure_data 関数だけだと20行切っている。素晴らしい!
ErlangやElixirの並列計算機能はきっとこういことに活かすんだろう。

コードが書けたらプロジェクトのトップディレクトリで

$mix run

をたたけば書いたコードがコンパイル・実行される。

感想

mix/HTTPoison の使い方の理解に一番時間かかった。といってもそこの調査と学習に使った時間はたぶんトータル5~6時間くらいだと思う。

HTTPosionとの勘違いがなければもっとスムーズだったはずだ。あぁバカだった。

無事お宝データもゲットできたのでelixirの基本的な勉強をもう一回おさらいしてみたい。

よく考えたら分岐(if・switch)とかも知らないのでFIZZ・BUZZとか書けない。
明日は、今日の宿題と合わせてFIZZ・BUZZを書いてみることにする。

宿題

  • Elixirで文字列への式展開はどうやるのか?printf的な関数を通すしかないんだろうか。
  • デバッグ中に ruby の "sss".class #=> String みたいなことがしたかったけどどうやってやるのかよくわかっていない。
  • リスト操作に慣れていない
  • 関数の戻り値をパターンマッチで受ける作法
  • 異常系処理の書き方とかしらない
  • ゲットしたお宝まだちゃんと見れていない。