≪ 夏バテな予感… |メインページへ戻る| 好きに書いてもいいじゃん ≫

2005年06月13日

【 続:Perlで天気予報表示 】

[2006年4月某日追記]
ネタ元のフォーマットが変って、以前に作ったスクリプトではパーズできなくなってたので、暫く放置していましたが、やる気になったので表示再開します。久しぶりにジブンのブログのTOPでも天気予報が見たくなったので(どんな理由だ?)、ザックリとやっつけました。

今回もネタを引っ張ってくきてオフセットを読んで、正規表現でパーズしたり置き換えたりするところまでは同じです。でもその後はJavascriptには畳み込まずにふつ~のテキストファイルに落とし込んでみました。デフォルトで非表示にしていることもあり、GoogleMapsのAjax APIを使ってページがロードされた後、そのテキストファイルを非同期で読み込んでいます。

■以下は2005年06月13日の、オリジナルのエントリです:
お昼休みにゴソゴソとPerlで書いてみた。Socketで天気予報情報を引っ張ってきて、パーズしてJavaScriptとして整形保存。PHP版は見たことがあるけど、Perl版は見たことないからね、とりあえずお遊びってコトで。

おおまかな流れは「CGIで呼び出し」→「Socket生成」→「HTTPセッション開始」→「本文を抜き出して正規表現で整形」→「JavaScritに畳む」ってカンジです。難点と言えば、最新の情報が実はページがロードされた後でサーバ側へ落ちてくるので、微妙な時間帯では、ひょっとすると「最新じゃないかも」な情報がページに表示されてしまう可能性があるコト。でもまぁ明示的に「再読み込みしてみてね」ってコメントも付けてるし、PHPが使えないとか制約があるサーバではRSS引っ張ってきてゴソゴソするとか、色んな応用ができるハズです。

サーバにはPerlの5.8以上がインストールされていなければなりません。これはSocket.pm、そして必要に応じてEncode.pmを利用するからです。5.8以降ではこれらモジュールが標準でインストールされていますが、それ以前のバージョンではモジュールをCPANから放り込んでやる必要があります。借りてるサーバ屋さんがモジュールのインストールを認めていない場合(ほとんどの場合そうでしょうが…)、スクリプトと同じ階層へモジュールの必要なファイルをアップロードして、強引かつ勝手に'use lib'で認識させちゃう手もありますが、下手すると怒られたりするので、このアタリは自己責任でやってクダサイ。ここまで読んでナニ書いてるのか「サパーリ判らん」状態な場合はあきらめた方が得策です。素直にPHPが使えるホスティング屋さんに乗り換えて健全に動的なページを楽しみましょう。ちなみに、その手のホスティング屋さんならPerlも最新のバージョンがインストールされているはずです。

スクリプトは次のように始まります。
#!/usr/bin/perl
use Socket;
Perlのパスはサーバの環境に合わせて変更しましょう。Socketを使う旨を宣言しています。
use Encode;
use Encode qw/from_to/;
binmode STDERR,"encoding(euc-jp)";
アタシの場合サイトをUTF-8でエンコーディングしているので、吐き出すJavaScriptもUTF-8にする必要があります。ってなワケで、先の指定に加え加え、上のようにEncodeの使用を宣言しています。吐き出す結果もEUC-JPのままでよければ、Encodeは必要ありません。

続いて変数に値を落とします。
$host = 'www.SomeWeatherSource.feed.or.domain';
#上のネタ元は適当に読み替えてくださいな
$port = getservbyname('http', 'tcp');
$ipAddr = inet_aton($host);
$socketAddr = pack_sockaddr_in($port, $ipAddr);
関数getservbyname()の使い方はPHPと同じです。最初の引数にサービス名、次にプロトコル名を与え、対象となるポート番号を得ます。関数inet_aton()は引数にホスト名から4バイトの構造体としてのIPアドレスを得ます。構造体のままでかまわないのかと言う疑問が一瞬沸くかも知れませんが、内部処理でハンドリングされるのでこのままでかまいません。関数pack_sockaddr_in()には最初の引数にポート番号、次に構造体で表された構造体を渡します。これで接続先のソケット・アドレスが生成されます。

では、ソケットを生成してファイルハンドルと結び付けましょう。
socket(FH, PF_INET, SOCK_STREAM, 0);
connect(FH, $socketAddr);
select(FH);
$| = 1;
select(STDOUT);
関数socket()の最初の引数がファイルハンドルです。任意の名前でかまいません。二番目の引数では、利用するプロトコル・ファミリを指定します。インターネット通信ですのでPF_INET(ARPAのインターネット・プロトコル)を指定します。三番目の引数にはタイプを指定します。この場合、TCPを利用するのでSOCK_STREAMを指定します。四番目の引数のプロトコル番号には、ゼロを指定します。関数connect()で接続を開始します。最初の引数には先で指定したファイルハンドル、二番目の引数にpack_sockaddr_in()で指定したホストとポートを渡します。出力用のファイルハンドルをselect()で指定します。$|は現在selectされているファイルハンドルに対する特殊変数です。$|に1を指定することでバッファリングをOFFにします。

続いてHTTPセッションを開いて(出力して)、リモートのHTMLファイルを読み込みます。
print FH "GET /index.html HTTP/1.0\r\n\r\n";
while (<FH>){m/^\r\n$/ and last;}
while (<FH>){$tmpString .= $_;}
Telnetと同じですね。GETしたいファイルを指定し、HTTPのバージョンを出力し続けてお約束の空行が2行。最初のwhileはHTTPヘッダを読み飛ばしています。次のwhileで変数$tmpStringにコンテンツ(HTMLファイルの中身)を落としています。

基本的にはこれだけです。必要な素材は$tmpStringに落ちていますから、中身を洗って必要な情報だけ抜き出します。もちろん$tmpStringを得ているループの中でやっつけてかまいません。アタシの場合は畳み込んだ内容をJavaScriptに落として、HTMLの中から読み込ませています。スクリプト自体はビーコン用のCGIのサブルーチンとして組み込んで、ページがロードされた時点でトリガされるようにしています。

単にサーバ経由で特定のWebページを読み出してブラウザに表示したければ以下のようなスクリプトになります。適当にfoobarr.cgiとか名前をつけて実行属性を持たせ、サーバの然るべきディレクトリにアップロードしてブラウザから突けば、$hostで指定したWebページが表示されるハズです。最後のヒア文はHTTPの出力部分です。このスクリプトはEUCで書かれ、なおかつ引っ張ってくるWebページもEUCであることを前提にしています。エンコーディングが異なる場合は、JcodeやEncodeで変換する必要があります。
#!/usr/bin/perl
use Socket;
$host = 'some.domain.com';
$port = getservbyname('http', 'tcp');
$ipAddr = inet_aton($host);
$socketAddr = pack_sockaddr_in($port, $ipAddr);

socket(FH, PF_INET, SOCK_STREAM, 0);
connect(FH, $socketAddr);
select(FH);
$|=1;
select(STDOUT);

print FH "GET /index.html HTTP/1.0\r\n\r\n";
while (<FH>){m/^\r\n$/ and last;}
while (<FH>){$tmpString .= $_;}

print <<HERE;
Content-Type: text/html; charset=EUC-JP
Content-Language: ja
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Last-Modified: Sat, 01 Jan 2000 00:00:00 GMT
Cache-Control: no-cache, must-revalidate
Pragma: no-cache


$tmpString
HERE
exit;

|by Nagarazoku : 16:54コメント (0)トラックバック (0)

トラックバック・スパム対策のため、このBLOGへのリンクを持たないページから送られたトラックバックは自動的に拒否されます。悪しからずご了承ください。
また、このエントリと全然関係の無い内容のページからのトラックバックは、アタシ的な判断で勝手に削除します。これも又、ご了承くださいマセ。

■このエントリーのトラックバックURL ≫ http://www.nagarazoku.com/mvt/mt-tb.cgi/135



▼コメント(スパム対策のため、半角英文のみのコメントは受け付けていません。悪しからずご了承ください。)




保存しますか?