因为项目需要,做了一个网络爬虫的小DEMO。
为实现高性能的网络爬虫,首先考虑采用APACE的HttpClient进行页面的采集和解析,HttpClient可以很方便的通过URL获得远程内容,例如一个小程序:
还可以做页面解析和模拟登陆等,功能相当强大。
其次,如果是网络爬虫或者网络采集,可能需要做大量的URL地址收集和分析,所以需要通过NoSQL数据库来提高执行的效率,Redis、Memcache、BerkeleyDB都是不错的选择。这里选择了BerkeleyDB数据库。虽然采用传统队列或其他形式可能性能会更高,但会带来大量的内存消耗,并不一定能找到符合条件的大内存服务器。
然后,对URL地址需要进行过滤,判断是否是已读的URL地址,如果已读就存入已读数据库,如果未读则放入未读数据库,有点类似队列的形式,以此避免重复读取URL地址。当然更进一步的需要判断页面内容是否重复,降低读取重复页面的概率。
再然后,对页面进行解析,提取关键内容和URL地址。
最后,为了保证性能,采用多线程的实现方式,在多服务器的模式下还可以采用分布式算法来实现更高的性能。
按照上面的思路,写了一个小程序:
1、部分配置信息,以CrawlConfig来做配置,也可以把这些存储为xml文件,这里采集的是163网站
(1)CrawlConfig.java
(2) CrawlUrl.java作为URL地址的对象,当然除了URL属性外还可以存储其他信息
(3)LinkFilter.java ,作为URL地址的过滤器
2、编写访问BerkelyDB的代码(请先安装BerkeleyDB,并引入BerkeleyDB的Je包
(1)AbstractFrontier.java
(2)Frontier.java
(3)考虑到并发的BDBFrontier.java
3、核心部分:包括了URL获取、页面解析、页面下载,页面的解析和下载会比较消耗时间。
(1)RetievePage.java,实现了URL访问和页面的下载
(2)HtmlParserTool.java,实现页面的解析,提取URL地址
(3)MyCrawler.java实现页面的采集,这里采用了宽度优先的采集规则,当然更复杂的考虑这里还要设置深度,这里主要采用域名前缀作为过滤条件。另外多线程环境下,需要考虑数据的同步问题。
(4)以Runnable接口形式实现d额多线程
执行结果:
采集开始
……
采集结束
程序运行时间: 25777ms
最后对采集性能进行分析,先后采用LinkQueue队列单线程、BerkeleyDB单线程、BerkeleyDB多线程方案进行网络采集,测试数据对比如下:
综上,多线程可以带来明显的性能提升。