最近看过不少讲爬虫的教程[1][2],基本都是一个模式:

  1. 开始先来拿正则、lxml、jquery/pyquery等等教大家从页面上抠出一个一个的值来

  2. 然后深入一些在讲讲http 协议,讲讲怎么拿出 cookie 来模拟登录之类的,讲讲基本的反爬虫和反反爬虫的方法

  3. 最后在上一个 简单地 scrapy 教程,似乎就皆大欢喜了。

具体地采集一个一个的数据的确让人产生成就感,然而这些教程却都忽略了爬虫最核心的逻辑抽象,也就是「爬虫应该采取什么样的策略遍历网页」。其实也很简单,只需要两个队列和一个集合,Scrapy 等框架拆开来看也是如此,本文参照 Scrapy 实现一个最基础的通用爬虫。

万维网是由一个一个的页面构成的,而每个页面和页面之间是由链接来联系的,并且这些链接都是具有方向性的。对应到数据结构的话,我们可以把每一个页面都看作一个节点,而每一个链接都是一个有向边,也就是整个万维网其实是一个巨大的「有向图」[3]。说到这里,可能有的同学已经明白了,可以用广度优先或者深度优先的算法来遍历这个图。当然,这个图是在太巨大了,我们不可能遍历整个图,而是加一些限定条件,只去访问其中很小一部分我们感兴趣的节点,比如某个域名下的网页。

广度优先和深度优先都可以使用递归或者辅助的队列(queue/lifo_queue)来实现。然而如果你的爬虫是用 python 写的话,很遗憾不能使用递归来实现了,原因很简单,我们要访问的网页可能成千上万,如果采用递归来实现,那么爬虫每向前访问一个节点,系统的调用栈就会 +1,而 python 中至今没有尾递归优化,默认的堆栈深度为1000,也就是很可能你访问了1000个网页之后就抛出异常了。所以我们这里使用队列实现对网页的遍历访问。

理论知识说了这么多,下面以一个例子来说明一下如何爬取数据:爬取煎蛋网的妹子图: http://jandan.net/ooxx

首先,我们打开对应的网址,作为起始页面,也就是把这个页面放入待访问的页面的队列。注意,这是我们需要的第一个队列,存放我们的待访问页面。

class MiniSpider(object):

    def __init__(self):
         self._request_queue = queue.Queue()  # 带请求页面的队列
         self._request_queue.put('http://jandan.net/ooxx')  # 把第一个待访问页面入队

延伸阅读

学习是年轻人改变自己的最好方式-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训学习是年轻人改变自己的最好方式