分类:
2007-04-12 17:13:25
要对 LWP 做全面的介绍需要一整本书,很幸运,Perl & LWP 已经出版。而这篇文章向你介绍了最常见的 LWP 用法。
通过调用 get($url) 函数,就可以得到相关网址的内容。如果没有发生错误,get 函数返回此网页,否则,返回 undef。例子如下:
my $url = 'http://freshair.npr.org/dayFA.cfm?todayDate=current'如果要在命令行里运行,getprint 函数非常方便。如果没有发生错误,它会把网页内容输出到 STDOUT,否则将会有错误信息输出到 STDERR。 例如:
use LWP::Simple;
my $content = get $url;
die "Couldn't get $url" unless defined $content;
# $content 里是网页内容,下面是对此内容作些分析:
if($content =~ m/jazz/i) {
print "They're talking about jazz today on Fresh Air!\n";
} else {
print "Fresh Air is apparently jazzless today.\n";
}
% perl -MLWP::Simple -e "getprint ''"上面的网址指向一个文本文件,列有最近两个星期内 CPAN 更新过的文件。如果想要知道 Acme:: 的模块是否有更新,有就email 自己,你可以把它和 Shell 结合到一起来实现。如下:
% perl -MLWP::Simple -e "getprint ''" \LWP::Simple 还有一些非常有用的函数,包括一个运行HEAD请求的函数,用来检查链接是否有效,网页是否更新。另外两个用来保存和镜像网址的函数也值得一提。具体请看 LWP::Simple 的文档或 Perl & LWP 的第二章.
| grep "/by-module/Acme" | mail -s "New Acme modules! Joy!" $USER
在众多的 LWP Class 里,LWP::UserAgent 和 HTTP::Response 是必须理解的。LWP::UserAgent 就像一个虚拟浏览器用来作 request (请求)。HTTP::Response 用来储存 request (请求) 生成的 response(响应)。
最基本的用法是 $response = $browser->get($url), 或写的更完整些 :
# 程序开始:上面有两个相关的 object: $browser,是 LWP::UserAgent 的一个object。$response 是属于 HTTP::Response 类的一个object。一个程序里只需要一个 $browser object,但是每次发出一个 request,就会得到一个新的 HTTP::Response object。
use LWP 5.64; # 载入较新版本的 LWP classes
my $browser = LWP::UserAgent->new;
...
# get request:
my $url = 'http://freshair.npr.org/dayFA.cfm?todayDate=current';
my $response = $browser->get( $url );
die "Can't get $url -- ", $response->status_line
unless $response->is_success;
die "Hey, 我想要 HTML 格式而不是 ", $response->content_type
unless $response->content_type eq 'text/html';
# 或者任何其他的 content-type
# 成功的话就对内容处理
if($response->content =~ m/jazz/i) {
print "Fresh Air 今天在讨论爵士乐!\n";
} else {
print "Fresh Air 今天讨论的和爵士乐一点边都不沾.\n";
}
HTTP::Response object 有以下一些有价值的属性:
$response = $browser->get( $url, $key1, $value1, $key2, $value2, ... );举个例子,如果你要对一个只允许 Netscape 浏览器连入的网站发出请求,那就需要发出类似 Netscape 的 header,如下:
my @ns_headers = (如果不打算重复使用这个 array,你可以把它写到 get 函数里
'User-Agent' => 'Mozilla/4.76 [en] (Win98; U)',
'Accept' => 'image/gif, image/x-xbitmap, image/jpeg,
image/pjpeg, image/png, */*',
'Accept-Charset' => 'iso-8859-1,*,utf-8',
'Accept-Language' => 'en-US',
);
...
$response = $browser->get($url, @ns_headers);
$response = $browser->get($url,如果只是打算修改 User-Agent,可以通过 LWP::UserAgent 的 agent 方法把缺省的agent ‘libwww-perl/5.65’(或者别的)改掉。
'User-Agent' => 'Mozilla/4.76 [en] (Win98; U)',
'Accept' => 'image/gif, image/x-xbitmap, image/jpeg,
image/pjpeg, image/png, */*',
'Accept-Charset' => 'iso-8859-1,*,utf-8',
'Accept-Language' => 'en-US',
);
$browser->agent('Mozilla/4.76 [en] (Win98; U)');
内存式的 cookie 使用方法:
$browser->cookie_jar({});也可以把 cookie 储存到硬盘的文件里:
use HTTP::Cookies;文件里的 cookie 是以 LWP 自定的格式储存,如果你想在 netscape 里使用这个 cookie 文件,可以使用 HTTP::Cookies::Netscape class :
$browser->cookie_jar( HTTP::Cookies->new(
'file' => '/some/where/cookies.lwp',
# 储存 cookies 的地址
'autosave' => 1,
# 当完成后自动储存到硬盘里
));
use HTTP::Cookies;你也可以象上面一样使用 ‘autosave’ => 1 。 但 Netscape 的 cookie 有时会在写入硬盘之前就被丢掉,至少在写这篇文章的时候还是这样。
# yes, loads HTTP::Cookies::Netscape too
$browser->cookie_jar( HTTP::Cookies::Netscape->new(
'file' => 'c:/Program Files/Netscape/Users/DIR-NAME-HERE/cookies.txt',
# where to read cookies
));
$response = $browser->post( $url,或者你也可以把 HTTP header 也一起发出
[
formkey1 => value1,
formkey2 => value2,
...
],
);
$response = $browser->post( $url,下一个例子向 AltaVista 的搜索引擎发送 HTTP POST 请求,然后从HTML里提取出符合匹配的总数。
[
formkey1 => value1,
formkey2 => value2,
...
],
headerkey1 => value1,
headerkey2 => value2,
);
use strict;
use warnings;
use LWP 5.64;
my $browser = LWP::UserAgent->new;
my $word = 'tarragon';
my $url = '';
my $response = $browser->post( $url,
[ 'q' => $word, # the Altavista query string
'pg' => 'q', 'avkw' => 'tgz', 'kl' => 'XX',
]
);
die "$url error: ", $response->status_line
unless $response->is_success;
die "Weird content type at $url -- ", $response->content_type
unless $response->content_type eq 'text/html';
if( $response->content =~ m{AltaVista found ([0-9,]+) results} ) {
# 从 "AltaVista found 2,345 results" 里匹配出结果
print "$word: $1\n";
} else {
print "Couldn't find the match-string in the response\n";
}
%20Runner&restrict=Movies+and+TV下面是使用 LWP 实现同样的结果 :
use URI;第5章详细描述了 HTML 表格和表格数据,第6章到第9章描述了怎样从获得的HTML数据里提取出有用的信息。
my $url = URI->new( '' );
# makes an object representing the URL
$url->query_form( # And here the form data pairs:
'title' => 'Blade Runner',
'restrict' => 'Movies and TV',
);
my $response = $browser->get($url);
use URI;现在回忆一下获取最新 CPAN 模块的那个例子。
$abs = URI->new_abs($maybe_relative, $base);
use strict;输出的结果是
use warnings;
use LWP 5.64;
my $browser = LWP::UserAgent->new;
my $url = '';
my $response = $browser->get($url);
die "Can't get $url -- ", $response->status_line
unless $response->is_success;
my $html = $response->content;
while( $html =~ m/chunk86920392chunklt;A HREF=\"(.*?)\"/g ) {
print "$1\n";
}
MIRRORING.FROM你可以使用 URI 模块的 new_abs 方法来得到完全网址路径,修改 while 循环:
RECENT
RECENT.html
authors/00whois.html
authors/01mailrc.txt.gz
authors/id/A/AA/AASSAD/CHECKSUMS
...
while( $html =~ m/ print URI->new_abs( $1, $response->base ) ,"\n";$response->base 方法可以在 HTTP::Message 里找到。它返回的 URL 通常被用来和相对路径合并来得到完全路径。现在得到的结果是
}
请参考 Perl & LWP 的第四章,以得到对 URI objects 更详细的描述。
...
当然,使用 regexp (正则表达式) 来匹配 url 相对简单,如果情况复杂,需要更强大的匹配工具,可以考虑 HTML 分析模块 HTML::LinkExtor 或 HTML::TokeParser,甚至 HTML::TreeBuilder
$browser->agent( ‘SomeName/3.14 (contact@robotplexus.int)’ );或者可以伪装为
$browser->agent( ‘Mozilla/4.0 (compatible; MSIE 5.12; Mac_PowerPC)’ );
LWP::RobotUA 用法与 LWP::UserAgent 一样:
use LWP::RobotUA;HTTP::RobotUA 多了几个特性:
my $browser = LWP::RobotUA->new(
'YourSuperBot/1.34', 'you@yoursite.com');
# 机器人名字和 email 地址
my $response = $browser->get($url);
die "$url -- ", $response->status_line, "\nAborted"然后你会得到这样的错误信息:
unless $response->is_success;
-- 403 Forbidden
by robots.txt
Aborted at whateverprogram.pl line 1234
$browser->delay( 7/60 );
代理通常储存在环境变量 HTTP_PROXY 里。LWP 可以通过 user-agent object 里的 env_proxy 函数把环境变量里的代理地址装载。
use LWP::UserAgent;详细请参照 LWP::UserAgent 文档里的 proxy, env_proxy 和 no_proxy 方法.
my $browser = LWP::UserAgent->new;
# And before you go making any requests:
$browser->env_proxy;
Unicode.org 的管理员为了防止机器人访问邮件组获取发信人地址,要求先进行 HTTP 认证。用户名和密码是公开的:用户名: unicode-ml 密码: unicode
假设一个限制页面的地址是
如果你在浏览器里请求这个地址,一个新的窗口跳出,显示 “Enter username and password for ‘Unicode-MailList-Archives’ at server ‘’”。请你输入用户名和密码,就像这样:
单纯使用 LWP 请求这个网址 :
use LWP 5.64;你将得到以下错误:
my $browser = LWP::UserAgent->new;
my $url =
'';
my $response = $browser->get($url);
die "Error: ", $response->header('WWW-Authenticate') ||
'Error accessing',
# ('WWW-Authenticate' is the realm-name)
"\n ", $response->status_line, "\n at $url\n Aborting"
unless $response->is_success;
Error: Basic realm="Unicode-MailList-Archives"这是因为 LWP 不知道 host 里的 “Unicode-MailList-Archives” 区的用户名和地址。解决这个问题最简单的方法是使用 credentials 方法来提供用户名和密码:
401 Authorization Required
at
Aborting at auth1.pl line 9. [or wherever]
$browser->credentials(通常, 端口是 80. credentials 函数要在发请求之前调用.比如:
'servername:portnumber',
'realm-name',
'username' => 'password'
);
$browser->credentials(我们的 unicode.org 的例子可以写成
'reports.mybazouki.com:80',
'web_server_usage_reports',
'plinky' => 'banjo123'
);
$browser->credentials( # add this to our $browser 's "key ring"
':80',
'Unicode-MailList-Archives',
'unicode-ml' => 'unicode'
);
use LWP 5.64;如果没有 HTTPs 的支持, 如下错误信息会显示
my $url = ''; # Yes, HTTPS!
my $browser = LWP::UserAgent->new;
my $response = $browser->get($url);
die "Error at $url\n ", $response->status_line, "\n Aborting"
unless $response->is_success;
print "Whee, it worked! I got that ",
$response->content_type, " document!\n";
Error at如果你安装了 LWP 的 HTTPS 支持的话,你的请求应该是成功的,你可以像对待普通的 HTTP 请求一样处理 $response 对象。
501 Protocol scheme 'https' is not supported
Aborting at paypal.pl line 7. [or whatever program and line]
关于安装 HTTPS 支持的信息可以在libwww-perl 里的README.SSL 文件找到.
一个解决方法是把文件存到硬盘
$response = $ua->get($url,比如:
':content_file' => $filespec,
);
$response = $ua->get('',当使用 content_file 时, headers 还是在$response, 但$response->content 是空.
':content_file' => '/tmp/sco.html'
);
值得注意的是LWP 5.66 之前的版本不支持content_file . 你应该使用 use LWP 5.66; 如果你的程序可能运行在低版本的 LWP 上, 你也可以使用下面的例子来保证兼容性, 这与 content_file 有同样效果.
use HTTP::Request::Common;
$response = $ua->request( GET($url), $filespec );
use LWP::ConnCache;这告诉 browser object 使用 HTTP/1.1 “keep-Alive” 特性, 即重复使用先前的 socket 来加快请求速度.
$browser->conn_cache(LWP::ConnCache->new()):
你也可以在 new LWP::UserAgent 时为 $browser 加上 “keep-Alive” 特性, 如下
use LWP;
$browser = new LWP::UserAgent(keep_alive => 1);
use LWP;输出结果:
my $br = LWP::UserAgent->new;
my $resp = $br ->get('');
print $resp->headers_as_string";
Cache-Control: private, max-age=0你也可以通过 $response->header(‘field’) 来获得想要的特别 header. 象上面的例子, 如果要访问的网页使用了 meta refresh :
Connection: close
Date: Sun, 16 Jan 2005 04:18:26 GMT
Server: Microsoft-IIS/6.0
Content-Length: 432
Content-Type: text/html
Content-Type: text/html; charset=iso8859-1
Client-Date: Sun, 16 Jan 2005 04:18:09 GMT
Client-Peer: 207.61.136.40:80
Client-Response-Num: 1
REFRESH: 0;URL=/Front_Page/page.asp
X-Meta-Robots: noindex
X-Powered-By: ASP.NET
你可以使用 $response->header(‘refresh’) 来拿到 refresh 的 url 地址, 选择是否继续跟进.
function Submit()
{
.........
self.document.location.href="verify.php";
return false;
}
........