我正在构建一个网络爬虫,我已经实现了解析部分。现在我想将获得的 URI 存储到一个高效的数据结构中。我应该用什么??我正在使用 Jena 库进行解析。
5 回答
我会将要处理的 URI 队列和已处理的 URI 存储在 Redis (http://redis.io/) 中。Redis 是一个非常快速的半持久键值存储,原生支持各种数据结构,包括列表(URI 队列)和哈希(映射)。这样,这些数据结构将在您的 Java 应用程序重新启动后继续存在。您还可以运行您的应用程序的多个实例,而无需通过 Redis 进行通信。
通常在网络爬虫应用程序中 - 您需要管理 url 以丢弃蜘蛛陷阱(有时称为“黑洞”),丢弃对同一页面的频繁访问,您还将使用 url 作为页面内容的全局标识符。
但另一个有趣的时刻 -放弃两次访问相同的 url 是错误的(因为网页的内容可能会及时改变)。
所以满足这些要求的最好方法是使用某种优先级队列并将每个 url 与元组相关联:{url, hash(url) }。当您获得新的 url 时 - 只需计算其哈希值,并且如果您的数据库记录具有相同的哈希值 - 只需将此 url 设置为低优先级并将其放入优先级队列中。
网络爬虫向优先队列询问要访问的 url。因此,只会首先访问具有最高优先级的 url 的页面。
您可以构建自己的散列函数,以最好的方式满足您的需求(例如 - 从 url 字符串中删除参数并从字符串的其余部分计算散列)。
哈希。
例如:URL:schem://domain:port/path?query_string#fragment_id。
将 URL 解析为字符串后,将 url 存储为:
哈希 ['方案'] = 方案;
哈希 ['域'] = 域;
哈希 ['端口'] = 端口;
哈希 ['路径'] = 路径;
哈希['query_string'] = query_string;
哈希['fragment_id'] = fragment_id;
爬虫通常使用 aQueue
来保存要检查的 URI,并Set
在将 URI 插入上述队列并在检查后将 URI 放入集合之前检查重复项。
如果您的链接数量可以容纳在内存中,那么您可以将 aLinkedList
作为队列,将 aHashSet
作为集合。否则,您可以将外部数据库用于这两个目的,或者将队列服务器(如 ActiveMQ)用作队列,将数据库用作集合。
我猜你想自动丢弃重复项,所以没有 URI 被抓取两次?然后我会建议一个HashSet。
它会自动丢弃重复项,并且在最佳情况下插入复杂度仍然是恒定的。请注意,当您使用自己的类而不是默认类java.net.URI来表示 URI 时,您必须重写int hashCode()
URI 类的方法以返回 URI 字符串的基于文本的哈希值。Object 的默认方法为每个对象创建一个唯一的哈希码,即使内容相同也是如此。