ZetCode

Perl LWP 编程

最后修改于 2023 年 8 月 24 日

在本文中,我们将展示如何使用 Perl LWP 模块进行 WWW 编程。

LWP 是一组 Perl 模块,它为万维网提供了一个简单一致的应用程序编程接口 (API)。该库的主要重点是提供类和函数来编写 WWW 客户端。LWP 是 Library for WWW in Perl 的缩写。

LWP::Simple

LWP::Simple 是 LWP 的一个简单的过程式接口。它包含一些函数,可以方便地处理网页。LWP::Simple 模块对于简单情况很有用,但它不支持更高级的功能,如 cookie 或授权。

get 函数

get 函数获取由给定 URL 标识的文档并返回它。如果失败,则返回 undef$url 参数可以是字符串或 URI 对象的引用。

simple_get.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::Simple;

my $cont = get('http://webcode.me') or die 'Unable to get page';

say $cont;

该脚本抓取 http://webcode.me 网页的内容。

$ ./simple_get.pl
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My html page</title>
</head>
<body>

    <p>
        Today is a beautiful day. We go swimming and fishing.
    </p>

    <p>
         Hello there. How are you?
    </p>

</body>
</html>

这是 simple_get.pl 脚本的输出。

以下程序获取一个小型网页并去除其 HTML 标签。

strip_tags.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::Simple;
 
my $cont = get('http://webcode.me');

foreach ($cont) {
    s/<[^>]*>//g;
    print;
}

该脚本剥离 http://webcode.me 网页的 HTML 标签。

head 函数

head 函数检索文档头。成功时,它返回以下五个值:内容类型、文档长度、修改时间、过期时间和服务器。如果失败,它返回一个空列表。

head_fun.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::Simple;

my ($content_type, $doc_length, 
    $mod_time, $expires, $server) = head("http://webcode.me");

say "Content type: $content_type";
say "Document length: $doc_length";
say "Modification time: $mod_time";
say "Server: $server";

该示例打印 http://webcode.me 网页的内容类型、文档长度、修改时间和服务器。

$ ./simple_head.pl
Content type: text/html
Document length: 348
Modification time: 1563623365
Server: nginx/1.6.2

getstore 函数

getstore 函数检索由 URL 标识的文档并将其存储在文件中。返回值是 HTTP 响应代码。

get_store.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::Simple;

my $r = getstore('http://webcode.me', 'webcode.html') 
    or die 'Unable to get page';

say "Response code: $r"; 

该脚本抓取 http://webcode.me 网页的内容并将其存储在 webcode.html 文件中。

$ ./get_store.pl
Response code: 200
$ cat webcode.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My html page</title>
</head>
<body>

    <p>
        Today is a beautiful day. We go swimming and fishing.
    </p>

    <p>
         Hello there. How are you?
    </p>

</body>
</html>

可以使用 is_success 函数检查返回代码。

check_return_code.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::Simple;

my $url = 'http://webcode.mee';

my $r = getstore($url, 'webcode.html') 
    or die 'Unable to get page';
    
die "Error $r on $url" unless is_success($r); 

在示例中,我们故意拼错了网页 URL。

$ ./check_return_code.pl
Error 500 on http://webcode.mee at ./check_return_code.pl line 11.

LWP 类模型

LWP 类模型包含用于更复杂地处理万维网的类。

LWP::UserAgent 是一个实现 Web 用户代理的类。在应用程序中,我们创建并配置一个 LWP::UserAgent 对象。然后,我们创建一个 HTTP::Request 实例来执行所需的请求。然后,此请求被传递给用户代理的请求方法之一,该方法使用相关协议进行调度,并返回一个 HTTP::Response 对象。有用于发送最常见请求类型的便利方法:getheadpostputdelete

用户代理

LWP::UserAgent 是一个 Web 用户代理类。

$ cpanm Mojolicious::Lite

我们安装 Mojolicious 框架。

server.php
#!/usr/bin/perl

use Mojolicious::Lite -signatures;

get '/' => sub ($c) {

    my $ua = $c->req->headers->user_agent;

    $c->render(text => $ua);
};

app->start;

服务器处理客户端请求,确定用户代理,并将用户代理返回给客户端。

$ perl server.pl daemon
[2021-07-08 13:02:55.63239] [49095] [info] Listening at "http://*:3000"
Web application available at http://127.0.0.1:3000

我们启动服务器;它监听端口 3000。

agent.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::UserAgent;

my $ua = new LWP::UserAgent;
$ua->agent('Perl script');

my $req = new HTTP::Request 'GET' => 'https://:3000';
my $res = $ua->request($req);

if ($res->is_success) {

    say $res->content;
} else {

    say $res->status_line;
}

此脚本向 localhost 发送一个简单的 GET 请求。

my $ua = new LWP::UserAgent;

创建了 LWP::UserAgent 的实例。

$ua->agent("Perl script");

使用 agent 方法,我们设置代理的名称。

my $req = new HTTP::Request 'GET' => 'https://:3000';

创建了一个到 localhost 的 GET 请求。

my $res = $ua->request($req);

request 方法调度请求对象。返回值是一个响应对象。

if ($res->is_success) {

    say $res->content;
} else {

    say $res->status_line;
}

is_success 方法检查响应是否具有成功的返回代码。content 方法返回原始内容。status_line 返回状态代码和响应消息。

$ ./agent.pl
Perl script

服务器响应了我们随请求发送的代理名称。

get 方法

用户代理的 get 方法是一个执行 HTTP 请求的便捷方法。它节省了一些输入。

get_page.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::UserAgent;
      
my $ua = new LWP::UserAgent;
$ua->agent("Perl script");

my $res = $ua->get('http://webcode.me');

if ($res->is_success) {

    say $res->content;
} else {

    say $res->status_line;
}

该脚本获取 webcode.me 页面的内容。我们使用了便捷的 get 方法。

在下面的示例中,我们在 urbandictionary.com 上查找一个术语的定义。

get_definition.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::UserAgent;
use HTML::TreeBuilder;

my $word = shift || 'dog';

my %parameters = (term => $word);
my $url = URI->new('https://www.urbandictionary.com/define.php');
$url->query_form(%parameters);

my $ua = LWP::UserAgent->new;
my $res = $ua->get($url);

my $tree = HTML::TreeBuilder->new_from_content($res->decoded_content);
my @meanings = $tree->look_down(_tag => q{div}, 'class' => 'meaning');

foreach my $el (@meanings) {

    say $el->as_text;
}

die "Error: ", $res->status_line unless $res->is_success;

在此脚本中,我们在 urbandictionary.com 上查找术语 dog 的定义。我们显示来自第一页的定义。HTML::TreeBuilder 用于解析 HTML 代码。

发布一个值

post 方法在给定的 URL 上分派一个 POST 请求,为表单填写内容提供键/值对。

server2.pl
#!/usr/bin/perl

use Mojolicious::Lite -signatures;

post '/' => sub ($c) {

    my $name = $c->param('name');

    $c->render(text => "Hello $name!");
};

app->start;

在处理程序中,我们获取 name 参数。根据该参数,我们构建一个消息并将其发送给客户端。

post_value.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::UserAgent;

my $ua = LWP::UserAgent->new;

my $res = $ua->post('https://:3000/',
    ['name'  =>  'Jan']);

if ($res->is_success) {

    say $res->content;
} else {

    say $res->status_line;
}

该脚本发送一个带有 Jan 值的 name 键的请求。

$ ./post_value.pl
Hello Jan!

凭据

用户代理的 credentials 方法设置要用于某个域的名称和密码。安全域是用于保护 Web 应用程序资源的一种机制。

$ sudo apt-get install apache2-utils
$ sudo htpasswd -c /etc/nginx/.htpasswd user7
New password:
Re-type new password:
Adding password for user user7

我们使用 htpasswd 工具为基本 HTTP 身份验证创建一个用户名和密码。

location /secure {

    auth_basic "Restricted Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

在 nginx 的 /etc/nginx/sites-available/default 配置文件中,我们创建一个受保护的页面。该领域的名称是“Restricted Area”。

index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Secure page</title>
</head>

<body>

<p>
This is a secure page.
</p>

</body>

</html>

/usr/share/nginx/html/secure 目录中,我们有这个 HTML 文件。

credentials.pl
#!/usr/bin/perl

use 5.30.0;
use warnings;
use LWP::UserAgent;

my $ua = new LWP::UserAgent;
$ua->agent("Perl script");

$ua->credentials('localhost:80', 'Restricted Area', 'user7' => 's$cret');

my $res = $ua->get('https:///secure/');

if ($res->is_success) {

    say $res->content;
} else {

    say $res->status_line;
}

该脚本连接到受保护的网页;它提供访问该页面所需的用户名和密码。

$ ./credentials.pl
<!DOCTYPE html>
<html lang="en">
<head>
<title>Secure page</title>
</head>

<body>

<p>
This is a secure page.
</p>

</body>

</html>

使用正确的凭据,credentials.pl 脚本会返回安全页面。

在本文中,我们使用了 Perl LWP 模块。

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。至今,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有超过十年的经验。

列出 所有 Perl 教程