##使うライブラリ
HTTPoison
HTTPoisonは, HTTPクライアントでリクエストを投げて, レスポンスのHTMLを取得するために使います。
###Floki
Flokiは, シンプルなHtmlパーサでHtmlを解析してデータを取得するために使います。
###プロジェクト作成
mixは
Elixirプロジェクトの作成や依存解決,コンパイル,テストを行うビルドツール。
mixを使ってElixirプロジェクトの作成をしていきます。
$ mix new scraper
* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/scraper1.ex
* creating test
* creating test/test_helper.exs
* creating test/scraper1_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd scraper
mix test
Run "mix help" for more commands.
Elixirプロジェクトが作成されたので, プロジェクトに移動し進めていきます
###関連モジュール, ライブラリを取得
#mix.exs
defmodule Scraper.Mixfile do
use Mix.Project
def project do
[app: :scraper,
version: "0.1.0",
elixir: "~> 1.3",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
deps: deps()]
end
def application do
[applications: [:logger, :floki, :httpoison]]
end
defp deps do
[
{:floki, "~> 0.10.0"},
{:httpoison, "~> 0.9.0"}
]
end
end
mix.exsのdeps
にimportするモジュールを書き込みます。
ここで
- floki
- httpoison
を使うので追加します。
{:floki, "~> 0.10.0"},
{:httpoison, "~> 0.9.0"}
mix deps.get
でdepsに書き込んだ関連モジュールを取得します。
Takuya@Takuya-no-MacBook-Air:~/scraper1 mix deps.get
Running dependency resolution
Dependency resolution completed
certifi: 0.7.0
floki: 0.10.1
hackney: 1.6.3
httpoison: 0.9.2
...
関連モジュールを取得してスクレイピングをする準備ができました。
次はスクレイピングをしていきます。
###スクレイピング
iex -S mix
でプロジェクトの環境を読み込み, 依存モジュールを使用しながらインタラクティブにコードを実行していくことができます。
ここでは例としてgithubのプロフィールからfollower数を取ってみたいと思います。
githubのapiで提供されていると思うがやってみます:)
iex -S mix
Erlang/OTP 19 [erts-8.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.3.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> body = HTTPoison.get!("https://github.com/takpy").body
iex(2)> Floki.find(body, "span.counter") |> Enum.at(2) |> Floki.text() |> String.strip()
###body = HTTPoison.get! "https://github.com/takpy"
では"https://github.com/takpy" にhttpリクエストを送ったレスポンスのhtmlをbodyにバインドします。
bodyの Data typeはBitStringになっています
ちなみに変数のData typeは i 変数
で確認できます。
###Floki.find(body, "span.counter") |> Enum.at(2) |> Floki.text() |> String.strip()
パイプライン演算子でつなげていますが一つずつ解説します。
<a href="/takpy?tab=followers" class="underline-nav-item " aria-selected="false" role="tab">
Followers
<span class="counter">
取得したい --> 2
</span>
</a>
取得したいfollowerの数を取るためにはこの要素を取らなければならないのですが,
Floki.find(body, "span.counter")
をすると
Floki.find(body, "span.counter")
[{"span", [{"class", "counter"}], ["\n 3\n "]},
{"span", [{"class", "counter"}], ["\n 12\n "]},
{"span", [{"class", "counter"}], ["\n 2\n "]},
{"span", [{"class", "counter"}], ["\n 2\n "]}]
共通のタグとクラスのデータのレポジトリ数, star数なども取れてしまいます。
ですがリストの2番目(3要素目)に入っていることがわかっているのでlist[2]を指定してデータを取得します。
iex(34)> Floki.find(body, "span.counter") |> Enum.at(2)
{"span", [{"class", "counter"}], ["\n 2\n "]}
Enum.at(2)でlistの2番目を取得することができました。
ですが今は{tag, attribute, text}のtuppleが帰って来ています。
textを取得するためには
iex(37)> Floki.find(body, "span.counter") |> Enum.at(2) |> Floki.text()
"\n 2\n "
これで取りたいfollowerの数が取れたのですが, 改行コードも付いて来てしまったのでパースしたいと思います。
iex(42)> followers = Floki.find(body, "span.counter") |> Enum.at(2) |> Floki.text()
"\n 2\n "
iex(43)> String.strip(followers)
"2"
String.strip(変数)で改行コード, 空白文字をremoveしました。
一応取得したかったfollower数を取得することができました。
振り返ってみると今回のスクレイピングは一行でかけましたね。
HTTPoison.get!("https://github.com/takpy").body |> Floki.find("span.counter") |> Enum.at(2) |> Floki.text() |> String.strip()
パイプライン演算子は本当に気持ちがいい...