本文按如下内容组织:
# 介绍这个爬虫的目的、模块,创造原始单线程爬虫
# 对这个爬虫进行改造,创造多线程爬虫
一、爬虫功能介绍
文章标题取的是《Python爬虫与多线程》,而不是《Python多线程爬虫》,因为爬虫的目的是为了获取数据而非炫技。即使没有多线程,单线程的爬虫也可以完成任务,大不了电脑不关放一夜跑(做量化回测中常有的事)。
下面就介绍这个爬虫的功能,是用来爬取https://quantocracy.com/所有帖子的标题、描述、网址、发布时间,分别对应数据库的四个字段:title、description、url、time。
这个网站的结构非常简单,所以爬虫的逻辑也比较简单:
下面依次介绍代码的实现逻辑:
(1)构造出一页的url,比如https://quantocracy.com/?pg=1,使用自定义的get_html函数获得html内容:
(2)使用Beautiful库解析内容,获得我们需要的信息。通过chrome的审查元素功能可以发现,网页的结构如下图:
加粗的标签是含有信息的标签,所以我们用tags = soup.find_all('div',attrs={'class':'qo-content-col'})找到所有的div标签,每页可以得到五十个标签。
下面使用自定义的get_info函数对每个标签做子解析:
(3)将信息存储到本地文件或数据库。
上述步骤(2)返回了一条[title, description, url, time]的信息,然后不断把这条信息append到results列表中,就得到了所有信息。当循环完所有页面时,我们可以把results转成pd.DataFrame,然后存储到本地csv。
以上,我们实现了一个功能完整的单线程爬虫,耗时在十几分钟。第二部分讨论可以在哪些环节降低延迟。
二、多线程爬虫
上文的爬虫流程:获取页面 -> 解析页面 -> 数据存储,在这些环节中的耗时分别是:
(1)获取页面,由于网络延迟,一页通常需要1-2s,这是最主要的延迟;
(2)数据存储,由于是存储到本地数据库,速度较快。
下面考虑怎么降低延迟:
(1)创建一个Consumer类和多个实例,用于对每个页面的获取、解析和存储。
(2)用一个队列Queue对象,来实现Consumer类不断获取网址。
代码逻辑如下:
先产生所有url,put进队列;
然后产生八个消费者,用于不断从队列中取出网址,进行获取、解析和存储;
所有信息存储到内存中,然后批量存储到数据库或csv。
这个流程下来,有八个worker并行工作,所以效率提升很多。
Consumer类的代码如下:
三、最后呈现的数据长这样:
领取专属 10元无门槛券
私享最新 技术干货