0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

实现Java多线程爬虫的两点

汽车玩家 来源: 黑马程序员 作者: 黑马程序员 2020-05-05 21:25 次阅读

在我们调试爬虫程序的时候,单线程爬虫没什么问题,但是当我们在线上环境使用单线程爬虫程序去采集网页时,单线程就暴露出了两个致命的问题:

采集效率特别慢,单线程之间都是串行的,下一个执行动作需要等上一个执行完才能执行

对服务器的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 之后保存到哈希表中去重,相比于上面一种,能够节约空间

使用 布隆过滤器(Bloom Filter)去重,这种方式能够节约大量的空间,就是不那么准确。

关于多线程爬虫的两个核心知识点我们都知道啦,下面我画了一个简单的多线程爬虫架构图,如下图所示:

实现Java多线程爬虫的两点

多线程爬虫架构图

上面我们主要了解了多线程爬虫的架构设计,接下来我们不妨来试试 Java 多线程爬虫,我们以采集虎扑新闻为例来实战一下 Java 多线程爬虫,Java 多线程爬虫中设计到了 待采集 URL 的维护和 URL 去重,由于我们这里只是演示,所以我们就使用 JDK 内置的容器来完成,我们使用 LinkedBlockingQueue 作为待采集 URL 维护容器,HashSet 作为 URL 去重容器。下面是 Java 多线程爬虫核心代码,详细代码以上传 GitHub,地址在文末:

实现Java多线程爬虫的两点

实现Java多线程爬虫的两点

实现Java多线程爬虫的两点

我们用 5 个线程去采集虎扑新闻列表页看看效果如果?运行该程序,得到如下结果:

实现Java多线程爬虫的两点

多线程采集结果

结果中可以看出,我们启动了 5 个线程采集了 61 页页面,一共耗时 2 秒钟,可以说效果还是不错的,我们来跟单线程对比一下,看看差距有多大?我们将线程数设置为 1 ,再次启动程序,得到如下结果:

实现Java多线程爬虫的两点

单线程运行结果

可以看出单线程采集虎扑 61 条新闻花费了 7 秒钟,耗时差不多是多线程的 4 倍,你想想这可只是 61 个页面,页面更多的话,差距会越来越大,所以多线程爬虫效率还是非常高的。

分布式爬虫架构

分布式爬虫架构是一个大型采集程序才需要使用的架构,一般情况下使用单机多线程就可以解决业务需求,反正我是没有分布式爬虫项目的经验,所以这一块我也没什么可以讲的,但是我们作为技术人员,我们需要对技术保存热度,虽然不用,但是了解了解也无妨,我查阅了不少资料得出了如下结论:

分布式爬虫架构跟我们多线程爬虫架构在思路上来说是一样的,我们只需要在多线程的基础上稍加改进就可以变成一个简单的分布式爬虫架构。因为分布式爬虫架构中爬虫程序部署在不同的机器上,所以我们待采集的 URL 和 采集过的 URL 就不能存放在爬虫程序机器的内存中啦,我们需要将它统一在某台机器上维护啦,比如存放在 Redis 或者 MongoDB 中,每台机器都从这上面获取采集链接,而不是从 LinkedBlockingQueue 这样的内存队列中取链接啦,这样一个简单的分布式爬虫架构就出现了,当然这里面还会有很多细节问题,因为我没有分布式架构的经验

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2964

    浏览量

    104686
  • 多线程
    +关注

    关注

    0

    文章

    278

    浏览量

    19940
收藏 人收藏

    评论

    相关推荐

    socket 多线程编程实现方法

    在现代网络编程中,多线程技术被广泛应用于提高服务器的并发处理能力。Socket编程是网络通信的基础,而将多线程技术应用于Socket编程,可以显著提升服务器的性能。 多线程编程的基本概念 多线
    的头像 发表于 11-12 14:16 330次阅读

    Python中多线程和多进程的区别

    Python作为一种高级编程语言,提供了多种并发编程的方式,其中多线程与多进程是最常见的种方式之一。在本文中,我们将探讨Python中多线程与多进程的概念、区别以及如何使用线程池与进
    的头像 发表于 10-23 11:48 383次阅读
    Python中<b class='flag-5'>多线程</b>和多进程的区别

    INA818输入直接取电阻R2两点电压,两点压差范围约为2mV~200mV,是否可以直接作为INA818的输入呢?

    : 1.INA818采用5V单电源供电,REF引脚由DAC芯片给出2.5V的参考电压。 2.INA818的输入直接取电阻R2两点电压,两点压差范围约为2mV~200mV,这是否可以直接作为INA818的输入呢
    发表于 08-09 06:29

    ESP32会不会有多线程问题,需要加锁吗?

    ESP32会不会有多线程问题,需要加锁吗
    发表于 07-19 08:05

    多线程设计模式到对 CompletableFuture 的应用

    最近在开发 延保服务 频道页时,为了提高查询效率,使用到了多线程技术。为了对多线程方案设计有更加充分的了解,在业余时间读完了《图解 Java 多线程设计模式》这本书,觉得收获良多。本篇
    的头像 发表于 06-26 14:18 331次阅读
    从<b class='flag-5'>多线程</b>设计模式到对 CompletableFuture 的应用

    探索虚拟线程:原理与实现

    虚拟线程的引入与优势 在Loom项目之前,Java虚拟机(JVM)中的线程是通过java.lang.Thread类型来实现的,这些
    的头像 发表于 06-24 11:35 284次阅读
    探索虚拟<b class='flag-5'>线程</b>:原理与<b class='flag-5'>实现</b>

    动态线程池思想学习及实践

    ://www.javadoop.com/post/java-thread-pool 引言 在后台项目开发过程中,我们常常借助线程池来实现多线程任务,以此提升系统的吞吐率和响应性;而
    的头像 发表于 06-13 15:43 1171次阅读
    动态<b class='flag-5'>线程</b>池思想学习及实践

    bootloader开多线程做引导程序,跳app初始化后直接进hardfualt,为什么?

    如标题,想做一个远程升级的项目,bootloader引导区域和app都是开多线程跑的,就是自己写了个小的任务调度器,没什么功能主要是想让程序快速的响应,延时不会对其他程序造成堵塞,程序测试
    发表于 04-18 06:07

    鸿蒙APP开发:【ArkTS类库多线程】TaskPool和Worker的对比

    TaskPool(任务池)和Worker的作用是为应用程序提供一个多线程的运行环境,用于处理耗时的计算任务或其他密集型任务。可以有效地避免这些任务阻塞主线程,从而最大化系统的利用率,降低整体资源消耗,并提高系统的整体性能。
    的头像 发表于 03-26 22:09 606次阅读
    鸿蒙APP开发:【ArkTS类库<b class='flag-5'>多线程</b>】TaskPool和Worker的对比

    鸿蒙原生应用开发-ArkTS语言基础类库多线程TaskPool和Worker的对比(一)

    TaskPool(任务池)和Worker的作用是为应用程序提供一个多线程的运行环境,用于处理耗时的计算任务或其他密集型任务。可以有效地避免这些任务阻塞主线程,从而最大化系统的利用率,降低整体资源消耗
    发表于 03-25 14:11

    java实现多线程的几种方式

    Java实现多线程的几种方式 多线程是指程序中包含了个或以上的线程,每个
    的头像 发表于 03-14 16:55 676次阅读

    AT socket可以多线程调用吗?

    请问AT socket 可以多线程调用吗? 有互锁机制吗,还是要自己做互锁。
    发表于 03-01 08:22

    linux多线程编程实例

    linux线程
    的头像 发表于 02-15 21:16 454次阅读
    linux<b class='flag-5'>多线程</b>编程实例

    使用C++11新特性实现一个通用的线程池设计

    在C++11标准之前,多线程编程只能使用pthread_xxx开头的一组POSIX标准的接口。从C++11标准开始,多线程相关接口封装在了C++的std命名空间里。
    的头像 发表于 12-22 13:58 1257次阅读
    使用C++11新特性<b class='flag-5'>实现</b>一个通用的<b class='flag-5'>线程</b>池设计

    你还是分不清多进程和多线程吗?一文搞懂!

    你还是分不清多进程和多线程吗?一文搞懂! 多进程和多线程是并发编程中常见的个概念,它们都可以用于提高程序的性能和效率。但是它们的实现方式和使用场景略有不同。 1. 多进程: 多进程指
    的头像 发表于 12-19 16:07 558次阅读