检查网页是否已下载

时间:2015-02-04 14:44:28

标签: java html performance mongodb hash

上下文

我编写了一个Java抓取工具,定期下载Google上列出的并包含一组关键字的网页。这些页面是静态的(即,其内容不改变)或动态的(即,其内容改变,因为它是用户生成的或意图每天更新/ ecc ...)。抓取工具将每个页面存储在MongoDB数据库中,保存:

  • 标题
  • URL
  • 内容(即整页的HTML内容)

问题

但是,页面可能会被多次下载,我的目标是了解我的数据库中是否已存在某个页面,并阻止抓取工具再次下载。

我的解决方案

因此,我使用以下散列函数散列页面的内容:

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;
}

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

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

不幸的是,页面可能会有所改变,仍然会提出相同的内容。举个例子:

    从Twitter下载的
  • 页面在每次请求时都会更改“身份验证令牌”

因此,我的数据库中有很多重复项,它报告相同的内容,并且在某些字符上有所区别。

问题

是否有更智能的方法来跟踪页面之间的差异,因此如果更改很少,我可以识别该页面已经存在于数据库中?显然,该解决方案应该具有高性能,因为数据库可能变得非常大并且与大型文档执行完全匹配可能很昂贵。

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

我想到了:

  • 仅从页面中提取正文
  • 删除标签(即表格中的所有内容&lt; ...&gt;)
  • 计算幸存此操作的文本部分的哈希值

它有意义吗?

1 个答案:

答案 0 :(得分:2)

如果您的问题是检查数据库中是否已存在特定版本的页面以防止抓取工具下载它,则无法进行散列,因为您无论如何都必须下载页面以生成散列

如果存储Last-Modified http header值,则可以在使用If-Modified-Since http标头的所有后续请求中使用它。 如果你按照这种方式,你将不得不存储

  • URL
  • 内容
  • 修改日期

存储内容对于进一步处理是好的,但是我会建议使用html scapping库来为你做。请参阅此问题options-for-html-scraping

另外我相信不经常下载数据会很好(可能这取决于你的问题域),但你可以简单地假设这个页面在最后20分钟左右没有变化。如果页面频繁更改,您仍会支持最新版本。