導入編に引き続き,スクレイピング編を書いていきます.
スクレイピング
スクレイピングするのに必要なライブラリ追加をします.
Erlang,ElixirにはHexというパッケージマネージャーがあります.
必要なライブラリを探すときはHexを見ると良いです.
今回必要なライブラリは以下です.
HTTPosion・・・HTTPクライアント
Floki・・・HTMLパーサー
mix.exsに参照ライブラリ,依存ライブラリを書きます.
参照ライブラリは :ライブラリ名
依存ライブラリは {:ライブラリ名, “~> バージョン”}
と書きます.
# code mix.exs
・ ・ ・ # Configuration for the OTP application # # Type "mix help compile.app" for more information def application do # Specify extra applications you'll use from Erlang/Elixir [extra_applications: [:logger, :httpoison, :floki]] # 追記 end # Dependencies can be Hex packages: # # {:my_dep, "~> 0.3.0"} # # Or git/path repositories: # # {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} # # Type "mix help deps" for more examples and options defp deps do [{:httpoison, "~> 0.11.0"}, # 追記 {:floki, "~> 0.12.0"}] # 追記 end
以下のコマンドでライブラリを取得し,ローカルにもってきます.
# mix deps.get
指定されたURLのリンクと画像を取得して返すスクレイピングのモジュールを作成します.
関数型言語は初めてで,Elixirらしい書き方が難しいです…
get_~_from_contentは外出しして,拡張性をあげたほうがそれっぽい気がします.
# code lib/imcrawler/scraping.ex
defmodule Imcrawler.Scraper do require HTTPoison require Floki @doc """ 指定されたURLからHTMLを取得し、その中からリンク/画像を取得する """ def scraping(url) do # 指定URLのHTMLを取得 {status, body} = get_html_body(url) if status == :ok do # リンク取得 links = get_links_from_content(body) # 画像取得 imgs = get_imgs_from_content(body) {:ok, links, imgs} else {:error, [], []} end end # 指定URLのHTMLを取得 defp get_html_body(url) do try do {_, res} = HTTPoison.get(url) %HTTPoison.Response{status_code: status_code, body: body} = res if status_code == 200 do {:ok, body} else {:error, ""} end rescue what -> IO.inspect(what) {:error, ""} end end # HTMLからリンクを取得 defp get_links_from_content(content) do list = content |> Floki.find("a") |> Floki.attribute("href") |> Enum.filter(fn(x) -> String.contains?(x, "http://") or String.contains?(x, "https://") end) # IO.puts(list) list end # HTMLから画像を取得 defp get_imgs_from_content(content) do list = content |> Floki.find("img") |> Floki.attribute("src") |> Enum.filter(fn(link) -> String.contains?(link, "http://") or String.contains?(link, "https://") end) |> Enum.map(fn(link) -> {status, body} = get_html_body(link) {status, link, body} end) |> Enum.filter(fn({status, _, _}) -> status == :ok end) |> Enum.map(fn({_, link, body}) -> {link, body} end) # IO.inspect(list) list end end
imcrawler.exのmain関数からScraping.scrapingをURL指定で呼び出すようにして実行します.
# mix run -e "Imcrawler.main"
(リンクと画像のURLが出てくる)
まとめ
Elixirらしい書き方はまだまだピンときませんが,パターンマッチングとパイプすげぇで心がいっぱいです.
クロール編に続く…