2012-04-18 165 views
3

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

+0

参见[HEAD](http://www.w3.org/Protocols/rfc261 6/rfc2616-sec9.html#sec9.4)请求。您可以查看最近修改的内容,内容长度等。 – Rob 2012-04-18 00:18:18

+0

您是否需要针对特定​​网站的通用解决方案或解决方案。我在问,因为最好的解决方案(CPU和网络使用效率更高)可能取决于服务器的功能。 – dolmen 2012-04-18 13:25:24

回答

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的,如果服务器提供一个用于请求的资源。您可以简单地存储它,然后设置您的请求标题以在后续请求中包含If-None-Match字段。如果服务器ETag保持不变,您将获得304 Not Modified状态和空的响应主体。否则,你会得到新的页面。 (和新的ETag。)请参阅RFC2616中的Entity Tags

当然,服务器可能在说谎,并发送即使内容已经改变了相同的ETag。除非你看,否则无法知道。

3

您应该使用If-Modified-Sincerequest header,注意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); 
     } 
    ); 

然而,LWP可以做这个最适合你用mirror如果你要保存的文件:

$ua->mirror($url, $filename) 
+0

请注意,服务器可能会忽略If-Modified-Since标头(非常常见于PHP生成的内容),因此这不是一种通用解决方案。 – dolmen 2012-04-18 13:22:39

+0

我注意到,当我写道“如果服务器支持它,并认为内容更新”:) – 2012-04-18 13:59:25

+0

从我的爬虫数据小于1/4支持它。现在我会消化所有页面来比较上面的答案。 – Frederico 2012-04-19 00:54:22