Python:优化算法,以避免在爬行时下载未更改的页面

时间:2011-09-30 03:38:16

标签: python http-headers etag web-crawler if-modified-since

我正在编写一个爬虫,定期检查新文章的新闻网站列表。 我已经阅读了有关避免不必要的页面下载的不同方法,基本上确定了5个标题元素,可用于确定页面是否已更改:

  1. HTTP状态
  2. ETAG
  3. Last_modified(与If-Modified-Since请求结合使用)
  4. 到期
  5. 内容长度。
  6. 优秀FeedParser.org似乎实施了其中一些方法。

    我正在寻找用于做出这种决定的Python(或任何类似语言)的最佳代码。 请记住,标题信息始终由服务器提供。

    这可能是这样的:

    def shouldDonwload(url,prev_etag,prev_lastmod,prev_expires, prev_content_length):
        #retrieve the headers, do the magic here and return the decision
        return decision
    

2 个答案:

答案 0 :(得分:2)

在提出请求之前,您唯一需要检查的是ExpiresIf-Modified-Since不是服务器发送给您的东西,而是您发送服务器的东西。

您要做的是HTTP GET,其中If-Modified-Since标头指示您上次检索资源的时间。如果您返回状态代码304而不是通常的200,则此后资源尚未修改,您应该使用存储的副本(不会发送新副本)。

此外,您应该保留上次检索文档时的Expires标题,如果您保存的文档副本尚未过期,则根本不会发出GET

将其转换为Python仍然是一个练习,但应该直接向请求添加If-Modified-Since标头,从响应中存储Expires标头,并检查状态代码来自回应。

答案 1 :(得分:1)

您需要将标题的dict传递给shouldDownload(或urlopen的结果):

def shouldDownload(url, headers, prev_etag, prev_lastmod, prev_expires,  prev_content_length):
    return (prev_content_length != headers.get("content-length") || prev_lastmod != headers.get("If-Modified-Since") || prev_expires != headers.get("Expires") || prev_etag != headers.get("ETAG"))
    # or the optimistic way:
    # return prev_content_length == headers.get("content-length") and prev_lastmod == headers.get("If-Modified-Since") and prev_expires = headers.get("Expires") and prev_etag = headers.get("ETAG")

打开网址时执行此操作:

# my urllib2 is a little fuzzy but I believe `urlopen()` doesn't 
#  read the whole file until `.read()` is called, and you can still 
#  get the headers with `.headers`.  Worst case is you may have to 
#  `read(50)` or so to get them.
s = urllib2.urlopen(MYURL)
try:
    if shouldDownload(s.headers):
        source = s.read()
        # do stuff with source
   else:
        continue
# except HTTPError, etc if you need to  
finally:
    s.close()