Qiita
ポエム
シェル芸

Qiitaレジェンド達の偉大さをシェル芸で眺めて2016年を振り返る

More than 1 year has passed since last update.

2016年の振り返り

eto_saru_kakizome.png

私事ですが、2016年のQiita振り返りをさせていただきます。
2016年に投稿したQiitaの記事は17本、これで18本目になります。

平均すると1カ月に1本以上書いてはいるのですが、時期的にはやはり波がありますね。
ネタのストックがなかったとか DevOps導入指南 執筆のタイミングと被ったとかいうのもあるかもしれませんが、下期は全体的に少なかったです。
1年の中で印象深かったのは、

の記事で、ありがたいことにこれだけで2000を超えるいいね1をいただくことができ、他の記事とあわせて年初に500程度だった総Contributionは現時点で3700を超えるまでになりました。

個人的にこうした数字で見える成果は好きなので、来年もアウトプットを続けるモチベーションになったと思っています。

Contributionの分析

tantei_boy.png

さて、現時点での総Contributionは上の記事1本によるところが大きいのですが、ちょっとContributionの分析をやってみます。

  • 総Contribution
  • 記事数
  • 記事あたりの平均Contribution(平均)
  • Top記事によるContribution(Top数)
  • Top記事によるContributionが総Contributionに占める割合(Top占有率)
総Contribution 記事数 平均 Top数 Top占有率
3799 26 146.115 2390 62.91%

という感じでした。
やはりTop記事による占有率が半分以上、運の要素があるとはいえ、ぽっと出感が否めません。
継続的によいアウトプットを出しつつ、よりContributionを高めていきたいと思います( 使命感 )

Qiitaレジェンド達はどうか

moses_umi.png

それではQiitaで 総ContributionのTOP100をひた走るQiitaレジェンド達 はどうなのでしょうか。

まず、Qiitaレジェンドの一覧を得なければなりません。

ありがたいことにランキングサイトを作ってくださった方がいました。たまに見てます^^(病気)。
そういえば現時点で僕は104位でした。もう少しでTOP100入り...!

こちらでTOP1002のユーザを確認することができます。
あとはそれぞれのユーザを確認してちまちま計算すれば大丈夫そうです。

それでは、地道に収集、計算していきたいと思います。
なお、たまたま私は シェル芸人3 を目指しておりますので、地道にワンライナーでの収集、計算にチャレンジします。環境はCentOS 7.2.15114です。

$ for PAGE in $(seq 1 5) ; do for USER in $(curl -s https://qiita-user-ranking.herokuapp.com/?page=${PAGE} | grep -E "第[0-9]*位" -A 1 | grep href | sed -e "s/^.*href=\".*\">\(.*\)<\/a>.*$/\1/g") ; do echo -en "@${USER}\t" ; curl -s http://qiita.com/${USER} | grep Contribution | sed -e "s/^.*<span class=\"userActivityChart_statCount\">\([0-9]*\)<\/span><br \/> <span class=\"userActivityChart_statUnit\">Contribution<\/span>.*<span class=\"userActivityChart_statCount\">\([0-9]*\)<\/span><br \/> <span class=\"userActivityChart_statUnit\">Items<\/span>.*<span class=\"fa fa-like\"><\/span> \([0-9]*\)<\/div>.*<a itemprop=\"url\" href=\"\(.*\)\">\(.*\)<\/a><ul class=\"list-inline userPopularItems_tags tagList\">.*\(itemprop.*\)\{,4\}.*$/\1\t\2\t\3\t\[\5\](http:\/\/qiita.com\4)/g" ; done ; done | awk -F"\t" '{if(NF==5) print "|"NR"|"$1"|"$2"|"$3"|"$2/$3"|"$4"|"$4/$2*100"%|"$5}'

出力がそのままMarkdownの表形式になるようにしたので見出しをつけてペタリ。

ランク ユーザ名 総Contribution 記事数 平均いいね Top数 Top占有率 Top記事
1 @hirokidaichi 30990 33 939.091 4641 14.9758% ペアプログラミングして気がついた新人プログラマの成長を阻害する悪習
2 @jnchito 26953 135 199.652 2478 9.19378% モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう
3 @suin 20120 652 30.8589 4034 20.0497% 【まとめ】これ知らないプログラマって損してんなって思う汎用的なツール 100超
4 @icoxfog417 18927 124 152.637 2057 10.8681% Pythonを書き始める前に見るべきTips
5 @shu223 17091 156 109.558 1239 7.24943% ディープラーニングの有名ライブラリ5種を最短距離で試す半日コース(TensorFlow, Chainer, Caffe, DeepDream, 画風変換)
6 @KeithYokoma 16737 138 121.283 3919 23.4152% うまくメソッド名を付けるための参考情報
7 @yuku_t 16134 182 88.6484 1352 8.37982% 中規模Web開発のためのMVC分割とレイヤアーキテクチャ
8 @kenju 15443 120 128.692 2173 14.0711% 中上級者になるためのJavaScript【知識編】
9 @KENJU 15443 120 128.692 2173 14.0711% 中上級者になるためのJavaScript【知識編】
10 @mizchi 15101 162 93.216 1795 11.8866% 春からはじめるモダンJavaScript / ES2015
11 @awakia 14642 150 97.6133 1547 10.5655% 開発フロー研修 @ Wantedly
12 @opengl-8080 14161 211 67.1137 1205 8.50929% AngularJS使い方メモ
13 @mpyw 13960 235 59.4043 1732 12.4069% PHPでデータベースに接続するときのまとめ
14 @mono0926 13289 89 149.315 1315 9.8954% ローディング時のズルい進捗表示
15 @muran001 12312 34 362.118 4191 34.04% Gitでやらかした時に使える19個の奥義
16 @haminiku 12144 70 173.486 2800 23.0567% 2016年 独りで新規WEBサービスを開発・運用した際の知見
17 @b4b4r07 11652 56 208.071 1430 12.2726% さいつよのターミナル環境を構築しよう
18 @appwatcher 11583 59 196.322 2004 17.3012% iOSでこんなアプリ,こんな機能を作りたかったらこれを見ろ!作りたいアプリに対応するクラス、フレームワーク、ライブラリのまとめ!
19 @edo_m18 11550 363 31.8182 1017 8.80519% WebのUIテスト自動化 - Seleniumを使ってみる
20 @cognitom 11489 89 129.09 1678 14.6053% そろそろ真面目に、HTMLで帳票を描く話をしようか
21 @susieyy 10847 47 230.787 1877 17.3043% Swiftで作られたイケてるUIライブラリたち
22 @kazunori279 10262 36 285.056 1259 12.2686% Cloud Vision APIの凄さを伝えるべくRasPi botとビデオを作った話
23 @yimajo 10247 127 80.685 688 6.71416% iOS実機のSSL通信をプロキシによって傍受したり改ざんする方法
24 @hkusu 9243 201 45.9851 963 10.4187% [WEB開発] 私的な最近のおすすめサービス/ツール 14選 ~2014年版~
25 @zaru 9393 96 97.8438 1525 16.2355% Webフロントエンド表示速度、最速化手法まとめ
26 @uasi 9000 116 77.5862 1977 21.9667% 英語のコメントや issue で頻出する略語の意味 (FYI, AFAIK, ...)
27 @kidach1 8990 83 108.313 1261 14.0267% Nginx導入時、サクッと対応しておくと良いかもしれない
28 @ynakayama 8937 186 48.0484 632 7.07172% 機械学習や統計に関する情報収集
29 @HirofumiYashima 8947 633 14.1343 482 5.38728% クロージャってどんなときに使うの? ~ 利用場面を 3つ 挙げてみる
30 @joker1007 8766 96 91.3125 999 11.3963% てめえらのRailsはオブジェクト指向じゃねえ!まずはCallbackクラス、Validatorクラスを活用しろ!
31 @koher 8540 50 170.8 1247 14.6019% null安全でない言語は、もはやレガシー言語だ
32 @tukiyo3 8527 1421 6.0007 356 4.17497% たくさんあるオープンソースライセンスのそれぞれの特徴のまとめ
33 @kenmatsu4 8515 60 141.917 1557 18.2854% 【機械学習】ディープラーニング フレームワークChainerを試しながら解説してみる。
34 @takeharu 8302 18 461.222 1304 15.7071% JavaScriptの「this」は「4種類」??
35 @hshimo 8075 276 29.2572 2051 25.3994% プログラマが独立・起業する時によくするミスと対策 まとめ
36 @tadsan 7795 145 53.7586 1856 23.8101% ライセンスの選択を恐れる必要はありません
37 @kawasima 7707 73 105.575 634 8.22629% 多い日も安心設計
38 @usagimaru 7578 155 48.8903 879 11.5994% iOS ヒューマンインターフェースの原則
39 @kawaz 7563 138 54.8043 1941 25.6644% 最強のSSH踏み台設定
40 @sion_cojp 7343 33 222.515 3473 47.2967% インフラエンジニアとしてよく使うコマンド集
41 @syui 7318 211 34.6825 1344 18.3657% MacBookAirで使っている便利ツール
42 @okappy 7218 28 257.786 4918 68.1352% 非デザイナーエンジニアが一人でWebサービスを作るときに便利なツール32選
43 @gaogao_9 7084 13 544.923 3963 55.943% 旧石器時代のJavaScriptを書いてる各位に告ぐ、現代的なJavaScript超入門 Section1 ~すぐにでも現代っぽく出来るワンポイントまとめ~
44 @zembutsu 6870 76 90.3947 1262 18.3697% Docker 入門ハンズオン資料
45 @kaiinui 6809 46 148.022 2474 36.3343% 最近の行儀のよい JavaScript の書き方
47 @vvakame 6648 39 170.462 1201 18.0656% Gradle入門
48 @Jxck_ 6580 62 106.129 1055 16.0334% DELETE_FLAG を付ける前に確認したいこと。
49 @tbpgr 6386 681 9.37739 667 10.4447% Markdown記法 サンプル集
50 @armorik83 6366 107 59.4953 1321 20.7509% AngularJSモダンプラクティス
51 @Quramy 6351 75 84.68 1767 27.8224% Electronでアプリケーションを作ってみよう
52 @yuya_presto 6324 38 166.421 754 11.9228% Gitコンフリクト解消ガイド(git mergetoolの使い方)
53 @gogotanaka 6129 56 109.446 3237 52.8145% ネイティブと働いて分かった英語コミットメッセージの頻出動詞10つ
54 @yaotti 5895 151 39.0397 1251 21.2214% gitでありがちな問題の解決方法まとめ
55 @n0bisuke 5802 222 26.1351 690 11.8925% 3行のソースコードを入れるだけで機械学習できると噂のindicoをNode.jsで使って機械学習入門してみる
56 @tonkotsuboy_com 5788 83 69.7349 798 13.7871% 2016年新機能! GitHubのmasterブランチをWebページとして公開する手順
57 @r7kamura 5581 56 99.6607 655 11.7362% RailsでAPIをつくるときのエラー処理
58 @tatesuke 5271 34 155.029 2056 39.0059% You Don't Need jQuery
59 @jacksuzuki 5268 5 1053.6 5258 99.8102% ロシアの天才ハッカーによる【新人エンジニアサバイバルガイド】
60 @tag1216 5270 64 82.3438 2475 46.9639% インフラエンジニアじゃなくても押さえておきたいSSHの基礎知識
61 @voluntas 5100 107 47.6636 843 16.5294% docker コマンド チートシート
62 @amay077 5087 212 23.9953 257 5.05209% NHK紅白の Android/iPhone アプリが .NET/Xamarin 製だったということ
63 @hnakamur 5053 187 27.0214 497 9.83574% ちょっとしたHTMLはGitHub Gistに置いてbl.ocks.orgで表示するのがお手軽です
64 @daxanya1 5042 28 180.071 4018 79.6906% 数学を避けてきた社会人プログラマが機械学習の勉強を始める際の最短経路
65 @y_hokkey 5008 52 96.3077 1473 29.4129% Dockerで即実行できる、社内・自宅向けオープンソースWebアプリ
66 @koba04 4970 38 130.789 739 14.8692% 私のJavaScript情報の集め方
67 @shibukawa 4927 81 60.8272 815 16.5415% オブジェクト指向と20年戦ってわかったこと
68 @magicant 4871 33 147.606 1994 40.9362% クラスの命名のアンチパターン
69 @koogawa 4858 55 88.3273 1117 22.993% iPhoneアプリ申請やAppleの審査に関するメモ
70 @puriketu99 4791 183 26.1803 791 16.5101% 機械学習クソ素人の俺がプロダクトをリリースするまでの2ヶ月で覚えたこと
71 @hidekuro 4731 79 59.8861 1764 37.286% VagrantとDockerについて名前しか知らなかったので試した
72 @nekoneko-wanwan 4684 56 83.6429 1365 29.1418% はじめてajaxを使うときに知りたかったこと
73 @okmttdhr 4664 63 74.0317 1918 41.1235% ここ数年前から2015/5までのモダンフロントエンドを総まとめしてみた
74 @mochizukikotaro 4581 178 25.736 855 18.664% 初心者がAWSでミスって不正利用されて$6,000請求、泣きそうになったお話。
75 @chuck0523 4567 62 73.6613 1367 29.9321% フロントエンドエンジニアが暇なときにやると良いかもしれないこと
76 @satomyumi 4521 243 18.6049 487 10.772% 覚えておきたい Vim コマンド 備忘録
77 @m-yamashita 4508 12 375.667 3361 74.5563% 初心者向け、「上手い」シェルスクリプトの書き方メモ
78 @kuni-nakaji 4484 17 263.765 2197 48.9964% httpsだからというだけで安全?調べたら怖くなってきたSSLの話!?
79 @kazukichi 4484 30 149.467 1396 31.1329% エンジニアで稼ぐために大切な15のコト
80 @disc99 4471 22 203.227 1817 40.6397% Javaを使うなら知っておきたい技術、フレームワーク、ライブラリ、ツールまとめ
81 @hachi8833 4437 45 98.6 2569 57.8995% Vim幼稚園からVim小学校へ
82 @makoto_kw 4402 59 74.6102 641 14.5616% 趣味でつくるiOSアプリこそJenkinsでリリースを自動化
83 @Hiraku 4370 111 39.3694 1162 26.5904% WebAPIリクエスト仕様書としてcurlコマンドのご提案
84 @howdy39 4376 19 230.316 1166 26.6453% フロントエンドにテストを導入
85 @mima_ita 4339 99 43.8283 587 13.5285% あなたのおっしゃるレビューってどのことかしら?
86 @ukiuni@github 4286 56 76.5357 1633 38.1008% JavaScriptを読んでて「なにこれ!?」と思うけれど調べられない記法8選。
87 @hik0107 4305 21 205 758 17.6074% Pythonでデータ分析するのに必要なツールのまとめ
88 @pugiemonn 4234 249 17.004 814 19.2253% こんなHTMLとCSSのコーディング規約で書きたい
89 @ryounagaoka 4230 47 90 1752 41.4184% もう逃げない。HTMLのviewportをちゃんと理解する
90 @tenntenn 4230 61 69.3443 1597 37.7541% Go言語の初心者が見ると幸せになれる場所 #golang
91 @futoase 4156 100 41.56 595 14.3167% 【個人メモ】CentOS環境に登録するyumリポジトリ
92 @reikubonaga 4115 61 67.459 680 16.5249% iOS開発する上で絶対に押さえておく8つの項目
93 @konifar 4053 92 44.0543 231 5.69948% Android Studioのgradleビルドを高速化する
94 @harukasan 4030 52 77.5 976 24.2184% 我々はどのようにして安全なHTTPS通信を提供すれば良いか
95 @k-shogo 4026 18 223.667 1450 36.0159% 無料のSSL証明書StartSSLを活用する
96 @nori0620 4018 11 365.273 1743 43.3798% [iOS] 新言語SwiftがObjective-Cよりも良いところ
97 @k0kubun 4015 41 97.9268 858 21.3699% ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い
98 @Hironsan 4008 36 111.333 889 22.1806% 機械学習を使って作る対話システム
99 @merrill 3991 37 107.865 996 24.9562% Swift でアプリ開発を1ヶ月やってみて感じた Xcode の効率的な使い方と、Web と連動するときのプラクティス
100 @horimislime 3975 35 113.571 1065 26.7925% APIドキュメントを書くのが楽になるツールまとめ

やはり上位のQiitaレジェンドは何か1つの記事で稼いだという感じでもなく、Top記事が1000いいねを超えていても占有率は高々20%という感じが大半のようです。

例外的なのは @jacksuzuki さんですかね...。
僕もいいねせずにはいられませんでしたが、 ロシアの天才ハッカーによる【新人エンジニアサバイバルガイド】 が1記事で5000を超えるいいねを集め、 占有率99.8102% というまた違ったレジェンドっぷりを輝かせております。

他に目立つものといえば、全体でもトップの @hirokidaichi さんは平均いいねが1000近く、ある程度数を重ねられている方でこの数値では圧倒的。
他には、 @tukiyo3 さんの 記事数1421 なんてのもすごい数字です。 @tbpgr さんの681でもすごい数字なのにその2倍近いとは恐れ入ります。。。

シェル芸の解説

school_sensei_kokuban.png

せっかくなので収集、計算に使ったシェル芸の簡単な解説をしておきます。

  1. Qiita User RankingからTOP100ユーザ名を抜き出す
  2. 各ユーザのQiitaトップページを取得する
  3. Qiitaトップページから「総Contribution」「記事数」「Top数」「Top記事」を抜き出す
  4. それぞれの値から「平均いいね」「Top占有率」を計算し、出力する

1. Qiita User RankingからTOP100ユーザ名を抜き出す

ランキングページの中身を見ると、

<h2>ランキング一覧</h2>

  <p>
    第1位
    <a href="http://qiita.com/hirokidaichi">hirokidaichi</a>,
    30974
  </p>
  <p>
    第2位
    <a href="http://qiita.com/jnchito">jnchito</a>,
    26930
  </p>
  <p>
    第3位
    <a href="http://qiita.com/suin">suin</a>,
    20108
  </p>

というような感じになっています。そこで、特徴的な「第○位」に着目し、

$ grep -E "第[0-9]*位" -A 1 | grep href | sed -e "s/^.*href=\".*\">\(.*\)<\/a>.*$/\1/g"

の要領でユーザ名を抜き出しています。
欲しいユーザ名は「第○位」の1行下にあるため、 grep -A 1 で出すことにしています。あとはみんな大好き正規表現で抽出しているだけですね。

ランキングページ自体は20件ずつの表示になっているため、

$ for PAGE in $(seq 1 5) ; do curl -s https://qiita-user-ranking.herokuapp.com/?page=${PAGE} ; done

で合計100件分をまわしています。
curl -s オプションで邪魔なステータスを出ないようにしています。

2. 各ユーザのQiitaトップページを取得する

こちらも簡単です。先ほど取得したユーザ名一覧を使って、

$ for USER in $([ユーザ名一覧]) ; do curl -s http://qiita.com/${USER} ; done

とするだけです。

3. Qiitaトップページから「総Contribution」「記事数」「Top数」「Top記事」を抜き出す

おわかりかと思いますが、ここが一番面倒です。
Qiitaユーザトップのソースを見てもらえばお分かりになるかと思いますが、実はこのページから 得たい情報の全てが1行のソースに存在 しています。

もちろんコードによって生成されていますので、法則性があり正規表現で捕まえられるのですが、ピンポイントで捕まえるのには結構苦労しました。

sed -e "s/^.*<span class=\"userActivityChart_statCount\">\([0-9]*\)<\/span><br \/> <span class=\"userActivityChart_statUnit\">Contribution<\/span>.*<span class=\"userActivityChart_statCount\">\([0-9]*\)<\/span><br \/> <span class=\"userActivityChart_statUnit\">Items<\/span>.*<span class=\"fa fa-like\"><\/span> \([0-9]*\)<\/div>.*<a itemprop=\"url\" href=\"\(.*\)\">\(.*\)<\/a><ul class=\"list-inline userPopularItems_tags tagList\">.*\(itemprop.*\)\{4\}.*$/\1\t\2\t\3\t\[\5\](http:\/\/qiita.com\4)/g"

どこまで行っても正規表現なので、興味がある方はページのソースと正規表現でにらめっこしてみてください。
1つだけ説明を加えておくと、「Top数」「Top記事」を取るのが大変でした。
1行が長いため、色々な部分で .* のワイルドカード的な表現を使っているのですが、 最長一致 などの都合でなかなか思うように抜き出しができませんでした。
最終的には、Top5記事に対するitempropを手掛かりに、最初の1つにパターンマッチをかけ、残り4つには \(itemprop.*\)\{4\} を引っ掛けることでTop記事に関する情報だけを抜き出しました。

4. それぞれの値から「平均いいね」「Top占有率」を計算し、出力する

あとは awk を使った簡単な計算です。
sed の出力をタブでさせていたので、デリミタをタブにしつつ各行の値を計算して出力しています。
ここでランクが出力されますが、ストリームのレコード番号を格納する NR で出しています。結構便利。
ちまちま挟んであるパイプはMarkdownでの表にするためですね。

awk -F"\t" '{if(NF==5) print "|"NR"|"$1"|"$2"|"$3"|"$2/$3"|"$4"|"$4/$2*100"%|"$5"|"}'

条件で NF==5 を指定していますが、それはこのあと出てきます。

46位がいない件

business_karoushi.png

お気づきの方もいらっしゃるでしょうか、実は上の表では 46位が欠けています
46位にランクされているのは @Qiita さんなのですが、投稿記事数が4でTOP100ユーザの中で唯一「 投稿記事数が5未満 」となっています。
どうして上の表に出てこないかというと、処理説明3のところで、

Top5記事に対するitempropを手掛かりに、最初の1つにパターンマッチをかけ、残り4つには \(itemprop.*\)\{4\} を引っ掛ける

と書いていたのですが、投稿記事数が4つしかない @Qiita さんは上記の正規表現で上手く値が取れませんでした。
そのため、 sed の結果としてフィールド数が足りない状態であるため、最後の awkNF==5 の条件をつけることで結果から弾いています。

そもそももっと頭のいい正規表現を書ければ今の方針でもなんとかなったのかと思いますが、15分考えてもいいものが浮かばなかったので諦めました5
何かいい方法をお持ちの方はぜひご指導をお願いいたしますm(_ _)m

ちなみに @Qiita さんのContributionまわりは下記の感じです。

ランク ユーザ名 総Contribution 記事数 平均いいね Top数 Top占有率 Top記事
46 @Qiita 6743 4 1685.75 5417 80.3351% Markdown記法 チートシート

チートシートは僕もたいへんお世話になりました。

おわりに

シェル芸たのしい^^

来年は sed awk とかメジャーなものだけじゃなく、もっと黒魔術っぽいシェル芸を身に着けたいです。がんばろう。

pose_ganbarou_man.png


  1. 投稿した当時はまだストックによるContribution反映でした。 

  2. なお、こちらのサイトの仕様上「サイトにある情報は結構タイムラグがあったりします」とのことなので、実際のTOP100ではない可能性があります。 

  3. シェル芸: マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理をCLI端末へのコマンド入力一撃で終わらすこと。あるいはそのときのコマンド入力のこと。(シェル芸の定義バージョン1.1

  4. GNU bash 4.2.46, GNU sed 4.2.2, GNU Awk 4.0.2でした。 

  5. 組織アカウントだし、まぁいいかな、なんて...(逃げ)