シェルスクリプトを使って「これから毎日金相場をスクレイピングしようぜ?」という話
クローラー/スクレイピング Advent Calendar 2014
今日は水曜日なのに、金のお話。
田中貴金属工業という会社があります。この会社のWebサイトにある、「本日の貴金属情報」では、毎日の金相場情報(地金情報)が公開されています。
この情報は毎日更新されるので、前日の金相場情報を見ることはできません。そこで今日のAdvent Calendarでは、この金相場情報をスクレイピングする方法を紹介してみようと思います。
シェルスクリプトでスクレイピング
クローラー/スクレイピング Advent Calendar 2014の記事を見てみると、RubyでNokogiriやMechanizeを使ってみたり、Pythonでurllibやrequestsを使ってみたり、はてはKimonoを使ってみたりしています。
筆者はPython書けな...今日はちょっと趣向を変えて、シェルスクリプトで泥臭くスクレイピングしてみましょう。開発、動作環境としてはNetBSD-6.1.5-amd64を利用してみます。
スクレイピングの手順
先ほど紹介したWebページのHTMLファイルは以下のようになっています。このHTMLに対してスクレイピングをかけて行きます。
<td height="18" align="center" background="images/s_title_bg.jpg" id="px12">地金価格</td>
...中略...
<td width="104" align="center" bgcolor="#FFFCEE" id="px12"><b>金</b></td>
<td width="126" align="center" bgcolor="#EFF8FE" id="px12"><b>プラチナ</b></td>
<td width="108" align="center" bgcolor="#F7F7F7" id="px12"><b>銀</b></td>
</tr>
<tr bgcolor="#FFFFFF">
<td align="center" bgcolor="#E6E6E6" id="px12">税込小売価格</td>
<td align="right" bgcolor="#FFFCEE" id="px12">5,124円</td>
<td align="right" bgcolor="#EFF8FE" id="px12">5,220円</td>
<td align="right" bgcolor="#F7F7F7" id="px12">73.87円</td>
</tr>
<tr bgcolor="#FFFFFF">
<td align="center" bgcolor="#E6E6E6" id="px12">(小売価格前日比)</td>
<td align="right" bgcolor="#FFFCEE" id="px12">+54円</td>
<td align="right" bgcolor="#EFF8FE" id="px12">+6円</td>
<td align="right" bgcolor="#F7F7F7" id="px12">+2.16円</td>
</tr>
<tr bgcolor="#FFFFFF">
<td align="center" bgcolor="#E6E6E6" id="px12">税込買取価格</td>
<td align="right" bgcolor="#FFFCEE" id="px12">5,039円</td>
<td align="right" bgcolor="#EFF8FE" id="px12">5,092円</td>
<td align="right" bgcolor="#F7F7F7" id="px12">69.77円</td>
</tr>
<tr bgcolor="#FFFFFF">
<td align="center" bgcolor="#E6E6E6" id="px12">(買取価格前日比)</td>
<td align="right" bgcolor="#FFFCEE" id="px12">+54円</td>
<td align="right" bgcolor="#EFF8FE" id="px12">+7円</td>
<td align="right" bgcolor="#F7F7F7" id="px12">+2.16円</td>
スクレイピング用に、以下のシェルスクリプトを作成します。
1 #!/bin/sh
2
3 URL='http://gold.tanaka.co.jp/commodity/souba/index.php'
4
5 TMP_DIR=/home/tsubaki/tmp/tanaka_gold
6 DOC=${TMP_DIR}/index.php
7
8 [ ! -d ${TMP_DIR} ] && mkdir ${TMP_DIR}
9
10 wget --quiet -O ${DOC} ${URL} || exit 1
11
12 echo -n `date "+%C%y/%m/%d,"`
13 iconv -f euc-jp -t utf-8 ${DOC} \
14 | grep -n -A 21 '税込小売価格' \
15 | grep '<td' \
16 | grep -v '\+' \
17 | egrep '(FFFCEE|EFF8FE)' \
18 | sed -e "s/</ /g" -e "s/>/ /g" \
19 | sed -e "s/円//" -e "s/,//" \
20 | awk '{ print $6 }' \
21 | paste -d, - - - -
コードを簡単に解説します。スクレイピング対象となるHTML内で、金相場データは以下のようにTABLEタグの中に書かれています。
<td align="right" bgcolor="#FFFCEE" id="px12">5,124円</td>
<td align="right" bgcolor="#EFF8FE" id="px12">5,220円</td>
<td align="right" bgcolor="#F7F7F7" id="px12">73.87円</td>
...
<td align="center" bgcolor="#E6E6E6" id="px12">(小売価格前日比)</td>
<td align="right" bgcolor="#FFFCEE" id="px12">+54円</td>
<
シェルスクリプト内でスクレイピングを行うのは14行目からですね。
14行目では、TABLEタグの直前に現れる「税込み小売価格」を引っかけています。そこから下21行にわたってデータが書かれているので、"-A 21"で抜き出します。
15行目では、TDタグのみ抜き出しています。これは途中にTRタグが出現するため、それを除去するためです。
16行目では、TDタグを含む行の中で"+"が含まれるものを除去しています。これはTABLEの中に「(小売価格前日比)」のような、(データとしては)不要な項目があり、「+6円」のような符号付きフォーマットになっているので、それを利用して当該行を除去しています。
17行目では、金とプラチナのデータをを含むTDタグを抜き出しています。運良くこれらの行は「bgcolor="#FFFCEE"」のような指定があるので、これを利用して抜き出します。
18行目は、後にawkでデータを取り出すことを想定し、データの前後の文字を空白で置き換えています。
19行目では「5,124円」といった記述からカンマと「円」という文字を除去します。
20行目では、必要なデータカラムのみ抜き出しています。
21行目では、複数行に渡って出力されるデータを一行にまとめています。12行目で年月日を出力しており、その出力と合わせた一行のデータになります。
このスクリプトを実行すると、以下の結果が得られます。
$ ./get_tanaka_gold_info.sh
2014/12/10,5124,5220,5039,5092
...。
あまり見栄えがしないですね...。
cronで定期的にデータを集めてみる。
作成したスクリプトを利用して、定期的にデータを集めてみます。こうすれば、毎日更新される金相場データを蓄積してゆくことができます。
crontabを設定して定期的にスクリプトを実行するようにしてみます。
TSUBAKI_DIR=/home/tsubaki
45 22 * * * ${TSUBAKI_DIR}/get_tanaka_gold_info.sh >> ${TSUBAKI_DIR}/result.dat
ちなみにtsubakiは筆者の名前ではなく、四月は君の嘘の登場人物の名前です。
蓄積したデータを見てみる
さて、こうして蓄積したデータはグラフ等に可視化してみると面白そうです。今回はgnuplotでグラフを作ってみましょう。
以下のシェルスクリプトを使用して、収集したデータの抽出とgnuplot用のコマンドファイルを生成します。
#!/bin/sh
[ ! -d tmp ] && mkdir tmp
cat result.dat | sed -e "s/,/ /g" | awk '{ print $1 " " $2 }' > tmp/gold_kouri.data
cat result.dat | sed -e "s/,/ /g" | awk '{ print $1 " " $3 }' > tmp/silver_kouri.data
cat result.dat | sed -e "s/,/ /g" | awk '{ print $1 " " $4 }' > tmp/gold_kaitori.data
cat result.dat | sed -e "s/,/ /g" | awk '{ print $1 " " $5 }' > tmp/silver_kaitori.data
# gnuplot用のコマンドを作成する。
cat <<_EOF > tanaka.plt
# 田中貴金属店の価格データ
set xdata time
set timefmt "%Y/%m/%d"
set format x "%Y/%m/%d"
plot "tmp/gold_kouri.data" using 1:2 ti "gold(kouri)" with lines, \
"tmp/silver_kouri.data" using 1:2 ti "silver(kouri)" with lines, \
"tmp/gold_kaitori.data" using 1:2 ti "gold(kaitori)" with lines, \
"tmp/silver_kaitori.data" using 1:2 ti "silver(kaitori)" with lines
pause -1
_EOF
このスクリプトを実行してグラフを表示してみます。
$ ./create_plot_data.sh
$ gnuplot tanaka.plt
金と銀の価格がじりじりと上昇していますね。2012年7月頃に金と銀を買い占めて、今一気に売ったら大金持ちなのじゃ!...と思うも、金と銀を購入するにはお金が必要で(金だけに)、お金持ちになるには、まずお金持ちでないとダメというトートロージに陥ってしまいます。
まとめ
シェルスクリプトによるスクレイピング例として、金相場データの収集手順を紹介してみました。
今回のように、データ数が少なく、かつ一日くらいの間隔で更新されるデータの場合はシェルスクリプトとcronでカバーすることも可能なようです。