Elixirを勉強する上で、肩慣らしにお宝画像のデータを集めるスクリプトを書いてみたいという記事を書いたけどmixの使い方がよく分からなかったので、憂さ晴らしにRubyでやりたいことを明確化していた。
何事もやるべきことを明確にして、小さな一歩を踏み出すことが重要だ。あとは、このRubyで書いたコードをElixirに変換するだけという状態だ。
今日は改めてmixとHTTPoisonの使い方とか調べてみてようやくElixirでもお宝をゲットする方法が分かった。
目次
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 を使いたい。
を参考に 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を長いこと見ていた。
これはもしや似たような名前を付けて自分のライブラリを使わせようとする罠か!?見事にはまってしまった。
もう一度言う。
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とそんなに変わらないみたいだ。
ファイル出力
ファイル出力に必要なことはここを参照した。
パターンマッチで結果を受け取るやり方にはまだ馴染んでいないのであとで復習する。
バイナリの書き込みはぱっと見、 IO.binwrite がそれっぽい。
その他
Elixirでの printfデバッグは、
IO.inspect 変数名
を使うらしい。Rubyの p デバッグとか、PHPの var_dump 相当。
自分の場合、Rubyだと
a = 123 puts "a:#{a}"
みたいに式展開をよくやるけどElixirにも式展開とかあるんだろうか。これも宿題だ。
ソースはどこに書くのか
mix new を実行するといろいろなファイルやフォルダが自動で生成される。
mix を使うHello Worldとしてイントロダクションを読んでおく必要がある。
肝心のソースファイルは 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
をたたけば書いたコードがコンパイル・実行される。