您的位置:首页 > 编程语言 > Python开发

[Python] 分布式新浪爬虫的实现

2015-12-18 15:07 543 查看
写新浪爬虫是我这个暑假冒出来的想法,当时因为种种原因没能完成,一直拖到年底。期间也学习了很多其他的东西,如tornado等等。写这个爬虫的初衷是,希望能够爬取用户之间的关系网,进行社交网络分析。此外,受那篇Twitter mood predicts the stock market的影响,也希望能够分析微博用户每天的情绪变化。

一开始写的时候,并没有想到要写成分布式的。我一开始只是写成单线程的形式。然后发现微博的反爬虫机制有点凶,如果请求速度过快的话直接就把你的IP给封了。这样一来的话,单线程的爬虫做来玩玩还可以, 如果想要大量爬取数据的话就不现实了。因此只能写成多线程或者是分布式的。

这个爬虫的结构大致如下所示:



如图所示,蓝底白字的框图表示控制模块,白底蓝字表示与数据库有关的程序,白底绿字表示有网络有关程序

从上图可以看到该爬虫主要分成两部分,即服务器端和客户端。左边是服务器端,右边是客户端。

服务器端负责代理的获取与维持,以及负责与数据库的交互;而客户端从服务器端获取代理以及任务,并从新浪爬取用户信息,之后将爬取到的数据返回服务器端。(我曾经有想过将各个节点做成可以相互通信的形式,但是考虑到作为学生,没有这么多专业的集群,更多的情况下是在民用的电脑下部署客户端,因此部署越简单越好,什么docker就别想了,最好是tornado这种第三方库都不用装,只装一个python就可以运行了。因此思虑再三,决定做成这种,由客户端主动发起通信,服务器端分配任务的模式)

服务器端各模块功能如下:

● Server( Tornado )

Tornado 负责接受并处理各个客户端发来的请求。主要是发送 task,proxy,接收客户端返回的用户信息和关注信息

● Proxy Manager

为了提高抓取效率,防止被封IP,使用代理来抓取页面是非常必要的。因此就需要服务器端维持一个代理池。具体方法是:首先从代理网站批量获取未经验证的代理(get raw proxy), 然后依次用这些代理去尝试连接外网(check proxy)。如果能够连接成功,则表示该代理有效,放入线程池,待客户端取用;如果无法连接,则表示该代理无效。由于单线程验证代理效率太低,所以有必要使用多个线程来验证代理。我现在是使用100个子线程来验证这些代理是否有效

● DB Manager

负责处理数据库的事物。Tornado在接收到客户端返回的数据之后,将该数据存入缓存表(Cache Table). 而DB Manager是一个单独的线程,负责处理分析在cache table 中的数据,并将其存入到正式表中。值得注意的是,在处理关注列表的时候,需要进行查重,即判断那些用户已经爬过且存在表中了,而哪些还没有,需要重新爬取。我一开始的时候是对关注列表中的每个人都会查询一次,结果发现这样做几乎占用了磁盘的所有读取性能,以至于使得服务器程序无法正常工作。因此,还引入了redis作为mysql的缓存,用于查重。关于用redis实现bloomfilter,在之前的文章中已经提过了用redis实现bloomfilter

客户端各模块功能如下:

● Client Manager

考虑到该爬虫目的比较单一,预期主要有两个功能:爬取用户关注列表,以及获取用户发布的微博信息。 目前只实现了第一个功能, 但是预留了可扩展的借口。该模块负责与服务器端进行通信,获取任务形式以及目标用户。如果是爬取关注的任务,则转到Task Manager 模块。

● Task Manager

该模块同样会维持一个代理池,大小设定在线程数*2。 也就是说,平均一个线程拥有2个代理。 当代理池内代理不够时,会向服务器请求代理。同时,该模块会启动多个子进程,分工请求不同页面,以加快速度。

未完待续
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: