这是我参与「第四届青训营 」笔记创作活动的第 33 天
一个大数据小白的自学成长之路 ( 四 ): 完整项目
作为一个本科应用数学专业的大数据领域的萌新 , 可能没法像技术大牛一样有很多的技术产出 , 暂且就把我在做项目时的一些心得和所学作为笔记吧 !( 有些大白话写的不是很专业 , 大佬轻喷 )
1.项目介绍
爬虫系统是搜索引擎领域中很关键,很基础的构件,能够将海量的网页数据下载到本地,进行数据处理后存储和索引以满足不同的使用场景。互联网的网页是海量的,如何能够进行高效的数据爬取是爬虫系统面临的最大挑战之一,一种可行的方式是采用分布式的方式进行数据爬取以提高爬取效率。
2.主要概念理解
分布式主要是单机的各个进程之间的通讯即伪分布式和各个设备之间的通讯这两个方面。前者是只在一台设备上进行的数据并行爬取,后者是可以在多个设备之间进行通讯,这种方式可以使得爬取效率得到很大的提升(基于设备数量而对于单个设备性能的依赖性降低)。
3.系统设计
整个分布式系统被配置到docker容器中。通过多进程来模拟多机爬虫,实现伪分布。通过docker我们能够更快,更高效的部署分布式系统,并维持一致的开发环境。爬虫方面,我们用到了beautifulsoup和request模块。Python脚本爬取的数据会通过kafka消息队列传输给java通过flink调度存储数据。最后为用户提供查询数据的借口。在此过程中凭借thrift进行python端和java端的RPC。
3.1.系统架构图及说明
上图为分布式爬虫系统的架构图,我们将所有的URL放入kafka消息队列中。URL由种子爬虫脚本生产,再传输给flink进行消费,分发给多个网页爬虫脚本爬取数据。新得到的URL(经过去重)会再放到kafka队列内等待爬取,而图片文本等数据会被存储到数据库中。
3.2.系统核心模块说明
整个系统有两个核心模块。分别是爬虫模块,和流数据处理及URL分发模块。
爬虫模块(python)的主要任务是获取新的URL加入URL队列,以及爬取文本图片等数据。我们遵守了robust协议,项目还支持主网站的DNS解析。URL的去重问题我们也通过把URL以MD5的形式存在内存中解决。
Flink(java)流数据处理模块也是该项目的核心。Flink作为消费者会不断接收kafka传出的URL,然后再将这些URL分发给爬虫脚本进行数据爬取。期间,会启动多个爬虫程序进行数据爬取,为了避免太多进程同时运行,我们设置了最大进程运行数量。因为爬虫脚本由python编写,URL分发由java编写,我们需要通过thrift完成RPC实现爬虫脚本和URL分发模块通信,统计并控制正在运行的进程数量。
3.3.系统各模块间交互逻辑说明
初始爬虫脚本先读取种子URL里的URL,作为生产者将这些URL发送到kafka消息队列中。再监听kafka队列,flink模块由此获得这些URL。其中,kafka作为项目上有连接初始爬虫脚本与URL分发模块的交互桥梁。
分发URL时,必须考虑当前运行的进程数量,因此,需要爬虫进程在开始和结束的时候发送信息给分发模块,以便控制爬虫进程数量。Thrift作为最高效的RPC工具实现了爬虫进程和爬虫分发模块之间的交互。
3.4.系统运行流程说明
首先,启动种子爬虫脚本(初始爬虫)爬取URL,将获取 URL存放到kafka消息队列中。Flink网址分发模块实时监听kafka消息队列,不断捕获URL(流数据),并将这些URL分发给爬虫脚本。爬虫脚本开始和结束的时候都会通知(通过thrift)分发模块,分发模块能够以此控制爬虫进程数量。最后,爬虫脚本爬取的数据将会被存到数据库中,而新爬到的网址经过去重后会被加入到kafka队列之中。
3.5.系统中涉及的分布式思想
分布式系统被认为是位于联网计算机上的硬件或软件组件仅通过传递消息来通信和协调其动作的系统。其目的是将庞大的数据分成若干小块处理(如通过多机,多进程分散处理数据)。本项目通过多进程实现分布式爬虫,每一个进程执行一个爬虫脚本,多个进程同时运行,能够高效的爬取指定网页的数据。URL分发模块会监控每个爬虫的爬取状态(进程间通信),确保正在运行的爬虫程序不超过设定的阈值。
3.6.核心代码实现说明
爬虫脚本核心代码:
访问网址函数,获取当前需读取网页的地址。
/MainCode/gen-py/crawl.py
解析得到标题与项目地址的列表
/MainCode/gen-py/crawl.py
禁爬协议实现
/MainCode/gen-py/crawl.py
DNS解析,主要通过函数gethostbyname获取DNS
/MainCode/gen-py/crawl.py
Kafka生产者,输入网址。
/MainCode/gen-py/crawl.py
URL分发模块作为消费者,消费kafka队列里的URL。通过监听端口获取URL。
/MainCode/flink/src/main/java/org/example/KafkaConsumer.java
Thrift监听
/MainCode/gen-py/server.py
监听服务,监听打印爬虫进度。
/MainCode/gen-py/listenServer.py
数据查询,连接sqlite3数据库并查询图片。
/MainCode/gen-py/queryPic.py
4.演示Demo
Flink架构包启动
项目启动,47.116.129.84为解析的DNS
kafka监听
thrift服务启动,监测在运行的爬虫进程数量。同时运行的爬虫进程数量上限设置为5,start表示启动了一个爬虫进程,finish表示结束了一个爬虫进程。
下载进度可以在监听程序里看到
结果展示,爬到的图片被存到了文件夹里。
5.项目总结与反思
项目是在docker容器中运行,能够直接将项目打包到容器中快速部署运行。无需花费大量时间配置环境等是这个项目的一大优势。Flink处理kafka内的流数据是整个项目的核心也是亮点。不同于传统的分布式爬虫系统,本项目能够一直接收URL的输入,通过Flink处理URL数据流,分发给爬虫脚本爬取数据。不仅如此,我们通过thrift完成了跨语言(python-java)的进程通信,项目进一步吸收了thrift特点(序列化后的体积小, 速度快)变得更加高效。最后,该项目还支持DNS解析,遵守robust协议。
诚然,项目还是有不少可以改进提高的地方。这个系统实际上是通过一个进程模拟单机实现的伪分布,数据处理的速度与数量还能再提高,未来能够将爬虫部署到个个单机上进一步提升爬虫速度与数据处理的能力。
6.项目代码仓库地址