2012-04-18 164 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