知乎爬虫

长久以来一直想解决一个问题,就是知乎上最高赞同的Top10是哪些答案,知乎内部的人查一下数据库就可以了,而在外部只能通过爬虫。可能这个问题对很多人而言意义不是很大,但我一直非常好奇…于是开始写了。

在写具体细节之前,先给一个爬的结果吧,截止至2014年3月7号的知乎Top10如下:

  1. 你觉得自己牛逼在哪里? 18279票
  2. 精神分裂症患者眼中的世界是什么样的? 15929票
  3. 到底什么叫爱?爱一个人到底什么感觉? 14993票
  4. 二十多岁该做些什么,将来才不会后悔? 14419票
  5. 你有什么相见恨晚的知识想推荐给年轻人? 13810票
  6. 哪些东西买了之后,会让人因生活质量和幸福感提升而感觉相见恨晚? 12632票
  7. 租个女友回家过年靠谱吗,有什么风险? 12504票
  8. 同样 25 岁,为什么有的人事业小成、家庭幸福,有的人却还在一无所有的起点上? 11913票
  9. 你爱上某一个人时,最奇特的一次是因为什么? 9251票
  10. 读一百本书和健身练6块腹肌相比,哪个对于找漂亮的女朋友更有帮助? 8955票

实现

话说爬虫用python的urllib2和BeautifulSoup或者java写是分分钟的事情,我想了想还是算了吧,我不喜欢这样写,我决定用C++来写这个爬虫。正巧我搜到了有位网友写了个搜索引擎,里面的爬虫部分也是在linux下用C++写的,于是我借鉴了一下他写的一些类库, 还好不是从头开始写,还算方便。

逻辑

  1. 确定爬的深度N,然后维护N个队列,用BFS扫第i的队列的时候把下一轮要处理的url放在第i+1个队列中。
  2. 用MD5值去重。
  3. 爬虫的初始种子是一些zhihu名人,在第0个队列里,然后把他们的followers和followees的主页url加入下一个队列。
  4. 使用了150个线程,爬的速度还算快。

注意点

多线程访问共享变量(url队列),就算你加了锁,还由可能出现想都没想到过的情况…多线程编程一定要考虑周全(实际上这不太可能)。

源码

如果你对源码感兴趣或者想拿自己的zhihu账号作为种子爬一爬,我把代码放在了github上。

进阶

实际上,写一个单机爬虫涉及不到高级的东西,设计并实现一个分布式爬虫是一件有挑战的事情。

首先要确定架构,一般的master-slave模型是比较好的选择,slave干完事了向master申请新的URL来爬。需要在master上维护一个URL队列,slave将当前URL上所有的网页发送给master。

其次是效率,用MD5在大规模去重上实在太慢!一个解决方法是用bloom filter,它的复杂度只有O(1),但是这个方法有个缺点,就是如果一个元素不在集中,会有非常小的概率被判断在集合里,导致遗漏。实际中这个概率小到我们可以忽略不计。

爬虫说细了是个很复杂的东西。它还有很多很多话题可以讨论。比如数据库存储,对网页如何有效地处理等等。