ハッカーニュース人気言語を CSV で出力する

bashで人気言語アンケートサイトの結果をcsvに変換してみる - labunix の ラボゆにっくすハッカーニュース人気言語 - karasuyamatenguの日記 にインスパイヤされて gawk (GNU awk) で作成してみます。

ここでは gawk の特徴のうち、以下の項目を使っています。

  • Socket 通信で w3m や wget 等に頼らず直接ダウンロードする
  • RS (レコードセパレータ) に正規表現を用いることにより、HTML のタグを削除する

実際のコードは以下のようなものです。

#! /usr/local/bin/gawk -f
# popular_language.awk
# ハッカーニュース人気言語を CSV で出力する

BEGIN {
    # Socket の設定
    base_url        = "news.ycombinator.com";
    port            = 80;
    query           = "/item?id=3746692";

    # Socket での問い合わせ
    http_service    = "/inet/tcp/0/" base_url "/" port;
    http_request    = "GET " query " HTTP/1.0";
    print http_request  |& http_service;
    print ""            |& http_service;

    # HTML タグを削除
    RS = "<[^>]+>|\n";

    # Socket からの入力の取得
    while ((http_service |& getline) > 0) {
        if (length($0) > 0) {
            line[++i] = $0;
        }
    }
    close(http_service);

    # 出力をカンマ区切
    OFS = ",";

    for (j = 1; j <= i; j++) {
        # ** points という行を抜き出す
        # ただし、見出しは省く
        if (line[j] ~ /^[0-9]+ points$/     &&
            split(line[j], tmp_arr) == 2    &&
            line[j - 1] !~ /\?/) {
            sub(/ points/, "", line[j]);

            print line[j - 1], line[j];
        }
    }
}

実際に実行してみます。

$ gawk -f popular_language.awk
Actionscript,90
Ada,23
Assembly,98
C,937
C++,514
C#,787
Clojure,439
Cobol,10
CoffeeScript,352
ColdFusion,34
D,52
Delphi,34
Erlang,157
Forth,38
Fortran,21
Haskell,501
Java,526
JavaScript,1345
Lisp,312
Lua,143
Objective C,316
OCaml,80
Pascal,24
Perl,299
PHP,626
Python,2962
Rexx,11
Ruby,1663
Scala,225
Scheme,182
Shell,61
Smalltalk,66
SQL,98
Tcl,30
Visual Basic,41
Other,183
Groovy (Added Two Hours Late Due To Requests),64

このようになってしまえば、後は sort コマンドなどを用いて処理することが簡単にできます。

また、gawk4 では for 文で読み出す際にソートを行うこともできます。 そのためには最後の部分を以下のようにして配列 PROCINFO で指定します。

#! /usr/local/bin/gawk -f
# popular_language.awk
# ハッカーニュース人気言語を CSV で出力する

BEGIN {
    # Socket の設定
    base_url        = "news.ycombinator.com";
    port            = 80;
    query           = "/item?id=3746692";

    # Socket での問い合わせ
    http_service    = "/inet/tcp/0/" base_url "/" port;
    http_request    = "GET " query " HTTP/1.0";
    print http_request  |& http_service;
    print ""            |& http_service;

    # HTML タグを削除
    RS = "<[^>]+>|\n";

    # Socket からの入力の取得
    while ((http_service |& getline) > 0) {
        if (length($0) > 0) {
            line[++i] = $0;
        }
    }
    close(http_service);

    # 出力をカンマ区切
    OFS = ",";

    for (j = 1; j <= i; j++) {
        # ** points という行を抜き出す
        # ただし、見出しは省く
        if (line[j] ~ /^[0-9]+ points$/     &&
            split(line[j], tmp_arr) == 2    &&
            line[j - 1] !~ /\?/) {
            sub(/ points/, "", line[j]);

            arr[line[j - 1]] = line[j];
        }
    }

    # for 文でソートする (gawk4)
    PROCINFO["sorted_in"] = "@val_num_desc";
    for (k in arr) {
        print k, arr[k];
    }
}

実行してみましょう。

$ gawk -f popular_language.awk
Python,2962
Ruby,1663
JavaScript,1345
C,937
C#,787
PHP,626
Java,526
C++,514
Haskell,501
Clojure,439
CoffeeScript,352
Objective C,316
Lisp,312
Perl,299
Scala,225
Other,183
Scheme,182
Erlang,157
Lua,143
SQL,98
Assembly,98
Actionscript,90
OCaml,80
Smalltalk,66
Groovy (Added Two Hours Late Due To Requests),64
Shell,61
D,52
Visual Basic,41
Forth,38
ColdFusion,34
Delphi,34
Tcl,30
Pascal,24
Ada,23
Fortran,21
Rexx,11
Cobol,10

ちゃんとソートされました。

でもね

gawk でも xgawk でも HTML を解釈させるのは非常に難しい作業です。 よく行う手段としては上記のように HTML タグを改行にしてしまうような処理と w3m のダンプ機能を使う bashで人気言語アンケートサイトの結果をcsvに変換してみる - labunix の ラボゆにっくすハッカーニュース人気言語 - karasuyamatenguの日記 に記載された方法があります。

w3m は設定によってダンプされる形式が異なる場合があるので、注意が必要ですが、実際には w3m でダンプするという手法が安全かつ一般的ではないでしょうか?

tag_gawk.png