7. 例2.為替レートを取得してみる

今回は、為替レートをスクレイピングにより取得してみましょう。といっても、実際は為替レートが表示されているHTMLファイルをスクレイピングし、該当箇所を抜き出すだけなので、基本は殆ど同じです。
今回利用するサイトはひまわり証券株式会社 ブログパーツ FXレートウォッチャーです。元がブログパーツなので、取得するHTMLファイルの容量も少なくてよさそうなので、今回は、このサイトを利用してみます。

上記のサイトでは、<IFRAME>タグを利用して、パーツを表示するタイプです。なので、<IFRAME>タグのsrcのアトリビュートで指定されている、

を対象にしてみます。

サンプルソースを見ながら解説を進めます。

ではプログラムを見てみましょう。
前回のはてなフォトライフではスクレイピング対象となるHTMLファイルを動的に変化させましたが、今回は固定ですね。3行目の define で定義した BASE_URI がスクレイピング対象のURIになります。
4行目でHTML取得に用いるhttp_request()関数を利用するために proxy.php をインクルードしています。
proxyを利用する場合は、例によって、7~12行目にproxyの設定を記述し、6行目の $use_proxy の値を1にします。

今回主に利用する内部関数は下記になります。

  • dump_nodes_rate()関数 (19~43行目)

メインの部分は、61~119行目になります。先ずメインの部分を見てみましょう。
61行目の「form変数の$_GET['cmd']がNULLでなければ」というのは、つまり、57行目の「submitボタンが押されたら」ということです。ボタンが押されたら if 文の中身を実行します。つまりはじめのアクセスの際はこの部分は何も実行されないことになります
ボタンが押されたら、先ず、63行目で、3行目に指定した BASE_URI (つまり取得対象HTML) のHTMLファイルを取得し $html に入れます。13~18行目のget_html()関数が対象のHTMLファイルを取得し、UTF-8に文字コードを変換し、$dataに取得したHTMLソースの中身が入ります。

65~67行目でtidy関数のパース時の設定を記述し、69行目で取得したHTMLソース($data)からtidyオブジェクトを作成します。
70行目でcleanRepair()し、73行目でtidyオブジェクトのbody()の部分を dump_nodes_rate() 関数に渡しています。

19~43行目のdump_nodes_rate()でタグの解析を行っています。
25行目の、

if( $node->id == TIDY_TAG_TD )
は、HTMLファイルの中の<TD>タグにマッチしているかどうがをチェックしています。
更に27行目で
if (strpos($node->attribute['class'] ,"tdborder") === 0)
としているのは、<TD>タグの中で更にclass属性がtdborderのものをマッチさせています。これは今回取得したいデータがすべてclass属性がtdborderのものだったので上記のように記載しました。このあたりは取得するHTMLや取得したい情報により異なると思います。
30行目は何をしているのでしょう?実は作り始めてわかったのですが、前日比が0の場合は何故かHTMLのソースに改行コードが入っているようなのです。なので、ここでは改行コードを全て除去するような処理を入れています。
30行目の $node->child[0]->value は <TD>xxxx</TD> で囲まれたxxxxの部分の値が入ります。 この処理を処理対象のノードがなくなるまで繰り返します。
これによって $urls には、
<TD class="tdborder">xxxx</TD>
の中身の部分xxxxが配列として保管されます。

ここまでで73行目の $rate には dump_nodes_rate() 関数で計算された $urls が配列として取得されたことになります。$rate にどういうデータが入っているかを知るには 73行目と74行目の間に、

echo '
';
print_r($rate);
echo '
';

などとすることにより、確認できると思います。

ここで今回の対象となるHTMLファイルの構造をよく見てみると <TD class="tdborder"> が指定されているタグは全部で31個と固定になっています。
更にひとつめは現在時刻を表し、残りの30個は通貨ペア、現在値、前日比の組み合わせが10回続いています。その10個は「ドル円、ユーロ円、ユーロドル、ポンド円、ポンドドル、豪ドル円、NZドル円、南アランド円、カナダドル円、スイス円」の順番で並んでいます。
後の処理をしやすくするために、少し配列を加工してみましょう。
75行目で配列の一番はじめの番号(phpでは配列は0から始まります)を

$nowtime = $rate[0];
として $nowtime という変数に退避させます。
そして80行目で
array_shift($rate);
としています。array_shift()はphpで配列のはじめの要素を取り除く関数です。これで、今まで31個あった配列がこれにより、先に退避させた $rate[0] を取り除き30個の配列になりました。
84行目からは3つのペアをまとめて処理するため、配列の要素の個数(30個)を3で割った数だけ繰り返し処理を実行します。ちなみに、配列の要素の個数を求めるにはcount()を利用します。
86~90行目で $tuka(通貨ペア) , $val(現在値) , $deg(前日比) という変数に夫々値を入力します。
94~106行目までのif文の中身は何をしているのでしょう?
これは、前日比の計算をしています。
前日比が0でない場合は
<span class="minus">▼0.29</span>
という形式になっています。ここもTIDY関数で求めてもよさそうなのですが、文字列処理の勉強のため、explodeという関数を利用してみます
explode関数はある文字列を指定した記号(【デリミター】delimiter. 区切り文字)で分けることにより、配列を作成する便利な関数でphpではよく使われます。
96行目で「>」をデリミターとして配列をつくり、その配列を更に、100行目で「<」をデリミターとして配列をつくります。これで「▼0.29」の部分が無事に $tmp1[0] に格納されたのですが、104行目で更に「▼」の部分を「-(マイナス)」に置換しています。同様に106行目で▲の部分を「+(プラス)」に置換しています。
この処理が終わると110行目で $js という変数に連想配列として、データを追加します。
このデータを117~119行目の foreach 文で繰り返し、データを表示します。

実際に動作するサンプルは下記になります。

為替レート取得(別ウィンドウで開きます)