koudenpaのブログ

趣味のブログです。株式会社はてなでWebアプリケーションエンジニアをやっています。職業柄IT関連の記事が多いと思います。

葬送のフリーレン人気投票のツイートを収集・集計表示して遊んでいた

令和最強のハイファンタジーマンガ葬送のフリーレンTwitter上でオープンに人気投票をやっている。オープンなら投票状況を見たくなるのが人情である。

またBlazor WebAssemblyなんだ。何かしらのデータセットチャート系のコンポーネントは相性がいいはずなのでそのうち試しておきたかったところに、ちょうどよい題材があってラッキーといったところ。

まだとりあえず表示しただけなので、インタラクティブに可視化の軸を変えたいと思いつつ、そういうのはスクラッチのWebアプリケーションではなく、適切なデータセットをBIツール(それこそPower BI)に入力するのがいいのではないか? と思わなくもない状態。投票数がどういう推移をしていったのかは眺めたいので、何かしらの形で処理したいとは思う。

追記:最低限という感じで時刻を遡った結果を見られるようにした。面白い。

https://7474.github.io/Frieren2022Checker/

Twitterをデータソースに遊ぶ際のTipsというか、今後こうしようかなー、を少しまとめておく。

今回の集計の要件

  • 特定のハッシュタグのツイートを集計する
    • #フリーレンアニメ化記念キャラ人気投票
  • 追加のハッシュタグに応じて投票数に係数を掛ける
    • #ツイートで1000票
    • #ツイートと葬送のフリーレンフォローで10000票
  • 追加のハッシュタグによっては特定のアカウントのフォローを有効票の条件とする
    • 今回はこれは要件から落とした
    • 「誰が」どのキャラクターに投票した、の様な個人情報味のある情報を手元に保存したくなかった
  • 最後のハッシュタグが投票先キャラクターである

詳しくは葬送のフリーレン人気投票ページを参照されたい。

websunday.net

アプローチ

この手の集計は、データの収集と、集計を分けてしまうといいのだろう。

  1. TwitterAPIを使って必要なデータ(ツイート)を収集して保存
  2. 保存したデータを要件に従って集計

これが良い。

当初はもっと雑に収集と集計をやってとりあえず見られれば良いや、としていたのだけれど、いろんな軸で見たいとなったらこれしかない。

保存するデータは全量にしておいて、加工する段になって不要なデータを弾く。そうしておくと、いろんな軸で可視化しやすくなってよろしい。

これが極まってくると、データレイクだとかデータマートだとかになってくるのだろう。

TwitterAPIを使って必要なデータ(ツイート)を収集して保存

好きな言語の好きなSDKを使って収集、必要な情報に絞って保存すればOK!

何でもいいよ、何でも。

とは言え、多少は再利用性を考えないとCIし辛い(←いまここ)ので、CLIで実行しやすい形にしておくのがいいのではないかと思う。

今回はC#TweetinviAPIはv1.1のSearch APIを使った。

収集、保存したのは「何時、誰に、何票」投票されたか。投票企画の要件的には「誰が」投票したのか? も必要だが、今回はその辺手元に持つのがなんか嫌だったので省いた。

この記事を書いている時点でのコード(目が腐るので見ないほうがいいと思う)

// ざっくりこんな感じ
// Search APIで全件取る
var tweetsOf10000 = await FetchAllAsync(appClient.Search.GetSearchTweetsIterator("#ツイートと葬送のフリーレンフォローで10000票"));

// ツイート内容から必要な情報だけ取り出す
 var raw = tweetsOf10000
    .Select(x => new RawVote(
        Timestamp: x.CreatedAt,
        Target: x.Hashtags.LastOrDefault()?.Text,
        Count: 10000
    ));

// とりあえずダンプ
File.WriteAllText($"./raw-{DateTimeOffset.Now.ToString("yyyyMMddHHmmss")}.json", JsonConvert.SerializeObject(raw));

// 全件イテレートするメソッド
static async Task<IEnumerable<ITweet>> FetchAllAsync(ITwitterIterator<ITweet, long?> ite)
{
    var res = new List<ITweet>();
    while (!ite.Completed)
    {
        res.AddRange((await ite.NextPageAsync()));
    }
    return res;
}

Twitterデベロッパーサイトを眺めていたらアンケートが出てきたので「いつになったらv2 APIはv1.1 APIでできていたことが簡単にできるようになるんですか? 現状は最悪です」的な回答をしておいた。

イーロンの買収が立ち消えになってマジショックである。なんとかTwitterのDXは持ち直してほしい。

保存したデータを要件に従って集計

これは結構曲者で「どういう風に見たいか?」がフワッとしていると可視化はできない。

取り合えずキャラクターごとの総得票は間違いのないものなので、それを見てみることにした。

可視化に使ったBlazor WebAssemblyは.NETなのでLINQを使えて便利。

Web上に先に取得した「何時、誰に、何票」投票されたかのデータを配置しておいて、読み込み、加工する。

この記事を書いている時点でのコード

// ざっくりこんな感じ
// これだけでWeb上に配置したJSONがオブジェクトになる、最高か?
votes = await Http.GetFromJsonAsync<Vote[]>("votes.json");

// 後は適当に集計する
var totalData = votes?
    .GroupBy(x => x.Target)
    .Select(x => new Vote { Target = x.Key, Count = x.Sum(y => y.Count) })
    .OrderByDescending(x => x.Count)
    .ToList() ?? new List<Vote>();

// チャート表示はライブラリ任せなので省略

要件に忠実にするなら、公式アカウントのフォロワーデータも用意しておいて、集計の前段階のどこかしらでフィルタするのが良いと思う。

オチ

特になし。なくてもよい。

葬送のフリーレンは大好きマンガなので、そのアニメ化&連載100回記念企画を自分として極限まで楽しみたいと遊んでいた次第。

プログラムできるとこういう遊びもできてよい。今ならノーコードツールでも遊べると思うので、みんなもITで遊ぼう!