このページでは、perl プログラムから Web ページを読み込む方法を説明します。perl プログラムの文法や、書き方、実行の方法は、既に知っている事を前提にしています。
ファイルハンドルを使ってファイルを読み込むのと同じ感覚で、Web 上のコンテンツ、つまり HTML や画像データを perl の変数にセットする事ができます。
この方法を使って、例えば自作 CGI に、次のような演出を加えられます。
ローカルで走るプログラムであれば、[Internet Explorer のお気に入り]や[Cookie]、[レジストリ]などにもアクセスできる為、
.exe
ファイルの更新日時を調べ、新しくなっていたら通知すると、夢が広がります。
次の準備が必要です。
MIME::Base64
Socket
FileHandle
ローカルで実行する場合はあまり問題になりませんが、プロバイダのサーバで動かす場合に注意が必要です。
使用に際し、次の点に注意して下さい。
他の人が作成したページは、その人が著作権を有しています。
複写や二次使用をするには、許可や契約が必要となります。
著作権法は、個人利用の範囲であれば、他人の著作物であっても複製してヨシ、と定めていますが、CGI での利用は、「個人利用の範囲」を逸脱しています。普通 CGI は、誰でも読めるようになっているからです。
著作者に無断でページを加工して自分の CGI で表示したり、内容に基づいてCGI の処理を分岐させたりすると、著作者から訴えられる可能性があります。
利用させてもらう前に、必ず著作者の方に確認を取るようにして下さい。
ネットワーク通信は、コンピュータにとって重い作業です。
この技を CGI で使用すると、一回実行するだけでも、通常の(ネットワーク通信を行わない)CGI と比べ、サーバーに大きな負荷がかかります。
同時にいくつも実行すると、ページがなかなか表示されなくなったり、他の CGI の処理速度が低下したりと、自分だけでなく、他の人の迷惑にもなります。
あまり度を越すと、サーバーの管理者から「迷惑行為」とみなされアカウントを剥奪されかねません。
また、接続先のサーバ(読み込み先)の負担も重要です。
これは、CGI だけでなく、ローカルからの使う場合であっても、同様に注意を払わねばなりません。
ブラウザからの読み込みは、人間の指の速さに比例した負荷しか与えませんが、この技を短い周期で自動ループさせたりすると、桁違いの負荷を与えてしまいます。向こうにしてみれば、いわゆる DoS 攻撃を受けているのに近く、迷惑な事おびただしい筈です。ここまでくると、営業妨害で訴えられる可能性もあります。
くれぐれも、常識はずれの負荷は掛けないようにして下さい。
相手や、相手までの伝達経路の混雑具合によって、読み込みにかかる時間はまちまちです。
ひょっとすると長時間、応答が返らないかもしれません。
この間、呼び出し元のプログラムは待ち続ける事になります。しかし CGI プログラムの場合、それは単に、「なかなかページが表示されない」事としてしか反映されません。
インターネットはハードディスクなどと違い、転送経路間に不安定材料が多く、時間も掛かるのが普通です。
CGI の場合、一体何が原因で遅くなっているのか見えないので、ユーザーは、ディズニーのクソネズミ園に並ぶ以上に、ストレスを感じるでしょう。遅い原因は、あなたの技術力不足と判断されるかもしれません。
せっかく来て頂いたお客さんに不愉快な思いをさせるのは残念ですし、自分の預かり知らぬ事が原因で酷評の矢面に立たされるのも、気持ちがいいものではありません。
不確定な要素を含んでいる旨。時間が掛かるかもしれない旨など、予め明記しておくとユーザーフレンドリーでしょう。
更新履歴
o******@***.n**.jp
)よりご指摘頂きました。ありがとうございます。
Base64
モジュールを呼び出す部分を、大文字(Mime
→ MIME
)に変更。(UNIX 環境では、大文字でないと当該モジュールが読み込まれませんでした)chomp
の位置を、while
の条件判断部からループ内に変更。(while 条件部に書いた場合、最後の行が改行コードを含まないとき、その行を読み込めませんでした)getHTML
→ getHTTP
)
\r\n
を \n
に置換しないようにした(すみません。これってバイナリを読む時ヤバかったです)
### ### Web 上のコンテンツを読む perl スクリプト ### A perl script to retrieve contents on the internet via http. ### (C) 2001-2004 笠井 崇文 最終更新日: 2004年 3月 5日 ### (C) 2001-2004 Takafumi Kasai Last modified: 5 May, 2004 ### 本スクリプトは、自由に転載・引用・配布・使用・改変していただいて結構です。 ### 但し、その結果何らかの損害を被った場合も、責任を負いかねます。 ### あらかじめご了承ください。 ### と言いつつ虫の好い話ですが、バグや無駄な部分等を発見されましたら、上記 ### アドレスまでご一報頂ければ幸いです。 ### You can quote, distribute, use, and alter this script without ### any permission. But I never bear responsibility for any possible ### damage by this script. However, I hope to receive reports of ### bugs or wasteful part in this script from you. # ============================================================== # 要件 / Requirements # # ・perl 5 以降 / perl 5 or later # ・以下の perl モジュール / perl modules follows: # Socket # FileHandle # MIME::Base64 # (ActivePerl 等に付属のものや、CPAN からダウンロードしたものを別途ご用意下さい) # (You can get them from ActiveStates or CPAN) # 使用方法 / Usage # # (1) このスクリプト(getHTTP)を、@INC にパスの通った場所に置く。 # (2) 呼び出し元のプログラムで、 # require('getHTTP'); # と書く。 # (3) # ($http_response, $errorMessage) = &getHTTP('http://www.kasai.fm/'); # のように、Web 上のコンテンツを読みこめる。 # $http_response に、読み込んだコンテンツが入る。 # もしエラーが起ると、$errorMessage にエラー理由が入る。 # (1) Put this script where @INC can reach. # (2) In the caller script, put this code: # require('getHTTP'); # (3) # ($http_response, $errorMessage) = &getHTTP('http://www.kasai.fm/'); # will retrieve contents on the internet. # 認証の必要なページを見る場合 / In case authorization required # ($http_response, $errorMessage) = &getHTTP('URL'=>'http://www.kasai.fm/', # 'UserID'=>'Mihata', 'Password'=>'Tatenashi'); # プロクシを使う場合 / In case you use a proxy # ($http_response, $errorMessage) = &getHTTP('URL'=>'http://www.kasai.fm/', 'Proxy'=>'someproxy.com:8080'); # 認証の必要なプロクシを使う場合 / In case you use a proxy which requires authorization # ($http_response, $errorMessage) = &getHTTP('URL'=>'http://www.kasai.fm/', 'Proxy'=>'someproxy.com:8080', # 'ProxyUserID'=>'Alladin', 'ProxyPassword'=>'open_sesami'); # ============================================================== use Socket; use FileHandle; #use MIME::Base64; require('BASE64'); sub getHTTP{ local $\ = ""; my %arg = ( @_ ); my $data; my ( $uri, $proxy_address, $proxy_port, $http_version, $user_id, $password, $proxy_user_id, $proxy_password, $referrer, $referer, $agent ) = ( $arg{URL} || $_[0], $arg{Proxy} || "", $arg{ProxyPort} || "8080", $arg{HTTP} || "1.1", $arg{UserID} || "", $arg{Password} || "", $arg{ProxyUserID} || "", $arg{ProxyPassword} || "", $arg{Referrer} || "", $arg{Referer} || "", $arg{UserAgent} || "HTTP client version 1.02 (www.kasai.fm)" ); my ( $scheme, $domain, $server_address, $server_port, $path ); my ( $target_address, $target_port, $target_path, $target_ip ); ######### URI parsing ### retrieve scheme ( "http://" ) if ( $uri =~ s!^(\w+?)://!! ){ $scheme = $1; return ("", "Can't handle '$scheme'. Only 'http' is possible" ) if ( $scheme !~ /^http$/i ); } else{ $scheme = 'http'; } ### retrieve domain, port and path ( "hogehoge:8080/foo/bar.html" ) ( $domain, $path ) = split( /\//, $uri, 2 ); ( $server_address, $server_port ) = split( /:/, $domain, 2 ); $server_address ||= "localhost"; $server_port ||= getservbyname( $scheme, "tcp" ); ### complete info about your proxy server if ( $proxy_address and !$proxy_port ){ ( $proxy_port ) = $proxy_address =~ /:(\d+)/; return ("", "Proxy port is undefined.". "Specify 'ProxyPort'=>8080 or 'Proxy'=>'${proxy_address}:8080'" ) unless ( $proxy_port ); } ### switch arguments according to if you use a proxy server ( $target_address, $target_port, $target_path ) = $proxy_address ? ( $proxy_address, $proxy_port, "${scheme}://${server_address}:${server_port}/${path}" ) : ( $server_address, $server_port, "/$path" ); ######### SOCKET (create) $target_ip = inet_aton( $target_address ) || return ("", "Can't connect to $target_address" ); $sock_address = pack_sockaddr_in( $target_port, $target_ip ); socket(SOCKET, PF_INET, SOCK_STREAM, 0) || return ("", "Can't create socket on $target_address"); ######### SOCKET (connect) connect(SOCKET, $sock_address) or return ("", "Can't connect socket on $sock_address"); autoflush SOCKET (1); ######### Send HTTP GET request if ( $http_version eq "1.1" ) { print SOCKET "GET $target_path HTTP/1.1\n"; print SOCKET "Host: $target_address\n"; print SOCKET "Connection: close\n"; } else { print SOCKET "GET $target_path HTTP/1.0\n"; } if ( $user_id ){ print SOCKET "Authorization: Basic\n "; print SOCKET &base64'b64encode("${user_id}:${password}")."\n"; } if ( $proxy_user_id ){ print SOCKET "Proxy-Authorization: Basic\n "; print SOCKET &base64'b64encode("${proxy_user_id}:${proxy_password}")."\n"; } print SOCKET "User-Agent: $agent\n" if ( $agent ); print SOCKET "Referrer: $referrer\n" if ( $referrer ); print SOCKET "Referer: $referer\n" if ( $referer ); print SOCKET "Accept: text/html; */*\n"; print SOCKET "\n"; ######### Receive HTTP response via SOCKET while ( <SOCKET> ) { chomp; $data .= "$_\n"; } ######### SOCKET (close); take down the session close(SOCKET); ######### return return ($data, ""); } 1;
使用する手順は次の通りです。
getHTTP
というファイル名で保存します。getHTTP
と同じフォルダに置きます。require('getHTTP');
($http_response, $errorMessage) = &getHTTP('http://www.kasai.fm/');
&getHTTP('xxxxx')
の、xxxxx
の部分に、読み込みたいページのアドレス(URL)を書く訳です。$http_response
に、サーバーからの応答が入ります。$errorMessage
にエラー理由が入ります。この時$http_response
には空文字列が返ります。$http_response
は、そのままではホームページとして表示することができません。$http_response
には、通信上必要となる様々な情報も含まれているからです。($http_response, $errorMessage) = &getHTTP('URL'=>'http://www.kasai.fm/', 'UserID'=>'Mihata', 'Password'=>'Tatenashi');
($http_response, $errorMessage) = &getHTTP('URL'=>'http://www.kasai.fm/', 'Proxy'=>'someproxy.com:8080');
($http_response, $errorMessage) = &getHTTP('URL'=>'http://www.kasai.fm/', 'Proxy'=>'someproxy.com:8080', 'ProxyUserID'=>'Alladin', 'ProxyPassword'=>'open_sesami');
本プログラムは、自由に配布、使用、改変して頂いて結構です。転載の許可も必要ありません。
但し本プログラムを使用した結果、何らかの損害を被ったとしても、当方では責任を負いかねます。ご了承ください。
と言いつつ虫の好い話ですが、バグや無駄な部分等を発見されましたら、下記アドレスまでご一報頂ければ幸いです。