Walrus,Digit. | 一覧 | 検索 | 更新履歴(RSS) | 新規作成
はてなブックマークに追加 はてなブックマークを表示 編集 | 編集(管理者用) | 差分

Perlモジュール/LWP

編集

WWW上のデータ−主としてホームページ等−を取得し、処理するためのライブラリ。 正式名称は「libwww-perl」なのですが、Perl5で本体が「LWP」という名前になっており、今ではこちらの呼び方も一般的に使われています。

HTTPクライアントとしては、LWPの他にHTTP::Liteというモジュールもあります。 LWPの使用が難しい環境(CGIやPerlCE)を意識したもので、HTTPSやftp等に対応していないもののHTTPだけであれば、使い勝手の良いモジュールです。

LWPの入手

編集

CPANまたはPPMによるモジュールのインストールで入手できます。 この際、モジュールの指定は「LWP」ではなく「libwww::perl」とします。

LWPは非常に多くのファイルからなる、ちょっと込み入ったモジュールです。 tarボールを取得してインストール、と行った方法はお奨めできません。

Perl4を使う場合

下のサイトから、libwww-Perl4 Distributionを入手する事ができます。

http://www.ics.uci.edu/pub/websoft/libwww-perl/

LWPのFAQ

LWPは便利なのですが、LWP、lwpcook、LWP::~など、ドキュメントが多岐にわたってしまいます。 実際に使うとなるとそれらを読むべきなのですが、使う前に知っておきたいんだけど、というようなリクエストへの回答として、FAQを作成しました。

余談ですがSoftWare?に掲載しているINCMプラグインは、インターネットへのアクセスは(INCMプラグインには珍しく)LWP::UserAgentやLWP::RobotUAを使用しています。

LWPで、「https://」で始まるSSL使用サイトにアクセスできますか?

できます。

LWPはCrypt::SSLeayがインストールされていれば、自動的にSSL使用サイトへのアクセスも適切に処理してくれます。アクセス先が「https://」で始まっていても、スクリプトを変える必要はまったくありません。それどころか、プロトコルが「http」か「https」かということすら判定する必要はありません。

ppmコマンドでCrypt::SSLeayをインストールするには、モジュール名ではなく、PPDファイルを指定してあげる必要があります。この理由や指定すべきPPDファイルについてはStatus of the ActiveState PPM Repositoriesの「Cryptographic Modules」で説明されています。

ActivePerl 5.6.x build 6xxを使っている時は、以下のようにします。

ppm install http://theoryx5.uwinnipeg.ca/ppmpackages/Crypt-SSLeay.ppd

ActivePerl 5.8.x build 8xxを使っている時は、以下のようにします。

ppm install http://theoryx5.uwinnipeg.ca/ppms/Crypt-SSLeay.ppd

なお、古いバージョンのLWPモジュールは、Net::SSLeayモジュールでも代用できました。現在ActivePerlに同梱されているLWPモジュールでは、すでにこのサポートはなくなっています(が、LWP::Protocol::https10.pmにその痕跡を見ることができます)。 もし何らかの理由でNet::SSLeayモジュールをインストールしたい時は、CPANモジュールを使ってください。ActivePerl 5.6.xを使っていて、PPMでのインストールをしたい時には、以下を試してみてください。

ppm install http://www.gossamer-threads.com/ppm/Net-SSLeay-1.22-5.6.1.ppd

ActivePerl 5.8.xを使っていて、PPMでのインストールをしたい時には、以下を試してみてください。

ppm install http://www.gossamer-threads.com/ppm/Net-SSLeay-1.22-5.8.0.ppd

これはこちらからリンクされているものを見つけたものです。将来的に長く残されることを前提にはしていないと考えた方が良いと思います。これを利用できなくなった時には、今回、私が上を見つけたgoogleの検索結果から利用できるものを探してみてください。

LWPでプロキシは使えますか?

使えます。

LWP::Simpleを使っている場合は、あらかじめ環境変数「HTTP_PROXY」、「HTTPS_PROXY」などにプロキシを設定しておくと、これが利用されます。 通常、この設定は「.rcstart」(UNIX系のBASH)や「autoexec.bat」(Windows)、最近のWindowsであれば「システムのプロパティ」の「詳細設定」タブにある「環境変数」などで行います。

LWP::UserAgentやLWP::RobotUAを使っている場合は、2種類の方法があります。 1つ目は上記同様に環境変数を設定した上で、$ua->env_proxyを呼び出す方法です。 以下は、スクリプト中で環境変数の設定をし、$ua->env_proxyを呼び出す例です。

my $ua = LWP::UserAgent->new;
$ENV{'HTTP_PROXY'} = 'http://proxy:8080';
$ua->env_proxy;

もう1つは、$ua->proxyで直接任意のプロキシを設定してしまうことです。

my $ua = LWP::UserAgent->new;
$ua->proxy('http', 'http://proxy:8080');

この他に、LWP::UserAgentモジュールとLWP::RobotUAモジュールにはnoproxyなどのメソッドもあります。

LWPでプロキシ認証は扱えますか?

扱えます。

LWP::UserAgentやLWP::RobotUAを使っている場合は、処理対象のHTTP::Requestオブジェクトに、proxy_authorization_basicメソッドで認証情報を持たせます。このメソッドは、HTTP::Headersモジュールから継承しているものです。例えば、次のようになります。

my $ua = LWP::UserAgent->new;
$ua->proxy('http', 'http://proxy:8080'); # env_proxyでプロキシ設定している場合でも同じ
my $req = HTTP::Request->new('GET', 'http://example.com/sample/');
$req->proxy_authorization_basic('username', 'password'); # プロキシ認証用の情報設定
my $res = $ua->request($req);

LWP::Simpleを使っている場合には、次のようにする方法があるようです。ActiveState.comのperl-win32-usersへの投稿で見つけました。

if ($ENV{HTTP_proxy_user} and $ENV{HTTP_proxy_pass}
    and $ENV{HTTP_proxy} =~ /^http:\/\/([^@]+)$/) {
       my $proxy ="http://$ENV{HTTP_proxy_user}:$ENV{HTTP_proxy_pass}\@" . $1;
       print "setting user/pass into proxy_env...\n";
       $ua-> proxy(['http'], $proxy);
}

LWPでPOSTメソッドを使えますか?

使えます。

POSTメソッドを使うのであれば、LWP::Simpleではなく、LWP::UserAgentかLWP::RobotUAを使う必要があります。 これでいつも通りHTTP::Requestモジュールでリクエストを、POSTメソッドを指定して生成しても良いのですが、そうするとフォームデータをリクエストに入れるときに、content-typeを考慮したり、エスケープを済ませておいたりということが必要で、面倒です。 代わりにHTTP::Request::Commonモジュールを使ってリクエストを生成すると良いでしょう。 生成したリクエストは、いつも通りLWP::UserAgentかLWP::RobotUAのオブジェクトに処理させるだけです。

use LWP::UserAgent;
use HTTP::Request::Common qw(POST);

# リクエストの生成
my $url      = 'http://localhost/test.cgi';
my %formdata = ('user' => 'アリババ', 'password' => 'opensesami');
my $request  = POST($url, [%formdata]);

# UserAgentを生成して処理
my $ua = LWP::UserAgent->new;
my $res = $ua->request($request);
print $res->as_string;

POSTの時と同じように、GETメソッド用のリクエストを生成するのにもHTTP::Request::Commonモジュールを使うことができます。 この場合でも、エスケープの手間が省けるのは良い点でしょう。 この場合、POSTではフォームの値を配列リファレンスで渡しましたが、GETの場合にはそのままの配列で渡すことに注意してください。

use HTTP::Request::Common qw(GET);
my $url      = 'http://localhost/test.cgi';
my %formdata = ('user' => 'アリババ', 'password' => 'opensesami');
my $request  = GET($url, %formdata);

LWPでCookieを送受信できますか?

できます。

Cookieを使うのであれば、LWP::Simpleではなく、LWP::UserAgentかLWP::RobotUAを使う必要があります。 使い方は簡単で、HTTP::Cookiesモジュールのオブジェクト(Cookieを保管するので、cookie_jarと呼ばれているようです)を生成しておいて、LWP::UserAgentまたはLWP::RobotUAのオブジェクトにこれを渡してやるだけです。

まず、cookie_jarを生成します。 cookie_jarの生成のポイントは、cookieを保存するためのファイル名を指定すること、それからcookieが自動的に保存されるようにするためにautosaveを指定することです。 その後、いつも通りLWP::UserAgentまたはLWP::RobotUAのオブジェクトを生成し、これのcookie_jarとして上で生成したものを指定します。

use HTTP::Cookies;
use LWP::UserAgent;

# cookie_jarの生成
my $cookie_jar = HTTP::Cookies->new(file => $cookie_file, autosave => 1);

# UserAgentの生成と、cookie_jarのセット
my $ua = LWP::UserAgent->new;
$ua->cookie_jar($cookie_jar);

# cookie_jarを使用してアクセス
my $request = HTTP::Request->new(GET => 'http://localhost/test.cgi');
my $res = &process_request($ua, $request);
print $res->as_string;

cookie_jarが指定されると、以降はこのUserAgentでのURLへのアクセスでは、自動的にcookie_jarのファイル内のCookieのうち適切なものが(あれば)送信されます。 また、新しくCookieを受信すると、このファイルに書き加えていきます。

なお、デフォルトでは保持期限(expire)が指定されていないCookieは保持されないようです。 最近ではCookieをセッション情報保持などのために使用することが増えています(「必ずCookieを有効にしてください」と書かれているようなサイトはそうです)が、こうしたサイトでは保持期限のないCookieを保持しないと先の処理ができないことがほとんどです。この時は、下のようにcookie_jarを生成する時に、ignore_discardを指定すれば良いようです。

my $cookie_jar = HTTP::Cookies->new(file => $cookie_file, autosave => 1, ignore_discard => 1);

■ サーバーからはCookieが送られてきているのに受け取れないのですが。

古いHTTP::Cookiesモジュールでは、ドメイン名に2つ以上のピリオドがないとエラーと見なしていました。 このため、「mixi.jp」や「gree.jp」など、ドメイン名にピリオドが1つしかないサイトのCookieを保持できませんでした。 このケースであれば、まずHTTP::Cookiesモジュールを新しいものに入れ替えてみてください。

このケースを私はHTTP::Cookiesの1.14版で経験しました。 どの版までがこれに該当するか分かりませんが、自分で調べたいと思った時にはset_cookieメソッドの$domainに対するチェック部分を確認してみてください。

LWPではリダイレクト先を取得することができますか?

できます。

何もしなくても、最初のアクセスにGETおよびHEADメソッドを使っている時は、リダイレクト先を自動的に取得しに行きます。

POSTメソッドの場合でもこれを行うには、正攻法であればrequest処理時に返されるHTTP::Responseオブジェクトの内容を調べます。 リダイレクトが指定されていると、HTTP::Responseオブジェクトのis_responseメソッドの返り値は1になります。 この時に、HTTP::Responseオブジェクトのheaderメソッドで'Location'に対応する値(リダイレクト先のURLです)を取得し、このURLをGET(リダイレクトはGETで行うのが標準です)すれば良いのです。 次のようなサブルーチンを使えば、リダイレクト先の取得を済ませてからHTTP::Responseオブジェクトを返させることができます。

sub process_request {
  my ($ua, $request) = @_;
  my $res = $ua->request($request);
  while ($res->is_redirect) {
    my $url = $res->header('Location');
    $res = $ua->request(HTTP::Request->new(GET => $url));
  }
  return $res;
}

process_requestサブルーチンは次のように、$ua->requestメソッドの代わりに使います。

my $res = &process_request($ua, $request);

もう一つの正攻法は、LWP::UserAgentまたはLWP::RobotAgentのサブクラスを作り、メソッドを調べてリダイレクトの可否を返しているredirect_okメソッドを、POSTでも可(1)を返すようにオーバーライトすることです。 これは、Perlのモジュールの作り方の知識を必要とするでしょう。

正攻法にこだわらなければ、もっと簡単な方法があります。 デフォルトのredirect_okメソッドは、ユーザーエージェントオブジェクトの持つ'requests_redirectable'という配列リファレンスをチェックしています。 ここに直接、'POST'を追加してしまうと、POSTメソッドでもリダイレクトを自動的に処理してくれるようになります。

my $ua = LWP::UserAgent->new;
push(@{ $ua->{'requests_redirectable'} }, 'POST');

あとは通常通り、$ua->requestメソッドを使えば、POSTであってもリダイレクトを処理してくれます。

LWPを使う時に、HTTP::*モジュールをuseする必要がありますか?

LWPモジュールをuseするだけで、多くのHTTP::*モジュールが読み込まれますので、明示的にuseやrequireなどしなくても済みます。例えば、LWP::UserAgentを読み込むと、次のようなモジュールも読み込まれます。

  • HTTP::Date、HTTP::Headers、HTTP::Message、HTTP::Request、HTTP::Response、HTTP::Status
  • LWP、LWP::Debug、LWP::MemberMixin、LWP::Protocol、LWP::UserAgent
  • Time::Local、URI、URI::Escape

次のような簡単なスクリプトで、どんなモジュールが読み込まれるかを確認できます。

use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
END {
  foreach (sort (keys(%INC))) {
    print "$_ => $INC{$_}\n";
  }
}

LWPはどこから手をつければ良いでしょうか?

あなたがやりたいことが、単に特定URLのHTMLデータを取得するだけであれば、LWP::Simpleを使えば良いでしょう。 LWP::Simpleのドキュメント(または川合さんによる和訳)を開き、次のようなことを確認してください。

  • 「SYNOPSYS」にある使用例を眺めてください。
  • 「DESCRIPTION」にある関数を眺めてみてください。次のようなことができるのです。
    • get ... 取得したHTMLなどのデータを返す。
    • getprint ... 取得したデータはそのまま標準出力に表示される。
    • getstore ... 取得したデータはファイルに保管される。

これでまずは使ってみて下さい。

もしProxyの設定やデータを受け取った部分から順次処理するなど、処理を細かく制御したくなったら、LWP::UserAgent川合さんによる和訳)を調べてください。 LWP::UserAgentについて調べ始めると、HTTP系モジュールなどについても調べることになります。 しかし、理解することができれば非常に良いエージェントを作成できるようになるでしょう。

また、LWP::UserAgentにRobot Exclusionへの対応を加えたものがLWP::RobotUAです。 LWP::UserAgentとほぼ使い方は同じなので、LWP::UserAgentを使うことができれば戸惑わないでしょう。

あるURLへのアクセスや投稿だけではなく、あるページを取得し、HTMLを解析し、その中のフォームへの投稿を行って、結果を確認したい、といった一連の作業をしたくなったら、LWPモジュールに解析のためのHTML::Parserモジュールなどを組み合わせて、かなりテクニカルなことをする必要があります。もしここまできたのであれば、実際にこれらを組み合わせたグッド・ラッパーであるPerlモジュール/WWW::Mechanizeを見てみるのが近道かも知れません。

LWPに関する日本語の情報源は?

LWP Cook BookをはじめとするLWPモジュールのドキュメントの和訳が、河馬屋二千年堂に掲載されています。 また、O'Reilly Japanから刊行されている「WebクライアントプログラミングWithPerl」はLWPを使ったプログラミング、使わないプログラミングのいずれにも役立つな良書です。

設定できるプロパティやサーバーが返したコードの意味など、HTTPプロトコルそのものについて調べる必要もでてくるでしょう。 Web上ではStudying HTTPが参考になります。 書籍では、技術評論社の近刊に「インターネットプロトコルがわかる」をお勧めします。

このページに関するご意見、ご質問

[[#comment]]