2

在我的应用程序中,我使用 LWP 定期获取网页。无论如何要检查网页是否在两次连续获取之间在某些方面发生了变化(除了明确地进行比较)?是否有任何在较低协议层生成的签名(例如 CRC)可以被提取并与旧签名进行比较以查看可能的变化?

4

2 回答 2

4

有两种可能的方法。一种是使用页面的摘要,例如

use strict;
use warnings;

use Digest::MD5 'md5_hex';
use LWP::UserAgent;

# fetch the page, etc.
my $digest = md5_hex $response->decoded_content;

if ( $digest ne $saved_digest ) { 
    # the page has changed.
}

如果服务器为请求的资源提供了一个 HTTP ETag,另一种选择是使用 HTTP ETag 。您可以简单地存储它,然后将您的请求标头设置为If-None-Match在后续请求中包含一个字段。如果服务器 ETag 保持不变,您将获得一个304 Not Modified状态和一个空的响应正文。否则,您将获得新页面。(以及新的 ETag。)请参阅RFC2616 中的实体标签

当然,服务器可能在撒谎,即使内容发生了变化,也会发送相同的 ETag。除非你看,否则没有办法知道。

于 2012-04-18T05:28:01.737 回答
3

您应该使用If-Modified-Since 请求标头,注意 RFC 中的问题。您将此标头与请求一起发送。如果服务器支持它并认为内容较新,则会将其发送给您。如果它认为您拥有最新版本,它会返回304没有消息正文的消息。

但是,正如其他答案所指出的那样,服务器不必告诉您真相,因此您有时会卡住下载内容并自行检查。许多动态事物总是声称拥有新内容,因为许多开发人员从未想过在他们的 Web 应用程序中支持基本的 HTTP 事物。

对于 LWP 位,您可以创建带有额外标头的单个请求:

use HTTP::Request;
use LWP::UserAgent;

my $ua = LWP::UserAgent->new;
my $request = HTTP::Request->new( GET => $url );
$r->header( 'If-Modified-Since' => $time );

$ua->request( $request );

对于所有请求,您可以设置请求处理程序:

$ua->add_handler(
    request_send => sub { 
        my($request, $ua, $h) = @_; 
        # ... look up time from local store
        $r->header( 'If-Modified-Since' => $time );
        }
    );

mirror但是,如果您想保存文件,LWP 可以为您完成大部分工作:

$ua->mirror( $url, $filename )
于 2012-04-18T09:24:35.143 回答