爬虫的广度优先和深度优先算法
- 格式:pdf
- 大小:101.60 KB
- 文档页数:2
爬⾍的⼴度优先和深度优先算法⼴度优先算法介绍 整个的⼴度优先爬⾍过程就是从⼀系列的种⼦节点开始,把这些⽹页中的"⼦节点"(也就是超链接)提取出来,放⼊队列中依次进⾏抓取。被处理过的链接需要放 ⼊⼀张表(通常称为Visited表)中。每次新处理⼀个链接之前,需要查看这个链接是否已经存在于Visited表中。如果存在,证明链接已经处理过, 跳过,不做处理,否则进⾏下⼀步处理。把解析出的链接和Visited表中的链接进⾏⽐较,若Visited表中不存在此链接,表⽰其未被访问过。把链接放⼊TODO表中。处理完毕后,再次从TODO表中取得⼀条链接,直接放⼊Visited表中。针对这个链接所表⽰的⽹页,继续上述过程。如此循环往复。⼴度优先遍历是爬⾍中使⽤最⼴泛的⼀种爬⾍策略,之所以使⽤⼴度优先搜索策略,主要原因有三点:重要的⽹页往往离种⼦⽐较近,例如我们打开新闻⽹站的时候往往是最热门的新闻,随着不断的深⼊冲浪,所看到的⽹页的重要性越来越低。万维⽹的实际深度最多能达到17层,但到达某个⽹页总存在⼀条很短的路径。⽽⼴度优先遍历会以最快的速度到达这个⽹页。⼴度优先有利于多爬⾍的合作抓取,多爬⾍合作通常先抓取站内链接,抓取的封闭性很强。爬⾍深度优先搜索 深度优先搜索是⼀种在开发爬⾍早期使⽤较多的⽅法。它的⽬的是要达到被搜索结构的叶结点(即那些不包含任何超链的HTML⽂件) 。在⼀个HTML⽂件中,当⼀个超链被选择后,被链接的HTML⽂件将执⾏深度优先搜索,即在搜索其余的超链结果之前必须先完整地搜索单独的⼀条链。深度优先搜索沿着HTML⽂件上的超链⾛到不能再深⼊为⽌,然后返回到某⼀个HTML⽂件,再继续选择该HTML⽂件中的其他超链。当不再有其他超链可选择时,说明搜索已经结束。优点是能遍历⼀个Web 站点或深层嵌套的⽂档集合;缺点是因为Web结构相当深,,有可能造成⼀旦进去,再也出不来的情况发⽣。 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)