一个微博爬虫的设计原型

梳理下

上个月去了趟南京,回来后再加上个国庆假期,整个人就闲下来了.每天,也没太多事情可做,有时候,很享受这样的日子,呵.闲下来的时候,总想找点事做来打发打发时间.

目前的兴趣点在网络和图论这块,再加上之前接触了一下图数据库neo4j,感觉得这货以后很有潜力,于是乎,希望能够找个实际点的东西来练练手,然后,很短视地想到适合用图数据库的地方--社交网络.其实也没多想,就敲定了新浪微博这个平台(别问我为啥偏偏是微博).

在这里完整记录下自己考虑问题的整个过程(虽然暂时搁置下来了),希望以后考虑其他问题的时候,能从中有所借鉴吧.

目的

一开始希望做的事情是,能够用图数据库neo4j来存储一些社交网络上的数据,这样以后分析起来效率会高很多,也算是搭建个平台起来吧.

设计

做爬虫这种事,必然有很多人已经做过了,所以,最重要的是前期调研,然后,找到了知乎上点赞最多的这个回答,总的来说,很有收获.所以,自己后面数据流的设计基本是参照这个来的.为了后面阐述方便,先看大图:

:上图有个问题,实际上不应该使用Queue,而是使用set或者order set的结构来存储

可能大多数人做爬虫只是简单的上来先写好网络接口,配置好存储方式就开始了.不过,在这里,我是希望整个过程能够有一个良好的可扩展性.因此,需要考虑的事情会更多.

首先,明确两条主线.时间流数据流.

先说数据流这里采用自顶向下的思考方式.首先来考虑数据在图数据库中怎么存储的,假设现在有了1kw的用户及其微博(平均每人提取300条),那么该如何在图数据中表示这张超大的关系网呢?图数据库中基本的元素是点和边,自然一种最简单的方式是,以用户为node,以用户和用户之间的关系为edge来构造这个图.初看起来似乎完全没有问题,但是这里把许多细节高度抽象化了,还有很多细节需要考虑,比如:

  1. 微博内容存在哪?(这个可以存在用户节点内,以json格式组织,问题不大)
  2. 如何体现用户与用户之间关系(edge)的差异性?(比如,虽然我同时关注了几百号人,但是我跟其中的某些人关系很熟,经常互动,但是另外一些人可能虽然关注了但很少联系)
  3. 通过微博@用户的关系如何体现?用户对微博的评论,点赞,转发呢???(有个改进的方案,微博还是放在用户节点下,但是通过丰富用户与用户之间关系(edge)的属性(加入评论,转发,@等),强化用户关系之间的描述)
  4. 图数据库的优势体现在哪?

上面的分析可以发现,最大的问题在于,微博怎么放.由于微博在这里已经不再是一个简单的文本,而是负担起了网络中连接器的功能,所以有必要将其独立出来作为存储的节点,从而用户与用户之间,用户与微博之间,微博与微博之间的关系更加清晰.那么这样子做是否可行呢?有一个最大的担忧是,将微博作为节点的化,整个数据库的节点数目会接近30亿,那么这就对neo4j的性能提出要求了,neo4j能否容纳这么大量的节点数目呢?经过一番调研,发现是可以做到的,问题是,一台小型机恐怕有点容不下,需要分布式的结构,但是neo4j的社区版不支持分布式安装,还好有个人版.这块先这样.再往下,每个爬虫爬到数据后,通过pipeline将数据扔到数据库里.至于数据去重的部分,放在爬虫的功能设计中去.

再从时间流的角度考虑如何爬数据.简单的分析可以看出,用户之间的关系网很简单,而微博的关系网比较复杂,需要打开每一个微博的页面单独去爬评论,点赞之类的.这会导致用户数变得不可控,这里说的不可控是指,在整个网络中会产生大量的孤立节点.考虑到后期分析用户之间关系的目的,这些数据会变得根本不可用.因此,设计思路就变成了,首先爬取用户与用户之间完整的关系网,然后,通过微博的内容来完善该关系网.因此,从时间上考虑,可以简单分为以下3步.

  1. 随机选取种子用户
  2. 爬取用户的关系网络,同时爬取用户的个人信息
  3. 等整个数据库中用户数达到一定规模后,停止爬取用户网络,继续爬取用户的个人信息(这个会比较慢)
  4. 遍历数据库中的用户,读取其微博内容,以及爬取的网络中其他用户对该微博的评论,赞等

爬虫需要设计好如何避免重复,这里采用分布式的redis来实现该过程.每次开始爬数据之前,先向redis发起请求获取一批用户id,爬完后返回结果到pipeline,pipeline负责向neo4j保存数据,同时向redis放入下一步应该要爬的用户id.

这样子,整个流程就走通了.

于是乎,兴高采烈地写代码咯~

先用requests写了个登陆程序,再换成scrapy环境下的,接着写好pipeline,配置好redis和neo4j,这些都很顺畅.

可是,刚开始爬了几分钟,挂了...

WTF!!!

ip被封了...

悲剧的,好吧,用代理,

问题来了,代理上哪找,免费的没几个可用,

更蛋疼的问题是,异地登陆要验证码......

虽然微博的验证码没那么复杂,但是时间成本略大...

总之,这个事情就这么暂时搁置下来了,只能说,what a pity