curlコマンドで官公庁の報道発表資料を取得する

BUW(Bash on Ubuntu on Windows)には「curl」というWebサーバーへのアクセスなどを行うコマンドが用意されている。例えば「curl http://news.mynavi.jp/dp/business」と実行すれば、対象となるHTMLファイルを標準出力で取得するというものだ。その利用シーンは多岐にわたるが、今回からはRSS/ATOMフィードを配信していないWebサイトの情報を取得するために、curlコマンドを使ったシェルスクリプトの作成にチャレンジする。

ターゲットにするのは総務省の報道資料一覧を配信するWebページ。取得したHTMLの内容を見ると文字コードはシフトJISを使っている。また、報道資料一覧はTDタグを使ったテーブルを用いているようだ。確認したところ、このページでは他にテーブルを用いていないため、TDタグを抽出すれば、必要な情報を取り出せる。

curlコマンドで取得したHTMLの内容(vimの文字コードを一時的にシフトJISに変更している)

抽出方法はgrepコマンドを使用し、不要なHTMLタグの削除はsedコマンドを使用すればよい。ちなみにgrepはテキストファイルなどから文字列、正規表現に一致する行を検索するコマンド。sedはテキストデータを処理するコマンドである。この場合のコマンドラインは「curl -s -S http://www.soumu.go.jp/menu_news/s-news/ | grep "td" | sed 's/<[^>]*>//g'」となり、実行結果は下図に示したように、1行目に日時、2行目にタイトル、3行目にカテゴリーが並ぶ結果となった。ちなみにsedコマンドで指定している「s」は正規表現で置換処理を行うためのコマンド。ここで指定した「<[^>]*>」は「<」「>」で囲んだ文字列をすべて削除するというもの。末尾の「g」は1行中に複数マッチした文字列をすべて置換するために付加する。

このようにテキストのみ抽出するのであれば、コマンドライン1行で実現可能。ちなみにシフトJISの文字化けを回避するため、nkfコマンドを併用している(※インストールされていない場合は、sudo apt-get install nkfでインストールします)

一見すると簡単に成功したように見えるものの、今回のシェルスクリプトは本稿担当編集者が「日々の情報収集を簡単にしたい」というリクエストに基づいているため、URLを削除してしまっては元も子もない。そこでHTMLタグすべてではなくTDタグのみ取り除く設定が必要である。そこで、sedコマンドのオプション「-e」を使用し、置換パターンを複数記述する方法を用いた。今回は「<td>」「<td(に続く文字列)」「</td>」だけ取り除けば十分なので、「curl -s -S http://www.soumu.go.jp/menu_news/s-news/ | grep "<td" | sed -e 's/<td>//g' -e 's/<td.*">//g' -e 's/<\/td>//g'」と実行する。

リンク先のURLも残るように再調整したコマンドラインの実行結果

それでもこの状態ではリンクを張る「A」タグとタイトルが1行にまとまった状態だ。さらにsedコマンドを用いて置換する方法で対処しよう。まず「」を改行に置換。そしてタグを閉じる「」を削除しなければならない。その場合は「sed -e 's/<td>//g' -e 's/<td .*">//g' -e 's/<\/td>//g' -e 's/<a.*="//g' -e 's/<\/a>//g' -e 's/">/\n/g'」となる。これで1行ごとに情報を分解したデータを取り出すことができた。

不要なタグをさらに取り除いた状態

では今回のシェルスクリプトを紹介しよう。いつもどおりvimなどで下記の内容を作成し、chmodコマンドで実行権限を付加してほしい。

 #!/bin/bash

 URLBASE=http://www.soumu.go.jp
 URL={$URLBASE}/menu_news/s-news/
 I=0

 Array=($(curl -s -S $URL | grep "<td" | sed -e 's/<td>//g' -e 's/<td .*">//g' -e 's/<\/td>//g' -e 's/<a.*="//g' -e 's/<\/a>//g' -e 's/">/\n/g'))

 for Obj in ${Array[@]}; do
    Num=`expr $I % 4`
    case $Num in
        0 )
            StrDate=`echo ${Obj} | sed -e 's/[\r\n]\+//g'` ;;
        1 )
            StrURL=`echo ${Obj} | sed -e 's/[\r\n]\+//g'` ;;
        2 )
            StrTitle=`echo ${Obj} | sed -e 's/[\r\n]\+//g'` ;;
        3 )
            StrCat=`echo ${Obj} | sed -e 's/[\r\n]\+//g'`
            echo $StrDate $StrCat | nkf
            echo $StrTitle | nkf
            echo $URLBASE$StrURL | nkf
            echo -e "\n"
            ;;
    esac
    let I++
 done

まず3~4行目で設定した変数は取得先となるWebサイトのURLだ。2つの変数に分けているのは、curlコマンドで取得するURLにドメインなどが含まれないため、上記のように記述した。7行目は先ほどまで実行していたcurlコマンドの内容を配列「Array」に格納させている。10行目は配列Arrayをすべて展開するためのfor文だ。少々内容が煩雑なので順番に解説しよう。

今回取得した総務省の報道資料一覧は4要素で構成されているため、この計算結果を基に、11行目で変数「I」の値を4で割り、その結果を変数「Num」に代入して、12行目からのcase文で分岐する仕組みだ。値から各変数に文字列を展開しているが、その際はsedコマンドを使用し、改行コードを取り除いている。

変数Numの値はゼロから3までの数値になるので、19行目からの分岐で表示処理を加えている。今回はcurlコマンドで取得した要素をパーツとして使用可能にするまでを中間地点としているため、出力形式に凝ることはしなかった。

作成したスクリプトを実行する。BUWの2バイト文字表示は安定しないため、今回はリダイレクトでファイルに出力した

lessコマンドで作成したファイルを開いた状態

上図のように日付とカテゴリーを1行にまとめて、2行目は発表内容のタイトル、3行目は加工したURLがまとめられている。次回はこのシェルスクリプトをベースに活用方法を考えてみよう。

阿久津良和(Cactus)