指定url和深度的广度优先算法爬虫的python实现
广度优先算法介绍
整个的广度优先爬虫过程就是从一系列的种子节点开始,把这些网页中的"子节点"(也就是超链接)提取出来,放入队列中依次进行抓取。被处理过的链接需要放 入一张表(通常称为Visited表)中。每次新处理一个链接之前,需要查看这个链接是否已经存在于Visited表中。如果存在,证明链接已经处理过, 跳过,不做处理,否则进行下一步处理。
初始的URL地址是爬虫系统中提供的种子URL(一般在系统的配置文件中指定)。当解析这些种子URL所表示的网页时,会产生新的URL(比如从页面中的<a href= "http://www.admin.com "中提取出http://www.admin.com 这个链接)。然后,进行以下工作:
- 把解析出的链接和Visited表中的链接进行比较,若Visited表中不存在此链接,表示其未被访问过。
- 把链接放入TODO表中。
- 处理完毕后,再次从TODO表中取得一条链接,直接放入Visited表中。
- 针对这个链接所表示的网页,继续上述过程。如此循环往复。
广度优先遍历是爬虫中使用最广泛的一种爬虫策略,之所以使用广度优先搜索策略,主要原因有三点:
- 重要的网页往往离种子比较近,例如我们打开新闻网站的时候往往是最热门的新闻,随着不断的深入冲浪,所看到的网页的重要性越来越低。
- 万维网的实际深度最多能达到17层,但到达某个网页总存在一条很短的路径。而广度优先遍历会以最快的速度到达这个网页。
- 广度优先有利于多爬虫的合作抓取,多爬虫合作通常先抓取站内链接,抓取的封闭性很强。
广度优先遍历爬虫的python实现
1 #encoding=utf-8
2 from bs4 import BeautifulSoup
3 import socket
4 import urllib2
5 import re
6 import zlib
7
8 class MyCrawler:
9 def __init__(self,seeds):
10 #初始化当前抓取的深度
11 self.current_deepth = 1
12 #使用种子初始化url队列
13 self.linkQuence=linkQuence()
14 if isinstance(seeds,str):
15 self.linkQuence.addUnvisitedUrl(seeds)
16 if isinstance(seeds,list):
17 for i in seeds:
18 self.linkQuence.addUnvisitedUrl(i)
19 print "Add the seeds url \"%s\" to the unvisited url list"%str(self.linkQuence.unVisited)
20 #抓取过程主函数
21 def crawling(self,seeds,crawl_deepth):
22 #循环条件:抓取深度不超过crawl_deepth
23 while self.current_deepth <= crawl_deepth:
24 #循环条件:待抓取的链接不空
25 while not self.linkQuence.unVisitedUrlsEnmpy():
26 #队头url出队列
27 visitUrl=self.linkQuence.unVisitedUrlDeQuence()
28 print "Pop out one url \"%s\" from unvisited url list"%visitUrl
29 if visitUrl is None or visitUrl=="":
30 continue
31 #获取超链接
32 links=self.getHyperLinks(visitUrl)
33 print "Get %d new links"%len(links)
34 #将url放入已访问的url中
35 self.linkQuence.addVisitedUrl(visitUrl)
36 print "Visited url count: "+str(self.linkQuence.getVisitedUrlCount())
37 print "Visited deepth: "+str(self.current_deepth)
38 #未访问的url入列
39 for link in links:
40 self.linkQuence.addUnvisitedUrl(link)
41 print "%d unvisited links:"%len(self.linkQuence.getUnvisitedUrl())
42 self.current_deepth += 1
43
44 #获取源码中得超链接
45 def getHyperLinks(self,url):
46 links=[]
47 data=self.getPageSource(url)
48 if data[0]=="200":
49 soup=BeautifulSoup(data[1])
50 a=soup.findAll("a",{"href":re.compile('^http|^/')})
51 for i in a:
52 if i["href"].find("http://")!=-1:
53 links.append(i["href"])
54 return links
55
56 #获取网页源码
57 def getPageSource(self,url,timeout=100,coding=None):
58 try:
59 socket.setdefaulttimeout(timeout)
60 req = urllib2.Request(url)
61 req.add_header('User-agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)')
62 response = urllib2.urlopen(req)
63 page = ''
64 if response.headers.get('Content-Encoding') == 'gzip':
65 page = zlib.decompress(page, 16+zlib.MAX_WBITS)
66
67 if coding is None:
68 coding= response.headers.getparam("charset")
69 #如果获取的网站编码为None
70 if coding is None:
71 page=response.read()
72 #获取网站编码并转化为utf-8
73 else:
74 page=response.read()
75 page=page.decode(coding).encode('utf-8')
76 return ["200",page]
77 except Exception,e:
78 print str(e)
79 return [str(e),None]
80
81 class linkQuence:
82 def __init__(self):
83 #已访问的url集合
84 self.visted=[]
85 #待访问的url集合
86 self.unVisited=[]
87 #获取访问过的url队列
88 def getVisitedUrl(self):
89 return self.visted
90 #获取未访问的url队列
91 def getUnvisitedUrl(self):
92 return self.unVisited
93 #添加到访问过得url队列中
94 def addVisitedUrl(self,url):
95 self.visted.append(url)
96 #移除访问过得url
97 def removeVisitedUrl(self,url):
98 self.visted.remove(url)
99 #未访问过得url出队列
100 def unVisitedUrlDeQuence(self):
101 try:
102 return self.unVisited.pop()
103 except:
104 return None
105 #保证每个url只被访问一次
106 def addUnvisitedUrl(self,url):
107 if url!="" and url not in self.visted and url not in self.unVisited:
108 self.unVisited.insert(0,url)
109 #获得已访问的url数目
110 def getVisitedUrlCount(self):
111 return len(self.visted)
112 #获得未访问的url数目
113 def getUnvistedUrlCount(self):
114 return len(self.unVisited)
115 #判断未访问的url队列是否为空
116 def unVisitedUrlsEnmpy(self):
117 return len(self.unVisited)==0
118
119 def main(seeds,crawl_deepth):
120 craw=MyCrawler(seeds)
121 craw.crawling(seeds,crawl_deepth)
122
123 if __name__=="__main__":
124 main(["http://www.baidu.com", "http://www.google.com.hk", "http://www.sina.com.cn"],10)

浙公网安备 33010602011771号