广度优先搜索与网络爬虫
1.网页搜索与爬虫简介
为了对互联网中的有效信息进行高效获取,可以依托例如“阅读更多”链接对文章建立有向图,其中的点代表文章,有向边是文章之间的链接关系,从而不断深入获取文章的相关文章簇。之后就可以对图进行遍历获取文章。
广度优先搜索策略爬虫现在是使用最多的搜索策略。它的工作原理是,数据获取模块的爬虫在抓取文章页时,优先抓取当前层次范围的“阅读更多”,完成本层遍历后再抓取“阅读更多”数据,直到满足条件时结束抓取。
深度优先搜索策略爬虫是指从某篇文章为起点,根据文章提供的“阅读更多”,并沿着URL继续向下搜索并抓取,不断执行直到完整的执行完本条URL 线路后返回抓取源头处,开始新的一轮线路搜索和抓取任务。
深度优先遍历的优点是设计简单,但是这种遍历的最大缺陷是:由于顶层文章价值最高,往下逐渐减弱。无限制的深度挖取,挖取的文章的价值不会太大。
2.广度优先搜索进行网络爬虫
广度优先搜索是爬虫中使用最广泛的一种策略,主要原因有以下三点:
(1)重要的网页往往离种子比较近,例如我们打开新闻网站时首先看到的往往是最热门的新闻,随着不算的深入冲浪,所看到的的网页(新闻)的重要性越来越低。
(2)万维网的实际深度最多能达到17层,但到达某个网页总存在一条很短的路径。而广度优先搜索会以最快的速度到达这个网页。
(3)广度优先有利于多爬虫的合作抓取,多爬虫合作通常先抓取站内链接,抓取的封闭性很强。
例子:爬取新浪微博的链接,一级一级展开
from bs4 import BeautifulSoup import requests import re #自定义队列类 class linkQuence: def __init__(self): # 已访问的url集合 self.visted = [] # 待访问的url集合 self.unVisited = [] # 获取访问过的url队列 def getVisitedUrl(self): return self.visted # 获取未访问的url队列 def getUnvisitedUrl(self): return self.unVisited # 添加到访问过得url队列中 def addVisitedUrl(self, url): self.visted.append(url) # 移除访问过得url def removeVisitedUrl(self, url): self.visted.remove(url) # 未访问过得url出队列 def unVisitedUrlDeQuence(self): try: return self.unVisited.pop() except: return None # 保证每个url只被访问一次 def addUnvisitedUrl(self, url): if url != "" and url not in self.visted and url not in self.unVisited: self.unVisited.insert(0, url) # 获得已访问的url数目 def getVisitedUrlCount(self): return len(self.visted) # 获得未访问的url数目 def getUnvistedUrlCount(self): return len(self.unVisited) # 判断未访问的url队列是否为空 def unVisitedUrlsEnmpy(self): return len(self.unVisited) == 0 class MyCrawler: def __init__(self, seeds): # 初始化当前抓取的深度 self.current_deepth = 1 # 使用种子初始化url队列 self.linkQuence = linkQuence() if isinstance(seeds, str): self.linkQuence.addUnvisitedUrl(seeds) if isinstance(seeds, list): for i in seeds: self.linkQuence.addUnvisitedUrl(i) print("Add the seeds url %s to the unvisited url list" % str(self.linkQuence.unVisited)) # 抓取过程主函数 def crawling(self, seeds, crawl_deepth): # 循环条件:抓取深度不超过crawl_deepth while self.current_deepth <= crawl_deepth: # 循环条件:待抓取的链接不空 while not self.linkQuence.unVisitedUrlsEnmpy(): # 队头url出队列 visitUrl = self.linkQuence.unVisitedUrlDeQuence() print("Pop out one url \"%s\" from unvisited url list" % visitUrl) if visitUrl is None or visitUrl == "": continue # 获取超链接 links = self.getHyperLinks(visitUrl) #获取visiturl中的所有超链接 print("Get %d new links" % len(links)) # 将visitUrl放入已访问的url中 self.linkQuence.addVisitedUrl(visitUrl) print("Visited url count: " + str(self.linkQuence.getVisitedUrlCount())) print("Visited deepth: " + str(self.current_deepth)) # 未访问的url入列 也就是visiturl网页中的所有超链接links for link in links: self.linkQuence.addUnvisitedUrl(link) print("%d unvisited links:" % len(self.linkQuence.getUnvisitedUrl())) self.current_deepth += 1 # 获取源码中得超链接 def getHyperLinks(self, url): links = [] data = self.getPageSource(url) #获取url网页源码 soup = BeautifulSoup(data,'html.parser') a = soup.findAll("a", {"href": re.compile('^http|^/')}) for i in a: if i["href"].find("http://") != -1: links.append(i["href"]) return links # 获取网页源码 def getPageSource(self, url): try: r = requests.get(url) r.raise_for_status() r.encoding = 'utf-8' return r.text except: return '' def main(seeds, crawl_deepth): craw = MyCrawler(seeds) craw.crawling(seeds, crawl_deepth) #爬取新浪微博超链接,深度为3 if __name__ == '__main__': main("http://www.sina.com.cn", 3)
参考https://blog.csdn.net/weixin_34613450/article/details/72810595