在本节实践中,我们将借助Python多线程编程并采用生产者消费者模式来编写爬取Bing每日壁纸的爬虫。在正式编程前,我们还是一样地先来分析一下我们的需求及大体实现的过程。

总体设计预览

首先,我们先来看一下第三方提供的Bing壁纸网站http://bing.plmeizi.com/。在这一个网站中保存了以往的Bing每日壁纸,往下滑动也可以看到其目前一共有88页(即2016年9月至今)。

接着我们像之前一样来分析每页的URL构成法,这里不难分析得知其构成法为:http://bing.plmeizi.com/?page={index},其中index代表页码数(具体分析方法可参看之前的实践博客)。

然后我们再分析每页所需解析的数据源代码。如下图所示,通过简单地分析HTML源码我们便可以确定所需获取的图片数据被包含在了一个list类的div标签下的a标签中,并且这个a标签下有两个子节点——img图片标签和p文字说明标签。

如此一来,我们的目标和过程也就明确了,先获取每页的URL,然后对每页进行HTML解析并获取图片的img和说明内容,从而可利用其源地址src进行下载保存以达到爬取图片的目的。

爬取的发送请求和解析过程在之前的实践中已介绍,在此不在叙述,本节主要介绍如何利用生产者消费者模式来编写多线程爬虫。

生产者消费者模式分析

首先,我们来认识一下这里我们所设定的生产者消费者角色都是什么。生产者即生产资源的角色,这里我们可以让其专门负责解析每页URL并获取图片的src和说明内容;而消费者即消费资源的角色,这里我们可以指定其专门从以获取的src那里取出图片源地址进行下载。

这么一来,此模式的总体思路即:生产者线程解析单页网址,获取相应节点资源信息,并将信息存入一个中间单元,而消费者线程则负责从这个中间单元获取信息并消费。这里的共享中间单元,主要指的是图片相关的数据信息;而实际上,我们还可以设定另一个全局页面资源,其包含所有待解析的单页URL,主要目的是用于控制生产者是否解析完成和检查消费者是否已消费完成(当中间单元没有图片数据且页面资源页也已全部解析完毕则说明爬取任务已经完成)。

经上述分析,我想生产者消费者线程类也大体有了一个雏形,考虑到多线程编程,下面我们采用Queue线程队列来分别做进一步的介绍。

生产者线程类的实现:

在生产者线程类中,有两个属性self.pages_queue 和 self.imgs_queue,分别对应着上文中的页面资源和图片中间单元,这两个属性都可以在类初始化时通过参数传递进行设置;另外还具有parse_url(self,url)的方法,用于对单页进行解析,同时将解析后获取的图片资源存入图片中间单元;再者是run(self)方法的重写,其专门从页面资源中获取一个页面,并调用传递给parse_url()方法,同时其还需判断控制进程的完毕状态。具体实现如下:

消费者线程类的实现

和生产者线程类类似,其也有两个属性self.pages_queue 和 self.imgs_queue,含义和初始化操作均与生产者的一样;另外由于其只需要单纯地从中间单元取数据并消费,因此这一行为可以直接通过run()重写实现。消费者线程类的编写较为简单,具体如下:

主功能模块的实现

主功能模块负责进行一些前期数据准备工作,如两个资源队列的初始化和单页url的生成与存储,再者实例化创建相关的线程并执行。其具体实现如下:

如此一来,我们的多线程爬虫就编写完毕。下图是我的运行结果(效果还是比较满意的):


本文转载:CSDN博客