ElixirでWebスクレイピング

Webページの取得にHTTPoison, HTMLのパースにFlokiを利用します。

HTTPoison

GitHub - edgurgel/httpoison: Yet Another HTTP client for Elixir powered by hackney

Floki

GitHub - philss/floki: Floki is a simple HTML parser that enables search for nodes using CSS selectors.

実行環境を整える

プロジェクトの作成

$ mix new scraper_sample

関連モジュールの取得

mix.exsに依存関係を記述し取得します。

# mix.exs
defmodule NetseaCrawler.Mixfile do
  use Mix.Project

  # ....

  def application do
    [applications: [:logger, :floki, :httpoison]]
  end

  defp deps do
    [
      {:floki, "~> 0.10.0"},
      {:httpoison, "~> 0.9.0"},
    ]
  end
end
$ mix deps.get
Running dependency resolution
Dependency resolution completed
  certifi: 0.4.0
  floki: 0.10.0
  hackney: 1.6.1
...

iexの起動

以下のコマンドでiexを起動するとプロジェクトの環境が読み込まれるので、依存モジュールを参照することができます。

$ iex -S mix

スクレイピングしてみる

試しにelixirのページのコミットメッセージを取得してみます。

GitHub - elixir-lang/elixir: Elixir is a dynamic, functional language designed for building scalable and maintainable applications

HTTPoisonでWebページを取得する

iex(1)> ret = HTTPoison.get! "https://github.com/elixir-lang/elixir"
iex(2)> %HTTPoison.Response{body: body} = ret

これで変数bodyにHTMLが入ります。

Flokiでパース

ブラウザの「要素の調査」とかでHTMLの構造を把握します。
コミットメッセージは table.files > td.message > span で取れそうなのでFloki.findをパイプライン演算子でつなげていきます。(XPathで書けなそうなのでネストが深いと結構面倒)

iex(3)> Floki.find(body, "table.files") |>
...(3)> Floki.find("td.message") |>
...(3)> Floki.find("span") |>
...(3)> Enum.map(fn(span) -> Floki.text(span) end)
["Make batch style more consistent (#4944)",
 "Refactor and optimize aggregations over lists",
 "Fix a typo in the iex man page (#4655)", "Start v1.4.0-dev",
 "Move .gitattributes files to repo root",
 "Include docs zip in the publish process", "Use 18.2 instead of 18.2.1",
 "Integer.digits/2 & Integer.undigits changes (#4868)",
 "Small fixes in comments and documentation (#4744)",
 "Add Elixir Forum to list of help channels (#5121)",
 "Copyright requires just the starting year",
 "Properly check for earlier Erlang versions, closes#5090",
 "Add missing NOTICE file", "Add link to security mailing list",
 "Start v1.4.0-dev", "Start v1.4.0-dev",
 "Update rebar to rebar 2.1.0-pre. This (among other things) fixes a cr…",
 "Use proper case for proper nouns and acronyms", "Rebar3 dependency support"]

エラー処理とか全くしてない状態なので、今度はその辺突っ込んでみようかと。

プログラミングElixir

プログラミングElixir