Web::Scraperを使って、物件一覧をGoogle Mapsにマッピング
福岡ファミリー向け物件特集!: ファミリー物件を見ていて、これはいいな、RSS登録するか。
と思ったのですが、このRSSはどうやら福岡の不動産情報探し・お部屋探しサイト「ムビマップ福岡」:こだわりの物件特集[賃貸版]: 物件一覧のようで、僕にはいらん情報も混じっておりました。
で、話題のWeb::Scraperでスクレイピングしてみるか。ついでに取得した一覧はGoogle Mapsにマッピングしてやるか。
というエントリです。
http://fooo.name/ からURL一覧を取り出すのにWeb::Scraper使ったけど、これは良いね
scraper http://fooo.name/accounts/otsune
してsでソース見てそれっぽくXPath書いてdumpして、データが取れてたらcでソース出して終了。イカス。
を参考にさせてもらいました。
まずは、
$ scraper http://www.movimap.net/kodawariblog/family/
して
scraper> s
してソースをざーっと斜め読み。
取ってきたい情報のXPathを考える。
scraper> process '//div[@class="box"]/div[@class="box01"]/h3/a', 'link[]' => '@href', 'title[]' => 'TEXT'
これでどげんじゃろかと、出力してみる。
scraper> y
すると、
--- link: - !!perl/scalar:URI::http http://www.movimap.net/kodawariblog/2007/10/post_134.html - !!perl/scalar:URI::http http://www.movimap.net/kodawariblog/2007/08/post_33.html .... title: - +*。+純和風♪駅が近いので通勤・通学、奥様のショッピングにも便利なんデスヨ~(人・∀・*)+。*+ - ☆鴻巣山のふもとの静かな暮らし☆ ....
おし、これはおげ。
続いて住所情報が欲しいので、
scraper> process '//div[@class="box"]/div[@class="box02"]/p', 'address[]' => 'TEXT'
そして、
scraper> y
その結果が、
--- address: - '■□加藤邸(桜台) 福岡県筑紫野市桜台1丁目7-11 □■ +*○。+純和風のとても素敵なお家です!広さは4LDKと広々!駐車場も一台付いていまーす +。○*+ ' - ■□グレイス長丘 福岡市南区長丘5-8-18□■ ♪♪駐車場2台取れます♪♪ .... link: - !!perl/scalar:URI::http http://www.movimap.net/kodawariblog/2007/10/post_134.html - !!perl/scalar:URI::http http://www.movimap.net/kodawariblog/2007/08/post_33.html .... title: - +*。+純和風♪駅が近いので通勤・通学、奥様のショッピングにも便利なんデスヨ~(人・∀・*)+。*+ - ☆鴻巣山のふもとの静かな暮らし☆ ....
これで、address, title, linkとそれぞれの配列にデータが入った事を確認したところで、
scraper> c
とタイプすると、
#!/usr/local/bin/perl use strict; use Web::Scraper; use URI; my $uri = URI->new("http://www.movimap.net/kodawariblog/family/"); my $scraper = scraper { process '//div[@class="box"]/div[@class="box02"]/p', 'address[]' => 'TEXT'; }; my $result = $scraper->scrape($uri);
とコードを自動生成してくれます!
でも、最初の方に設定したXPathが出てこないみたいなので、ひとまず、
scraper> process '//div[@class="box"]/div[@class="box02"]/p', 'address[]' => 'TEXT'; process '//div[@class="box"]/div[@class="box01"]/h3/a', 'link[]' => '@href', 'title[]' => 'TEXT';
scraper> c
#!/usr/local/bin/perl use strict; use Web::Scraper; use URI; my $uri = URI->new("http://www.movimap.net/kodawariblog/family/"); my $scraper = scraper { process '//div[@class="box"]/div[@class="box02"]/p', 'address[]' => 'TEXT'; process '//div[@class="box"]/div[@class="box01"]/h3/a', 'link[]' => '@href', 'title[]' => 'TEXT'; }; my $result = $scraper->scrape($uri);
とやりました。
<追記:2007-11-15 09:01>
scraper> c all
とすれば良いだけでした。miyagawaさんありがとうございました!
<追記ここまで>
後はこの生成されたコードをコピペして、適当に配列をごにょごにょして、TTへ丸投げ。
movimap_scrape.pl
#!/usr/local/bin/perl use strict; use warnings; use Web::Scraper; use Data::Dumper; use Template; use URI; my $uri = URI->new("http://www.movimap.net/kodawariblog/family/"); my $scraper = scraper { process '//div[@class="box"]/div[@class="box01"]/h3/a', 'link[]' => '@href', 'title[]' => 'TEXT'; process '//div[@class="box"]/div[@class="box02"]/p', 'address[]' => 'TEXT'; }; my $result = $scraper->scrape($uri); my @list; for my $i ( 0 .. scalar @{$result->{"address"}} - 1 ){ my $data = $result->{"address"}->[$i]; $data =~ s/^x{25a0}x{25a1}.*?[ d]+(.+)?x{25a1}x{25a0}.+$/$1/; push @list, { address => $data, link => $result->{"link"}->[$i], title => $result->{"title"}->[$i], }; } my $tt = Template->new({ INCLUDE_PATH => ".", EVAL_PERL => 1 }); $tt->process("webscraper_googlemap.tt", { result => @list });
webscraper_googlemap.tt
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>scraper http://www.movimap.net/kodawariblog/family/</title> <script src="http://maps.google.com/maps?file=api&v=2&key=***" type="text/javascript"></script> <script type="text/javascript"> //<![CDATA[ var lat = 33.58981 var lng = 130.39878 var map = null; var geocoder = null; function load() { if (GBrowserIsCompatible()) { map = new GMap2(document.getElementById("map")); map.addControl(new GSmallMapControl()); map.addControl(new GMapTypeControl()); map.setCenter(new GLatLng(lat, lng), 12); geocoder = new GClientGeocoder(); [% FOREACH item = result %] geocoder.getLatLng( "[% item.address %]", function(point){ if (point){ var marker = new GMarker(point); map.addOverlay(marker); GEvent.addListener(marker, 'click', function() { marker.openInfoWindowHtml("<h4><a href='[% item.link %]'>[% item.title %]</a></h4>");1 }); } } ); [% END %] } } //]]> </script> </head> <body onload="load()" onunload="GUnload()"> <div id="map" style="width: 80%; height: 400px"></div> </body>
こんだけで簡単にGoogle Mapsへのマッピングが完了。
住所を抜き取る正規表現はかなりあやしいです。住所に何らかの定義をしてくれると助かるのだけどなぁ。
<追記:2007-11-15 19:18>
このへっぽこな正規表現の解決策をエントリしました。Geography::AddressExtract::Japanを使って住所抽出 jmalaさん、Yappoさんに感謝!
<追記ここまで>
出来上がったHTMLファイルはこんな感じ。
http://cgfm.jp/~cota/sandbox/webscraper_googlemap.html
僕もスクレイピング脳に少しだけ近づけた気がします。