何谓网络爬虫
网络爬虫是一种用来抓取网页资源的程序工具。像谷歌,百度等知名搜索引擎就是采用网络爬虫把全网的网页资源收集起来,建立索引,用于搜索。
网络爬虫实现原理
互联网网页可以看成是一张超大图,每个网页是一个节点,网页中指向其他网页的链接是边。那么,可以这样实现全网网页收集:以某一个网页为起点,下载并处理该网页,解析里面的链接,所得的URL加入下载队列。这个过程其实就是图的遍历过程,可以是深度优先或者广度优先遍历,取决于下载队列如何维护。简单地,网络爬虫可以由以下部分组成:
下载模块
对于一个给定的URL,下载该网页。如果从零开始实现,工作量还是挺大的:①解析URL里面的域名并通过DNS查询域名对应的IP;②建立一个到该IP的TCP连接;③发送一个HTTP请求;④接收并解析HTTP响应;⑤保存该网页资源。说白了,就是给定一个URL,用HTTP协议请求一个网页资源的过程。
下载队列
下载队列保存从网页中解析出来将用于获取网页资源的URL:每次从下载队列里面取出一个URL,通过下载模块下载该网页,解析该网页里面的URL并加入下载队列,这样就可以源源不断地进行网页抓取。如果用FIFO实现下载队列,那么对网页资源的遍历就是广度优先的;如果用LIFO实现下载队列,那么对网页资源的遍历就是深度优先的。
重复检查
如果某个网页里面包含了已经下载的网页的URL怎么办呢?肯定不能再重复下载一次。如何避免就是重复检查模块要做的事。可以用一个set把所有遇到的URL记录下来,每次下载模块获取一个网页,将其URL放到该set;解析网页所获得的URL,如果在该set中已经存在了,就不要加入下载队列了。当然了,这只是最直白的实现方式,工程上为了应对大量的URL,一般采用布隆过滤器。
Python实现举例
-
#!/usr/bin/env python
-
# -*- encoding=utf8 -*-
-
import re, urllib2, md5, urlparse
-
class Crawler(object):
-
def __init__(self, *starts):
-
self.seen = set() # 已获取网页的URL集合
-
self.queue = [] # 待下载队列
-
self.URLMOD = re.compile('href="(http://[^"]*)"') # 用于匹配URL的正则
-
# 将起点URL加入下载队列
-
for start in starts:
-
self.queue.append(start)
-
def process(self, url, res):
-
# 正则解析网页里面的URL
-
for new_url in self.URLMOD.findall(res):
-
if new_url.find('\n') == -1 and new_url not in self.seen:
-
# 如果URL不在已获取集合,则加入下载队列
-
self.queue.append(new_url)
-
# 在这里写个性化的网页处理逻辑:保存到文件?写到数据库?
-
def run(self):
-
while self.queue:
-
# 从下载队列取出一个URL
-
url = self.queue.pop()
-
try:
-
# 下载该网页:用Python的urllib2
-
res = urllib2.urlopen(url, timeout=10).read()
-
print 'Get %s %s' % (url, '')
-
except:
-
# 下载出错
-
print 'Err %s %s' % (url, '')
-
continue
-
# 将URL加入已获取集合
-
self.seen.add(url)
-
# 处理该网页
-
self.process(url, res)
-
if __name__ == '__main__':
-
Crawler('http://www.baidu.com').run()