Web::Scraper の練習として玉子屋のメニューを取ってくる

$ scraper http://www.tamagoya.co.jp/menu/menu.html
scraper>

本当は、process コマンドを使って徐々に降りていったんだけど長いので、このブログには途中からの様子を。process コマンドで目的のものに近づいていく。

scraper> process '/html/body/table/tr[4]/td[2]/table/tr[8]', WARN;
<tr><td bgcolor="white" class="sp" width="24"><img border="0" height="1" src="../imgs/spacer.gif" width="24" /></td><td bgcolor="white" class="sp" colspan="2" valign="bottom"><br /><b>39日(月)〜313日(金)</b></td><td bgcolor="white" class="sp" colspan="2"><br /><b>316日(月)〜320日(金)</b></td><td bgcolor="white" width="48"></td> </tr>
scraper> process '/html/body/table/tr[4]/td[2]/table/tr[8]/td[2]', WARN;
<td bgcolor="white" class="sp" colspan="2" valign="bottom"><br /><b>39日(月)〜313日(金)</b></td>
scraper> process '/html/body/table/tr[4]/td[2]/table/tr[8]/td', WARN;
<td bgcolor="white" class="sp" width="24"><img border="0" height="1" src="../imgs/spacer.gif" width="24" /></td>
<td bgcolor="white" class="sp" colspan="2" valign="bottom"><br /><b>39日(月)〜313日(金)</b></td>
<td bgcolor="white" class="sp" colspan="2"><br /><b>316日(月)〜320日(金)</b></td>
<td bgcolor="white" width="48"></td>
scraper> process '/html/body/table/tr[4]/td[2]/table/tr[8]/td/b', WARN;
<b>39日(月)〜313日(金)</b>
<b>316日(月)〜320日(金)</b>

これでよさそうなので、配列として取得することにしてみる。

scraper> process '/html/body/table/tr[4]/td[2]/table/tr[8]/td/b', 'weeks[]' => 'TEXT';

確認。

scraper> y
---
weeks:
  - 39日(月)〜313日(金)
  - 316日(月)〜320日(金)

二週分のメニューもそれぞれ process を使って徐々に近づいたけど、そこは省略して要だけ。

scraper> process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[2]/table/tr/td', 'menu1[]' => 'TEXT';
scraper> process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[3]/table/tr/td', 'menu2[]' => 'TEXT';
scraper> y
---
menu1:
  - 日 付
  - カロリー 塩 分
  - メインメニュー
  - 9()
  - 442.7kcal 4.6g
  - うすいころもの手造りとんかつ×2  辛子付ソース
  - 10()
  - 359.3kcal 4.2g
  - 若鶏唐揚 葱ソース
  - 11()
  - 307.7kcal 3.2g
  - 旬の  筍ごはん
  - 12()
  - 405.3kcal 4.5g
  - 完熟トマトのビーフシチューと串カツ
  - 13()
  - 353.2kcal 4.2g
  - チンジャオロース
menu2:
  - 日 付
  - カロリー 塩 分
  - メインメニュー
  - 16()
  - 413.2kcal 4.4g
  - さっぱりおろしだれ ハンバーグステーキ
  - 17()
  - 302.3kcal 3.1g
  - 青玄米ごはんと 高級銀鮭
  - 18()
  - 354.4kcal 4.7g
  - すき焼風弁当 温泉玉子添え
  - 19()
  - 369.7kcal 3.7g
  - 好評 チキンソテー オニオンドレッシング
  - 20()
  - 春分の日
weeks:
  - 39日(月)〜313日(金)
  - 316日(月)〜320日(金)

c all でコードを出力してとりあえずおしまい。

scraper> c all
#!/usr/bin/perl
use strict;
use Web::Scraper;
use URI;

my $uri = URI->new("http://www.tamagoya.co.jp/menu/menu.html");
my $scraper = scraper {
    process '/html/body/table/tr[3]', WARN;
    process '/html/body/table/tr[4]', WARN;
    process '/html/body/table/tr[4]/td[2]', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[8]', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[8]/td[2]', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[8]/td', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[8]/td/b', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[8]/td/b', 'weeks[]' => 'TEXT';
    process '/html/body/table/tr[4]/td[2]/table/tr[9]', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[2]/table', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[2]/table/tr', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[2]/table/tr/td', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[2]/table/tr/td', 'menu1[]' => 'TEXT';
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[3]/table/tr/td', WARN;
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[3]/table/tr/td', 'menu2[]' => 'TEXT';
};
my $result = $scraper->scrape($uri);

あとは出力を加工するだけ。きれいに書けないなあ。

#!/usr/bin/perl
use strict;
use warnings;
use Web::Scraper;
use URI;
use Encode;

my $uri = URI->new("http://www.tamagoya.co.jp/menu/menu.html");
my $scraper = scraper {
    process '/html/body/table/tr[4]/td[2]/table/tr[8]/td/b', 'weeks[]' => 'TEXT';
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[2]/table/tr/td', 'menu1[]' => 'TEXT';
    process '/html/body/table/tr[4]/td[2]/table/tr[9]/td[3]/table/tr/td', 'menu2[]' => 'TEXT';
};
my $result = $scraper->scrape($uri);

my @lines = ();
sub pushto {
  push(@{$_[0]}, "===================");
  push(@{$_[0]}, $_[1]);
  my $i = 0 + 3;
  my $length = @{$result->{menu1}};
  while ($i < $length) {
    push(@{$_[0]}, "-------------------");
    push(@{$_[0]}, $_[2]->[$i] .q{ }. $_[2]->[$i+1]);
    $i += 2;
    push(@{$_[0]}, ($_[2]->[$i] || q{}) );
    $i++;
  }
}

pushto \@lines, $result->{weeks}->[0], $result->{menu1};
pushto \@lines, $result->{weeks}->[1], $result->{menu2};
push(@lines, q{});
print encode_utf8(join("\n", @lines));

実行結果はこんな感じ。

$ ./tamagoya.pl
===================
39日(月)〜313日(金)
-------------------
9() 442.7kcal 4.6g
うすいころもの手造りとんかつ×2  辛子付ソース
-------------------
10() 359.3kcal 4.2g
若鶏唐揚 葱ソース
-------------------
11() 307.7kcal 3.2g
旬の  筍ごはん
-------------------
12() 405.3kcal 4.5g
完熟トマトのビーフシチューと串カツ
-------------------
13() 353.2kcal 4.2g
チンジャオロース
===================
316日(月)〜320日(金)
-------------------
16() 413.2kcal 4.4g
さっぱりおろしだれ ハンバーグステーキ
-------------------
17() 302.3kcal 3.1g
青玄米ごはんと 高級銀鮭
-------------------
18() 354.4kcal 4.7g
すき焼風弁当 温泉玉子添え
-------------------
19() 369.7kcal 3.7g
好評 チキンソテー オニオンドレッシング
-------------------
20() 春分の日