zoukankan      html  css  js  c++  java
  • 爬虫的广度优先和深度优先算法

    广度优先算法介绍

      整个的广度优先爬虫过程就是从一系列的种子节点开始,把这些网页中的"子节点"(也就是超链接)提取出来,放入队列中依次进行抓取。被处理过的链接需要放 入一张表(通常称为Visited表)中。每次新处理一个链接之前,需要查看这个链接是否已经存在于Visited表中。如果存在,证明链接已经处理过, 跳过,不做处理,否则进行下一步处理。

      初始的URL地址是爬虫系统中提供的种子URL(一般在系统的配置文件中指定)。当解析这些种子URL所表示的网页时,会产生新的URL(比如从页面中的<a href= "http://www.admin.com "中提取出http://www.admin.com 这个链接)。然后,进行以下工作:

    1. 把解析出的链接和Visited表中的链接进行比较,若Visited表中不存在此链接,表示其未被访问过。
    2. 把链接放入TODO表中。
    3. 处理完毕后,再次从TODO表中取得一条链接,直接放入Visited表中。
    4. 针对这个链接所表示的网页,继续上述过程。如此循环往复。

    广度优先遍历是爬虫中使用最广泛的一种爬虫策略,之所以使用广度优先搜索策略,主要原因有三点:

    • 重要的网页往往离种子比较近,例如我们打开新闻网站的时候往往是最热门的新闻,随着不断的深入冲浪,所看到的网页的重要性越来越低。
    • 万维网的实际深度最多能达到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)
  • 相关阅读:
    《安富莱嵌入式周报》第222期:2021.07.19--2021.07.25
    嵌入式新闻早班车-第14期
    状态压缩动态规划【DP】
    Spring事务
    设计模式--组合模式
    设计模式--状态模式
    设计模式--中介者模式
    设计模式--责任链模式
    设计模式--享元模式
    设计模式--委派模式
  • 原文地址:https://www.cnblogs.com/wangshuyi/p/6734523.html
Copyright © 2011-2022 走看看