广度优先搜索与网络爬虫

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

 

posted @ 2020-07-24 16:17  Ayeah~夭夭  阅读(636)  评论(0编辑  收藏  举报