Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Qiita Advent Calendar 2023

livebooks/qiita/calender_2023.livemd

Qiita Advent Calendar 2023

Mix.install([
  {:req, "~> 0.5"},
  {:req_easyhtml, "~> 0.1"},
  {:explorer, "~> 0.9"},
  {:kino, "~> 0.14"},
  {:kino_vega_lite, "~> 0.1"}
])

準備

alias Explorer.DataFrame
alias Explorer.Series
require Explorer.DataFrame

カレンダーデータの取得

req =
  Req.new(http_errors: :raise)
  |> ReqEasyHTML.attach()
calendar_df =
  req
  |> Req.get!(url: "https://qiita.com/advent-calendar/2023/elixir")
  |> then(& &1.body["[data-js-react-on-rails-store=AppStoreWithReactOnRails]"].nodes)
  |> Floki.text(js: true)
  |> Jason.decode!()
  |> get_in(["adventCalendars", "tableAdventCalendars"])
  |> hd()
  |> Map.fetch!("items")
  |> Enum.frequencies_by(&get_in(&1, ["user", "urlName"]))
  |> then(fn map ->
    %{
      name: Enum.map(map, fn {name, _} -> name end),
      count: Enum.map(map, fn {_, count} -> count end)
    }
  end)
  |> DataFrame.new()
  |> dbg()

データテーブルの表示

calendar_df
|> DataFrame.sort_by(desc: count)
|> Kino.DataTable.new()

グラフの表示

x = Series.to_list(calendar_df["name"])
y = Series.to_list(calendar_df["count"])

VegaLite.new(width: 800, height: 400)
|> VegaLite.data_from_values(x: x, y: y)
|> VegaLite.mark(:bar)
|> VegaLite.encode_field(:x, "x", type: :nominal, sort: "-y", title: "アカウント名")
|> VegaLite.encode_field(:y, "y", type: :quantitative, title: "記事数")