最近看过不少讲爬虫的教程[1][2],基本都是一个模式:
开始先来拿正则、lxml、jquery/pyquery等等教大家从页面上抠出一个一个的值来
然后深入一些在讲讲http 协议,讲讲怎么拿出 cookie 来模拟登录之类的,讲讲基本的反爬虫和反反爬虫的方法
最后在上一个 简单地 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') # 把第一个待访问页面入队
延伸阅读
- ssh框架 2016-09-30
- 阿里移动安全 [无线安全]玩转无线电——不安全的蓝牙锁 2017-07-26
- 消息队列NetMQ 原理分析4-Socket、Session、Option和Pipe 2024-03-26
- Selective Search for Object Recognition 论文笔记【图片目标分割】 2017-07-26
- 词向量-LRWE模型-更好地识别反义词同义词 2017-07-26
- 从栈不平衡问题 理解 calling convention 2017-07-26
- php imagemagick 处理 图片剪切、压缩、合并、插入文本、背景色透明 2017-07-26
- Swift实现JSON转Model - HandyJSON使用讲解 2017-07-26
- 阿里移动安全 Android端恶意锁屏勒索应用分析 2017-07-26
- 集合结合数据结构来看看(二) 2017-07-26