在我们调试爬虫程序的时候,单线程爬虫没什么问题,但是当我们在线上环境使用单线程爬虫程序去采集网页时,单线程就暴露出了两个致命的问题:
采集效率特别慢,单线程之间都是串行的,下一个执行动作需要等上一个执行完才能执行
对服务器的CUP等利用率不高,想想我们的服务器都是8核16G,32G的只跑一个线程会不会太浪费啦
线上环境不可能像我们本地测试一样,不在乎采集效率,只要能正确提取结果就行。在这个时间就是金钱的年代,不可能给你时间去慢慢的采集,所以单线程爬虫程序是行不通的,我们需要将单线程改成多线程的模式,来提升采集效率和提高计算机利用率。
多线程的爬虫程序设计比单线程就要复杂很多,但是与其他业务在高并发下要保证数据安全又不同,多线程爬虫在数据安全上到要求不是那么的高,因为每个页面都可以被看作是一个独立体。要做好多线程爬虫就必须做好两点:第一点就是统一的待采集URL维护,第二点就是URL的去重,下面我们简单的来聊一聊这两点。
维护待采集的URL
多线程爬虫程序就不能像单线程那样,每个线程独自维护这自己的待采集URL,如果这样的话,那么每个线程采集的网页将是一样的,你这就不是多线程采集啦,你这是将一个页面采集的多次。基于这个原因我们就需要将待采集的URL统一维护,每个线程从统一URL维护处领取采集URL,完成采集任务,如果在页面上发现新的URL链接则添加到统一URL维护的容器中。下面是几种适合用作统一URL维护的容器:
JDK的安全队列,例如linkedBlockingQueue
高性能的NoSQL,比如Redis、Mongodb
MQ消息中间件
URL的去重
URL的去重也是多线程采集的关键一步,因为如果不去重的话,那么我们将采集到大量重复的URL,这样并没有提升我们的采集效率,比如一个分页的新闻列表,我们在采集第一页的时候可以得到2、3、4、5页的链接,在采集第二页的时候又会得到1、3、4、5页的链接,待采集的URL队列中将存在大量的列表页链接,这样就会重复采集甚至进入到一个死循环当中,所以就需要URL去重。URL去重的方法就非常多啦,下面是几种常用的URL去重方式:
将URL保存到数据库进行去重,比如redis、MongoDB
将URL放到哈希表中去重,例如hashset
将URL经过MD5之后保存到哈希表中去重,相比于上面一种,能够节约空间
使用布隆过滤器(BloomFilter)去重,这种方式能够节约大量的空间,就是不那么准确。
关于多线程爬虫的两个核心知识点我们都知道啦,下面我画了一个简单的多线程爬虫架构图,如下图所示:
上面我们主要了解了多线程爬虫的架构设计,接下来我们不妨来试试Java多线程爬虫,我们以采集虎扑新闻为例来实战一下Java多线程爬虫,Java多线程爬虫中设计到了待采集URL的维护和URL去重,由于我们这里只是演示,所以我们就使用JDK内置的容器来完成,我们使用linkedBlockingQueue作为待采集URL维护容器,HashSet作为URL去重容器。下面是Java多线程爬虫核心代码,详细代码以上传GitHub,地址在文末:
我们用5个线程去采集虎扑新闻列表页看看效果如果?运行该程序,得到如下结果:
结果中可以看出,我们启动了5个线程采集了61页页面,一共耗时2秒钟,可以说效果还是不错的,我们来跟单线程对比一下,看看差距有多大?我们将线程数设置为1,再次启动程序,得到如下结果:
可以看出单线程采集虎扑61条新闻花费了7秒钟,耗时差不多是多线程的4倍,你想想这可只是61个页面,页面更多的话,差距会越来越大,所以多线程爬虫效率还是非常高的。
分布式爬虫架构
分布式爬虫架构是一个大型采集程序才需要使用的架构,一般情况下使用单机多线程就可以解决业务需求,反正我是没有分布式爬虫项目的经验,所以这一块我也没什么可以讲的,但是我们作为技术人员,我们需要对技术保存热度,虽然不用,但是了解了解也无妨,我查阅了不少资料得出了如下结论:
分布式爬虫架构跟我们多线程爬虫架构在思路上来说是一样的,我们只需要在多线程的基础上稍加改进就可以变成一个简单的分布式爬虫架构。因为分布式爬虫架构中爬虫程序部署在不同的机器上,所以我们待采集的URL和采集过的URL就不能存放在爬虫程序机器的内存中啦,我们需要将它统一在某台机器上维护啦,比如存放在Redis或者MongoDB中,每台机器都从这上面获取采集链接,而不是从linkedBlockingQueue这样的内存队列中取链接啦,这样一个简单的分布式爬虫架构就出现了,当然这里面还会有很多细节问题,因为我没有分布式架构的经验
以上就是长沙牛耳教育java培训机构的小编针对“Java爬虫教程,多线程爬虫及分布式爬虫”的内容进行的回答,希望对大家有所帮助,如有疑问,请在线咨询,有专业老师随时为你服务。
Java教程