23
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Qiita】ひとりアドベントカレンダー2025年の完走率を調査してみたよ

Posted at

Qiitaアドベントカレンダーには、ひとりで25記事以上を投稿すると賞品をもらえる完走賞があります。

02.png

中でも一人でひとつのアドベントカレンダーを埋め尽くす、ひとりアドベントカレンダーを走っている人が毎年散見されます。
2025年には他者が参加することのできない専用のカレンダーまで用意されていました。

ということで、これは何名がひとりアドベントカレンダーに挑戦し、そのうちどれほどが完走したかを調べてみたという嫌がらせ記事になります。

調査のためのデータ抽出を行ったのは2025/12/29です。

調査結果

全アドベントカレンダー数、1502件。

うち、参加者がひとりのカレンダー、550件。
うち、完走数、165件。
うち、ぬいぐるみGET、141件・118名。

完走率は30%でした。
2023年が30.6%、2024年が30.2%と、だいたい3割で安定していますね。
完走数は昨年の122件からさらに増えて165件になりました。
順調に規模が拡大しつつありますね。

ぬいぐるみはQiita内に記事を投稿していないといけないため、外部サイトに投稿している人はもらえません。
最終的にぬいぐるみをGETできる人は118名となりました。

ロジック

アドベントカレンダーを全て拾い出す → 走者が一人しかいないアドベントカレンダーを抽出する → 全日程にリンクがあれば完走、という単純なロジックです。

プログラム自体は最後に載せておきます。

HTMLが自動生成なせいでclass="style-1dw8kp9"みたいな無機質なCSS名となっており抽出が非常につらいことになっています。
ちゃんと意味のある名前にしてくれ。

ぬいぐるみGETカレンダー一覧

以下の141カレンダー、118名です。

アイレット株式会社 by @personal_linyang
アイレット株式会社 by @na-tamura
ひとりアドカレ | 2025に学んだことの振り返り by @benjuwan
凡庸なシニアフロントエンドエンジニアが考えていること by @h-kinocoboy
Rails基礎固め25のTips by @gon0821
社内ソフトウェア開発 by @u1murayama
React HooksをHackしよう! by @JavaLangRuntimeException
「リクエスト&レスポンス理解シリーズ」 by @chdkm
picoCTF by @OzakiRoy
初アドカレにひとりで挑戦🎄🦌🎁 by @Ryuki4648
プロダクトエンジニアへの道 by @saka2jp
fiord by @fiord
初挑戦カレンダー by @silvia_hacks
IoTっぽいこと by @gzock
ふぐおの配信関係多めひとり by @boxfish_jp
わかっている「つもり」を叩き直す by @mattsu_mocha
ひとりでつくるSaaS - 設計・実装・運用の記録 by @pipipi-dev
アセンブラ by @ohisama@github
アセンブラ by @ohisama@github
個人 by @lamela
Hugo+BlowfishでWebサイトを作ってみた。ひとり by @dokokanoradio
GLSL by @ohisama@github
2025年の技術的な取り組みまとめ by @noissefnoc
Structive by @mogera551
はじめてのひとり by @omunomi
ワイの最強セルフホスティング by @sinsky
【リアルタイム電力予測】需要・価格・電源最適化ダッシュボード構築記 by @nakamin
七夕凛 by @ysmreg1
七夕凛 by @ysmreg1
七夕凛 by @ysmreg1
七夕凛 by @ysmreg1
ゆっくりテックウォッチ by @sumihiro3
クリスマスに✝️俺の考えた最強のCMS✝️をつくる by @yuriacats
Wanna be a GameCreator by @darknes_henohenon
My Engineer Journey by @future_kame
使っているクラウドなどの小ネタ Advent Calendar 2025 by @Keiji_otsubo
Gforth by @ohisama@github
【完走チャレンジ】2025年わたしが学んだことまとめ by @Maruhoppe8
『IBM愛』で綴る IBM i アドベントカレンダー by @yanagih
DF Yamashita by @yam_dev
ひとりアドカレbyタカハシ by @tttol777
ゼロから始めるAI駆動開発+Claude Code by @rf_p
HonoのマージされたPRを読んでいく by @MIDO-ruby7
技術書しっかりやり込もう2025 by @tatataichi
手探りしてみる CV/ ML/ NN by @masahiroteraoka
AI Coding Challenge by @zzzzico
25日間でCocos Creatorでゲームを作る by @riku_pa
Tech888’s Calendar by @tech888
インフォマティカ・ジャパン株式会社 by @shunsuzu
K4e Linux Distros by @Kanade147359
AWS初歩ミス図鑑 by @ei_540
anyプロダクトチーム by @ad-sho-loko
25日間でC言語をマスターしよう by @edamame2525
ひとりアドカレ@yS by @yshimizu
25日で分かるAIの基礎 by @pandausa
オレオレ開発環境をシェアして、自分の派閥を広げよう by @nattyan_tv
yua by @sasachi
【Laravel + Inertia + Vue】VILT Stackを流行らせる by @sigeta
mqtt by @heyanaohiro
やきとりの一人アドカレ by @IMattheZOO
科学と神々株式会社 by @jasagiri
科学と神々株式会社 by @jasagiri
科学と神々株式会社 by @jasagiri
科学と神々株式会社 by @jasagiri
科学と神々株式会社 by @jasagiri
2025 年の個人的な登壇+αを振り返る by @hmatsu47
初参戦完走 by @38MIYA
AWS 無料枠使い倒し by @ShingoKamiya
競技プログラミングに関する知見をシェアしよう|2025 by @SHori358Plus
ぼっち論文サーベイメモ2025 by @matumu20
techno-robocup by @rotarymars
今年のQiitanはスヤスヤver!?Qiitanは何個あっても欲しくなる by @tanimoto-hikari
Unityでつくる2DRPG by @ShrineGate3544
Daily CTF Upsolve Reversing Edition by @colza_
2025年の振り返り by @chi1180
あくあ by @Aqua-218
あくあ by @Aqua-218
あくあ by @Aqua-218
あくあ by @Aqua-218
あくあ by @Aqua-218
あくあ by @Aqua-218
AWS Lambda 実践入門 by @mamono210
マルチテナントSaaSにおけるエンジニアリング大全 by @ad-sho-loko
がちもとさん by @SatoshiGachiFujimoto
Daily Crypto CTF by @potyamaaaa
めんどい太郎の by @mendoitarou_
ひとりCloudflareを使い倒す by @toreis
miriwoお一人様 by @miriwo
ラクスパートナーズ by @H-Iida
ラクスパートナーズ by @mzuk
AWS Community Buildersになるために書きまくる by @yama3133
Direct3D Basic Programming in DirectXTK/XTK12 by @YKVKDX12
kazuedaの活動記録2025 by @kazueda
Rustでずんだもんが代理でしゃべるSIP電話を作る by @Massy0127
ぺんぎん by @penguin425
今年こそQiitanを貰う by @mementotacopi
Python×Plotly 3Dチャレンジ(高橋のカレンダー) by @Tadataka_Takahashi
学生ひよこ界隈が送るGo/Javaで実現する「はじめてのバックエンド」 by @mamenz752
EDPC by @kaz_tsu
Rust+SvelteKit+CDKでRSS要約アプリを作ってみる by @k4nd4
秘密じゃない花園 by @EgaSaQA
IBMが提供する製品に関する情報やナレッジを共有する_第2弾 by @yanagih
真のエンジニアを目指して2025 by @devmatsuko
私がこっそり教える「見てよかった」リスト by @itaya
数学アートギャラリーをつくっていく by @cocoakamen
やくも by @yakumo_09
Atsushi's by @AS_atsushi
鎮宮's by @sigure_sizumiya
すやすやverが欲しいよ by @omu58n
パイソニスタの一人アドカレ by @Pythonista_
生成AIセキュリティ by ナレコム by @akiraokusawa
keitaMax by @keitaMax
Elixir by @the_haigo
FORTH ベーシックマスター by @spumoni
LISP ベーシックマスター by @spumoni
kkfactory by @koji0705
技術同人誌執筆の軌跡 by @Kerdy
claustra01's Daily CTF by @claustra01
日本語プログラミング仕様記述言語 Re:Mind(リマインド) by @mylifewithviolin
【個人用】競プロ関係+α by @comet725
生成AIで遊びながら学ぶ by @nao_manabitan
デジタル創作サークルUniProject by @Aqua-218
デジタル創作サークルUniProject by @ysmreg1
デジタル創作サークルUniProject by @Aqua-218
新社会人のSalesforce学習記録とその他 by @Aruhimanahito
俺の2025年 by @nomurasan
STM32×AIで「3軸倒立振子」を作る25日間(ひとりアドカレ) by @RamTuckey
Qiita株式会社 by @degudegu2510
ひとりアドベント(Affinity) by @harycurl
ひとりアドベント(Affinity) by @harycurl
Jibakure by @Jibakure
AtCoderでプログラミング初心者にPythonを教える by @azubiwa
Rosetta Code で楽しむプログラミング by @gotoki_no_joe
3 年で飽きる by @e99h2121
エンジニアのながらキャッチアップ by @ennagara128
ZOZO by @shiozaki
ktrkが頑張る by @ktrk2002
ハウインターナショナル by @torifukukaiou
中部大学 新谷研究室 Advent Calendar 2025:サルコメア動態(HSOs/S4C)と Chaordic Homeodynamics by @Seine_A_Shintani
中部大学 新谷研究室 Advent Calendar 2025:サルコメア動態(HSOs/S4C)と Chaordic Homeodynamics by @Seine_A_Shintani
hooq by @namn1125

ただし『最終的な達成者は、コミュニティガイドラインに則していない記事が含まれていないか、運営が投稿内容を確認・審査の上で選定いたします』という条文があるので、中身のない記事しか書いていないユーザは弾かれる可能性があります。

また、正確なぬいぐるみゲット条件は『Qiita記事に1人で25記事投稿しきった方』なので、複数のアドベントカレンダーで合わせて25記事投稿した場合も対象となります。
その対象者は、このリストには含まれていません。
全アドベントカレンダーのリストは取得してあるので単純に合計すれば簡単に出せるのですが、面倒なのでまあいいや。

感想

完走者のみなさんおめでとうございます。

今回は一人で何シリーズも走っている人が目立ちますね。
どれだけ書きたいことがあるというのだ。

プログラム

一回動けばそれでいいの精神で作られています。
とか言いつつ3年使い回してますけどね。

まずアドベントカレンダーをぜんぶダウンロードしてローカルに保存する。

(new A())->run();
class A
{
    public function run()
    {
        // 新着カレンダーを全取得
        $this->getCalendarsList();

        // 新着カレンダーを順に処理
        $files = glob('./list/*');
        foreach ($files as $file) {
            echo 'Start ' . $file . "\n";
            $this->getCalendar($file);
        }
    }

    /**
     * 新着カレンダーページから個々のカレンダーを取得してローカル保存する
     * @param string $file ファイル名
     */
    public function getCalendar(string $file)
    {
        $html = file_get_contents($file);

        // カレンダーへのリンクを取得
        $pattern = '|<a aria-label="Open calendar" href="(.*?)" tabindex=|us';
        
        preg_match_all($pattern, $html, $matches);
        foreach ($matches[1] as $tmp) {
            // ページを取得
            $url = 'https://qiita.com' . $tmp;
            echo 'Downloading ' . $url . "\n";
            $html = file_get_contents($url);
            // ローカルに保存
            file_put_contents('./calendar/' . basename($tmp) . '.html', $html);
            sleep(1);
        }
    }
    private $cnt = 1;

    /**
     * 新着カレンダーを全取得してローカル保存する
     */
    public function getCalendarsList()
    {
        // ページ数は直接確認したので手抜き
        $urlp = 'https://qiita.com/advent-calendar/2025/calendars?page=';
        $page = 0;
        while ($page++ < 55) {
            // ページを取得
            $url = $urlp . $page;
            $html = file_get_contents($url);
            // ローカルに保存
            file_put_contents('./list/page' . $page . '.html', $html);
        }
    }
}

中身を分析する。

(new A())->run();
class A
{
    public function run()
    {
        $output = [];
        // ファイル
        $files = glob('./calendar/*');

        // カレンダーごとに中身を分析
        foreach ($files as $file) {
            echo 'Analyzing ' . $file . "\n";
            $html = file_get_contents($file);
            $url = substr($file, 11);
            $output[] = $this->analyze($url, $html);
        }
        // 終了
        file_put_contents(
            './analyse.json',
            json_encode(
                $output,
                \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE
            )
        );
    }

    /**
     * HTMLを調べる
     * @param string $url  URL
     * @param string $html HTML
     */
    public function analyze($url, $html)
    {
        $ret = [];
        // タイトル
        $pattern = '|<title>(.*?) - Qiita Advent Calendar 2025|us';
        preg_match($pattern, $html, $matches1);
        $title = $matches1[1];

        // 大ざっぱに切り取り
        $pattern = '|<section class="style-1covvrn">(.*)<section class="style-196d0fg"><div class="style-1i27l4i">|us';
        preg_match($pattern, $html, $matches1);
        $html = $matches1[1];

        // シリーズに分割
        $pattern = '|<section class="style-t7g594">(.*?)</section>|us';
        preg_match_all($pattern, $html, $matches);

        // シリーズごとにループ
        foreach ($matches[1] as $k => $calendar) {
            // 判定
            $tmp = $this->check($calendar);
            $tmp['title'] = $title;
            $tmp['series'] = $k + 1;
            $tmp['url'] = 'https://qiita.com/advent-calendar/2025/' . basename($url, '.html');
            $ret[] = $tmp;
        }

        return $ret;
    }

    /**
     * シリーズごとに判定
     * @param  string $calendar カレンダーのHTML
     * @return array  [user, complete, qiita]
     */
    private function check($calendar)
    {
        $ret = [
            'user' => null,
            'only' => true,     // 一人か
            'complete' => true, // 完走
            'qiita' => true,    // Qiitaか
            'count' => 0,       // 埋まった件数
        ];

        // 記事ごとに分割
        $pattern = '|<td class="style-1dw8kp9"><div class="style-1ssbn0c">(.*?)aria-labelledby="OtherCalendarInfo-label"|us';
        preg_match_all($pattern, $calendar, $posts);

        // 記事でループ
        foreach ($posts[1] as $post) {
            // ユーザ名
            $pattern = '|@<!-- -->(.*?)</a>|us';
            preg_match($pattern, $post, $matches);
            
            if (isset($matches[1])) {
                if ($ret['user'] === null) {
                    $ret['user'] = $matches[1];
                } elseif ($ret['user'] !== $matches[1]) {
                    $ret['complete'] = $ret['qiita'] = $ret['only'] = false;
                }
            }

            // 記事リンク
            $pattern = '|<div class="style-mpez5z"><a href="(.*?)"|us';
            preg_match($pattern, $post, $matches);
            if (!isset($matches[1])) {
                $ret['complete'] = $ret['qiita'] = false;
                return $ret;
            }

            // Qiita内か
            if (!str_starts_with($matches[1], 'https://qiita.com')) {
                $ret['qiita'] = false;
            }

            ++$ret['count'];
        }

        // 最後まで進んだ
        if ($ret['count'] < 25) {
            // 登録が足りない
            $ret['complete'] = $ret['qiita'] = false;
            return $ret;
        }
        return $ret;
    }
}

正規表現パターンをCopilotに書いてもらおうとしたけどてんで駄目だった。

23
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?