Adobe Creative Suite 出力対応店一覧をGoogle Mapsで表示させる(4)
アドビのCS4対応プリントショップのリストのページから、Google Mapsに表示させるやつの4回目。
前回 は、アドビのサーバからHTTPステータスコードが200ばっかり返ってくるので、ステータスコードは使えないから、HTTPレスポンスヘッダを見てみよう、ということで、FirefoxのLive HTTP Headersという機能拡張を入れて調べたところ、ヘッダからはコンテンツの更新がわからないということがわかりました。ということは実際に取得してみなくてはわからないと言うことになりますが、どうしよう? ていうところまでやりました。
さて、アドビのサーバは、「取得したデータは取得した側で6時間キャッシュしてね。内容変更はヘッダでは教えてあげないよ。」と言っているわけなので、まず、6時間ごとアドビのサーバから取得すればいい、という方針が立ちます。従って、取得する部分は6時間ごと実行するようにcronに設定すればいいかなあということになります。
また、6時間ごと取得しても、内容に変化がないことがあるのも予想されますので、「内容に変化がない」ことを検出する仕組みを作らなくてはなりません。どうしよう。
そこで、今回は「取得したHTMLの長さを比較する」方法でいきたいと思います。なお、この方法は、AdobeさんがPDFの改変チェックで採用している由緒正しい古式ゆかり な 方式です。PDFのチェックサムの再計算とか知らなかったとき、ゲームのセーブデータをいじるがごとく手法でPDFをいじっていたのを思い出します。
今回のコードはこんな感じです。
#!/usr/bin/perl
# Filename: test3.pl
use strict;
use warnings;
use URI::Fetch;
use Cwd;
# GETしてきたコンテンツの長さを記録するファイル
my $cwd = getcwd; # カレントディレクトリ
my $length_file = "$cwd/length.txt";
# GETするコンテンツのURL(STATUSが常に200なので
# 内容変更調べるにはコンテンツの大きさを使う)
my $url= 'http://www.adobe.com/jp/print/printshop/';
# main
my $html = get_html($url);
print "modified:\n" if $html;
exit;
sub get_html {
my $url = shift;
# length.txtから前回取得時のコンテンツの大きさを
# 取得するよ
my $length = 0;
if ( -e $length_file ) {
open my $fh, '<', $length_file or die $!;
$length = <$fh>;
close $fh;
}
# Webからコンテンツを取得するよ
my $ua = new LWP::UserAgent;
$ua->timeout(10);
$ua->agent('DTPWiki.jp AdobeJpPrintShopMap/0.1 '
. '(+http://labo.dtpwiki.jp/printmap/)'
);
my $res = URI::Fetch->fetch(
$url, UserAgent => $ua,
) or die URI::Fetch->errstr;
my $html = $res->content;
# 今回取得したWebコンテンツの大きさを記録するよ
my $length_new = length($html);
{
open my $fh, '>', $length_file or die $!;
print $fh $length_new;
close $fh;
}
# 前回と大きさが変わらない場合はundef、
# 変わっている場合はコンテンツを返すよ
return ( $length == $length_new
? undef
: $html
);
}
__END__
実行結果:
$ perl test3.pl
modified:
$ perl test3.pl
$ cat length.txt
188685$ cat > length.txt
120000
$ perl test3.pl
modified:
$ cat length.txt
188685$
1回目は更新と検出、2回目は変更なしと検出、length.txtファイルにはコンテンツのサイズが入っています。意図的にlength.txtファイルを書き換えてやると、その次に取得した場合は変更ありと検出されていることが確認できました。
ちなみに、length.txtに記録されるのは、HTTPレスポンスヘッダのContent-Lengthの値ではなくて、実際データとして利用できるコンテンツのサイズです。アドビのサーバからは、GZipエンコーディングで圧縮された状態で送られてくるのですが、URI::Fetchが自動的に伸張するのですね。
泥臭いですが何とかアドビさんからHTMLをGETするところができました。
次回 は、いったんWebやHTTPから離れて、HTMLを解析するところをやりたいと思います。
(2009-10-30 14:00修正)
<del>由緒正しい</del><ins><a href="http://www3.airnet.ne.jp/gomimemo/tmron/yukari.htm" target="_blank">古式ゆかり</a>な</ins>
ブックマークのコメント で、「ダメな手法を真似したらダメ。ギャグのつもりならネタだと分かるようにかいてほしい」とOtsuneさんから指摘があったので、ギャグにしました。念のため、古式ゆかりは本命キャラ攻略失敗時に出てくるキャラです。
アドビの擁護をするならば、PDFはバイトサービングなどの細切れで転送される用途もあったため、ファイル全体のハッシュ値でファイルの健全性を確認する手法は使えなかったのかもなあと思っています。
2009.10.29
12:30
[GoogleMaps ]
|
固定リンク
|
コメント
(0)
|
トラックバック
(0)
|
Adobe Creative Suite 出力対応店一覧をGoogle Mapsで表示させる(2)
アドビのCS4対応プリントショップのリストのページから、Google Mapsに表示させるやつの2回目。
前回 は、アドビのページから、HTMLを取得するところをやりました。
HTMLを取得するときに、キャッシュをして、コンテンツに変更がない場合は、キャッシュから使うような仕組みにしました。
さて、データを取得したかどうか、というのは、この後控えているジオコーディング(住所から経度緯度を取得する)をするかしないか、という判断に使うことになるので、重要です。
それを判断するためには、HTTPのステータスコードを使います。
ステータスコードというのは、404 Not foundとかいうところの404とかの数字で、サーバにURLを伝えてコンテンツの要求をしたとき、サーバからそのURLで示されるコンテンツがどうなっているかを知らせるために使うものです。
ステータスコード/意味
200 Found
404 Not Found
304 Not Modified
今回関係ありそうなのはこの程度。
それで、ステータスコードを表示するように改良したソースを以下に示します。
Filename: test2.pl
#!/usr/bin/perl
# Filename: test2.pl
use strict;
use warnings;
use Cache::File;
use URI::Fetch;
use Cwd;
my $cwd = getcwd;
my $cache = Cache::File->new(
cache_root => "$cwd/cache",
);
my $ua = new LWP::UserAgent;
$ua->timeout(10);
$ua->agent('DTPWiki.jp AdobeJpPrintShopMap/0.1 '
. '(+http://labo.dtpwiki.jp/printmap/)'
);
my $res = URI::Fetch->fetch(
'http://www.adobe.com/jp/print/printshop/',
Cache => $cache,
UserAgent => $ua,
) or die URI::Fetch->errstr;
my $html = $res->content;
print $res->http_status."\n";
__END__
さてこれを実行してみて、ステータスコードを観察しましょう。
$ perl test2.pl
200
$ perl test2.pl
200
$
……ええと、想定では、2回目の実行は304が返ってくるはずなのですが。
調べてみたところ、アドビのプリントショップリストのページがあるURLに関しては、毎回必ず200を返すようになっていました。なんだって!
手持ちのWebサーバの静的コンテンツのURLを指定した場合は、ちゃんと1回目が200、2回目が304になるんです。
というわけで、このプログラムだと、コンテンツの更新があったかどうかを検出することができないということになりました。
ちょっと考えなくてはいけないようですね。(続く )
2009.10.26
00:00
[GoogleMaps ]
|
固定リンク
|
コメント
(0)
|
トラックバック
(0)
|
Google Maps APIを使って住所リストからGoogle Mapsに表示するまで
印刷業界の仲間に、印刷ネタでWebコンテンツを作ってみることを促すシリーズ。
住所リストがあって、緯度経度を知りたい、というときに、Google Maps APIのジオコーディングが使えます。
今回は、日本印刷産業連合会のウェブサイトで、環境に配慮した印刷会社、グリーンプリンティング認定工場のリストがあったのでこれの第13回認定工場一覧を使います。
http://www.jfpi.or.jp/greenprinting/introduction/index.html
▲まじこれ見て発注してくださいよーたのんまっすよー
まず、Googleで「Google Maps API Geocoding」で検索すると出てくる
http://code.google.com/intl/ja/apis/maps/documentation/services.html
から、ジオコーディングの「例を表示 (geocoding-simple.html)」
http://code.google.com/intl/ja-JP/apis/maps/documentation/examples/geocoding-simple.html
にサンプルが有ります。ここのサンプルの動作を一通り楽しんだ後、Operaで「ページのソースを表示」を選択します。
次に、おもむろにソースをこのように改変します。
<!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" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<script src="http://maps.google.co.jp/maps?hl=ja&file=api&v=2.x&key=(略)" type="text/javascript"></script>
<script type="text/javascript">
var list = [
['オフセット','A10007','宝印刷株式会社','印刷部浮間工場','東京都北区浮間4-24-23','H21.9.30','H24.9.29'],
['オフセット','B10099','六三印刷株式会社','水沢工場','岩手県奥州市水沢区佐倉河字仙人6-1','H21.9.30','H24.9.29'],
['オフセット','B10100','株式会社アカマ印刷','本社工場','山口県下関市長府扇町9-10','H21.9.30','H24.9.29'],
['オフセット','B10101','株式会社橋本清文堂','','石川県金沢市示野町南51','H21.9.30','H24.9.29'],
['オフセット','B10102','株式会社金羊社','本社','東京都大田区鵜の木2-8-4','H21.9.30','H24.9.29'],
['オフセット','B10103','株式会社山口県農協印刷','','山口県山口市嘉川668-1','H21.9.30','H24.9.29'],
['オフセット','B10104','株式会社ソーエイ','','兵庫県明石市樽屋町6-6','H21.9.30','H24.9.29'],
['オフセット','B10105','冨士オフセット印刷株式会社','','茨城県水戸市根本3-1534-2','H21.9.30','H24.9.29'],
['オフセット','B10106','株式会社横山印刷','','茨城県土浦市卸町2-6-6','H21.9.30','H24.9.29'],
['オフセット','D10004','あさひ高速印刷株式会社','本社・本社工場','大阪府大阪市西区江戸堀2-1-13','H21.9.30','H24.9.29'],
['オフセット','F10017','小澤製本株式会社','本社工場','東京都荒川区西尾久8-27-3','H21.9.30','H24.9.29'],
['オフセット','J10003','株式会社大和紙工業','本社工場','埼玉県和光市新倉7-12-13','H21.9.30','H24.9.29'],
['オフセット','J10004','興亜産業株式会社','本社工場','東京都板橋区高島平1-55-16','H21.9.30','H24.9.29'],
['シール','G20010','株式会社ヒロミ産業','','北海道札幌市西区発寒14条2-2-21','H21.9.30','H24.9.29'],
['グラビア','H30020','北海紙工業株式会社','','北海道小樽市銭函3-524-15','H21.9.30','H24.9.29'],
['グラビア','H30021','株式会社東和プロセス','川口工場','埼玉県川口市領家5-8-18','H21.9.30','H24.9.29']
];
var last = list.length;
var timer;
var count = 0;
var geocoder = null;
function initialize() {
if (GBrowserIsCompatible()) {
geocoder = new GClientGeocoder();
}
}
function showAddress() {
address = list[count][4];
if (geocoder) {
geocoder.getLatLng(
address,
function(point) {
if (!point) {
document.getElementById('list').innerHTML
+= address + ",not found,\n";
} else {
document.getElementById('list').innerHTML
+= address + "," + point.toUrlValue() + "\n";
}
count ++;
if ( count != last ) timer = setTimeout( showAddress, 3000 );
}
);
}
}
</script>
</head>
<body onload="initialize();showAddress();" onunload="GUnload()">
<textarea id="list" style="width: 100%; height: 300px;"></textarea>
</body>
</html>
そして、Operaのページソースタブの「更新を適用」ボタンを押すと、Google Maps APIのジオコーディング問い合わせに3秒ごとに問い合わせてtextareaに書き出すことができます。
textareaの部分をコピペして、緯度経度をlistに反映。手作業ですw
反映した後地図に表示させるコードはこんな感じ。
<!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" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<script src="http://maps.google.com/maps?file=api&v=2&key=(自分が取得したkeyに置き換えてね)"
type="text/javascript"></script>
<script type="text/javascript">
var list = [
['オフセット','A10007','宝印刷株式会社','印刷部浮間工場','東京都北区浮間4-24-23','H21.9.30','H24.9.29',35.78669,139.690808],
['オフセット','B10099','六三印刷株式会社','水沢工場','岩手県奥州市水沢区佐倉河字仙人6-1','H21.9.30','H24.9.29',39.160941,141.152834],
['オフセット','B10100','株式会社アカマ印刷','本社工場','山口県下関市長府扇町9-10','H21.9.30','H24.9.29',34.020314,131.017882],
['オフセット','B10101','株式会社橋本清文堂','','石川県金沢市示野町南51','H21.9.30','H24.9.29',36.576984,136.608892],
['オフセット','B10102','株式会社金羊社','本社','東京都大田区鵜の木2-8-4','H21.9.30','H24.9.29',35.573727,139.682746],
['オフセット','B10103','株式会社山口県農協印刷','','山口県山口市嘉川668-1','H21.9.30','H24.9.29',34.075746,131.394741],
['オフセット','B10104','株式会社ソーエイ','','兵庫県明石市樽屋町6-6','H21.9.30','H24.9.29',34.646664,134.986707],
['オフセット','B10105','冨士オフセット印刷株式会社','','茨城県水戸市根本3-1534-2','H21.9.30','H24.9.29',36.387537,140.465555],
['オフセット','B10106','株式会社横山印刷','','茨城県土浦市卸町2-6-6','H21.9.30','H24.9.29',36.047697,140.145749],
['オフセット','D10004','あさひ高速印刷株式会社','本社・本社工場','大阪府大阪市西区江戸堀2-1-13','H21.9.30','H24.9.29',34.687638,135.490952],
['オフセット','F10017','小澤製本株式会社','本社工場','東京都荒川区西尾久8-27-3','H21.9.30','H24.9.29',35.75246,139.754298],
['オフセット','J10003','株式会社大和紙工業','本社工場','埼玉県和光市新倉7-12-13','H21.9.30','H24.9.29',35.802047,139.621708],
['オフセット','J10004','興亜産業株式会社','本社工場','東京都板橋区高島平1-55-16','H21.9.30','H24.9.29',35.784187,139.673496],
['シール','G20010','株式会社ヒロミ産業','','北海道札幌市西区発寒14条2-2-21','H21.9.30','H24.9.29',43.098772,141.296774],
['グラビア','H30020','北海紙工業株式会社','','北海道小樽市銭函3-524-15','H21.9.30','H24.9.29',43.137071,141.179022],
['グラビア','H30021','株式会社東和プロセス','川口工場','埼玉県川口市領家5-8-18','H21.9.30','H24.9.29',35.788408,139.742903]
];
var last = list.length;
var count = 0;
function initialize() {
if ( GBrowserIsCompatible() ) {
var map = new GMap2( document.getElementById("map_canvas") );
map.addControl(new GLargeMapControl() );
map.addControl(new GMapTypeControl () );
var point = new GLatLng(36.03, 139.15);
map.setCenter(point, 8);
var markers = [];
var gb;
var first = 1;
var manager = new GMarkerManager(map);
for ( count = 0; count < last; count++ ) {
var point = new GLatLng( list[count][7], list[count][8] );
var marker = new GMarker(point);
markers.push( marker );
if( first ){
gb = new GLatLngBounds( marker.getPoint(), marker.getPoint() );
first = 0;
}
else {
var point = marker.getPoint();
gb.extend( point );
}
}
manager.addMarkers( markers, 0 );
map.setCenter( gb.getCenter(), map.getBoundsZoomLevel( gb ) );
manager.refresh();
}
}
</script>
</head>
<body onload="initialize();" onunload="GUnload()">
<div id="map_canvas" style="width: 900px; height: 600px;"></div>
</body>
</html>
クリックすると社名が表示されるなどは実装していないけれども(賞味30分仕事だし)、配列に持っているからすぐできると思います。
地図に表示させるのは結構簡単なので、手持ちの住所リストでやってみるとおもしろいと思います。
本来は3回ぐらいに分けてやればいいネタだけど1回で終わってしまった……。
2009.10.22
23:10
[Web ]
|
固定リンク
|
コメント
(0)
|
トラックバック
(1)
|