🧪

ElixirでQiitaAdventCalendarの執筆者リストを作る

2022/12/09に公開

intro

この記事は、「Elixir Advent Calendar 2022」その1の9日目の記事です。
https://qiita.com/advent-calendar/2022/elixir

8日目は @Yoosuke さんの「Elixir × GraphQLシリーズ① ~ サクッとGraphQLサーバーのセットアップ ~」でした!

概要

今年のElixirのAdvent Calendarはスゴイ勢いですね!
カレンダーが9つもあり、どれもほとんど埋まっていて大盛況です。

今回はQiitaのAdventCalenderの執筆者を数えるプログラムをElixirで作ってみました。

リポジトリ

https://github.com/yellowsman/qiita_advent_calendar_user_counter

こんなプログラム

実装は下記のようになっています。
単純にQiitaのアドベントカレンダーのページを取得してユーザー情報の部分だけ抜き出してカウントしています。
記事を投稿しているかどうかに関わらず枠予約されていればカウントします。

lib/qiita_advent_calendar_user_counter.ex
defmodule QiitaAdventCalendarUserCounter do
  import Meeseeks.CSS

  @spec run(Calendar.year()) :: map()
  def run(year \\ Date.utc_today().year, language \\ "elixir") do
    request_body("https://qiita.com/advent-calendar/#{year}/#{language}", 0)
    |> Meeseeks.parse()
    |> Meeseeks.fetch_all(css(".css-1covvrn .css-15wswuq .css-h63oov"))
    |> elem(1)
    |> Enum.map(fn x -> Meeseeks.text(x) |> String.replace(" ","") end)
    |> Enum.frequencies
    |> Enum.sort
  end

  defp request_body(_, 10), do: "over retry challenge count!"
  defp request_body(target_url, retry_count) do
    result = HTTPoison.get!(target_url)

    case result.status_code do
      200 ->
        result.body

      _ ->
        :timer.sleep(1000)
        request_body(target_url, retry_count + 1)
    end
  end
end
mix.exs
defmodule QiitaAdventCalendarUserCounter.MixProject do
  use Mix.Project

  def project do
    [
      app: :qiita_advent_calendar_user_counter,
      version: "0.1.0",
      elixir: "~> 1.13",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      {:httpoison, "~> 1.8"},
      {:meeseeks, "~> 0.16.1"}
    ]
  end
end

解説

簡単なプログラムなので特に解説することもありませんが、QiitaのAdventCalendarのページを取得してきてMeeseeksライブラリでパースしたり必要な要素を取り出して Enum.frequencies/1 でキー名(= アカウント名)ごとに件数を数えています。

MeeseeksはHTML/XMLパーサです。Elixirではこの手のライブラリはFlokiが有名ですが、今回は勉強も兼ねてMeeseeksを使いました。
MeeseeksとFlokiの比較はMeeseeksが作ったドキュメントがあります。
https://github.com/mischov/meeseeks/blob/main/guides/meeseeks_vs_floki.md

他には、QiitaAdventCalendarUserCounter.run/2 に年と言語を指定すれば過去のカレンダーや他の言語のカレンダーを調べることも可能です。
年は2021年まで対応できているのを確認しています(それ以前はDOM構造が変わっているためパース失敗)

結果

※ 結果は 2022年12月9日現在のものです

iex(1)> QiitaAdventCalendarUserCounter.run()
[
  {"@Alicesky2127", 27},
  {"@GKBR", 1},
  {"@GeekMasahiro", 8},
  {"@Goody27", 1},
  {"@Gsann", 1},
  {"@MzRyuKa", 1},
  {"@RyoWakabayashi", 46},
  {"@ShigeItoEx", 7},
  {"@ShozF", 2},
  {"@Yoosuke", 8},
  {"@a_utsuki", 1},
  {"@def_elixir", 1},
  {"@gx3n-inue", 1},
  {"@hiro_1107", 1},
  {"@hisaway", 1},
  {"@k-j-y", 2},
  {"@kikuyuta", 1},
  {"@koga1020", 3},
  {"@koyo-miyamura", 1},
  {"@kyawaguchi", 1},
  {"@miwacchi", 5},
  {"@mnishiguchi", 34},
  {"@mokichi", 1},
  {"@myasu", 1},
  {"@nako_sleep_9h", 28},
  {"@nanbut14", 1},
  {"@naritomo08", 2},
  {"@ohr486", 1},
  {"@piacerex", 25},
  {"@pojiro", 1},
  {"@t-kurasawa", 1},
  {"@t-yamanashi", 8},
  {"@ta_to_jp", 2},
  {"@tamanugi", 1},
  {"@the_haigo", 13},
  {"@tomoaki-kimura", 1},
  {"@torifukukaiou", 45},
  {"@tuchiro", 1},
  {"@westbaystars", 3},
  {"@zacky1972", 26}
]

まとめ

ElixirでQiita AdventCalendarの執筆者リストを出力してみました。
大勢の方が参加されていることが具体的な数値で分かってElixirの人気っぷりが分かりますね!

明日は @t-yamanashi さんの「Elixirで音を鳴らして遊ぼう」です!お楽しみに!

Discussion