检查网页是否已经下载

Check if Web page was already downloaded

上下文

我写了一个 Java 爬虫,它会定期下载 Google 上列出的页面并包含一组关键字。这些页面要么是静态的(即,其内容不变),要么是动态的(即,其内容发生变化,因为它是 user-generated 或打算更新 daily/ecc...)。爬虫将每个页面存储在 MongoDB 数据库中,保存:

问题

但是,页面可能会被多次下载,我 objective 了解某个页面是否已经存在于我的数据库中并防止爬虫再次下载它。

我的解决方案

因此,我使用以下哈希函数对页面内容进行哈希处理:

private long hashFunction(String text) {
    long h = 1125899906842597L;
    int len = text.length();

    for (int i = 0; i < len; i++)
        h = 31*h + text.charAt(i);

    return h;
}

并将哈希值与前面列出的字段一起存储在数据库中。因此,每次下载一个页面时,我都会对它的内容进行哈希处理,如果哈希值已经包含在数据库中,我就会丢弃该页面。

为什么我的解决方案不起作用

遗憾的是,页面可能会发生一些变化,总的来说仍然提出相同的内容。例如:

因此,我的数据库中有很多重复项,它们报告相同的内容,只是在某些字符上有所不同。

问题

是否有任何更智能的方法来跟踪页面之间的差异,这样即使更改很小,我也能识别出该页面已经在数据库中?显然,该解决方案应该具有高性能,因为数据库可能会变得非常大,并且与大型文档执行精确匹配的成本可能很高。

[编辑] 一个暂定的解决方案(可能有意义...)

我考虑过:

它有意义吗?

如果您的问题是检查某个页面的特定版本是否已存在于您的数据库中以防止爬虫下载它,那么散列不是可行的方法,因为无论如何您都必须下载该页面才能生成哈希。

如果存储 Last-Modified http header value, you could use it in all subsequent requests using If-Modified-Since http header。 如果您按照这种方式进行操作,则必须存储

  • URL
  • 内容
  • Modified-Date

存储内容适合进一步处理,但我建议使用 html 抓取库来为您完成。看到这个问题options-for-html-scraping

此外,我认为最好不要太频繁地下载数据(这可能取决于您 problem-domain),但您可以简单地假设此页面在过去 20 分钟内没有更改或所以。如果页面更改非常频繁,那么您无论如何都会落后于最新版本。