3.2 网站图的爬取路径

深度优先与广度优先方法都是遍历树的一种方法,但是网站的各个网页 之间的关系未必是树的结构,它们可能组成一个复杂的图形结构,即有回路

如果在前面的网站中每个网页都加一条Home的语句,让每个网页都能回到主界面,那么网站的关系就是一个有回路的图

1. 复杂的 Web网站


  1. books.html

<h3>计算机</h3>
<ul>
    <li><a href="database.html">数据库</a></li>
    <li><a href="program.html">程序设计</a></li>
    <li><a href="network.html">计算机网络</a></li>
</ul>
  1. database.html

<h3>数据库</h3>
<ul>
    <li><a href="mysql.html">MySQL数据库</a></li>
</ul>
<a href="books.html">Home</a>
  1. program.html

<h3>程序设计</h3>
<ul>
    <li><a href="python.html">Python程序设计</a></li>
    <li><a href="java.html">Java程序设计</a></li>
</ul>
<a href="books.html">Home</a>
  1. network.html

<h3>计算机网络</h3>
<a href="books.html">Home</a>
  1. mysql.html

<h3>MySQL数据库</h3>
<a href="books.html">Home</a>
  1. python.html

<h3>Python程序设计</h3>
<a href="books.html">Home</a>
  1. java.html

<h3>Java程序设计</h3>
<a href="books.html">Home</a>

这时,深度优先与广度优先方法要做一点改进可以用一个 python 中的列表 urls ;来记住已经访问过的网站,如果一个网址 url 没有访问过就访问它,并把 url 加到 urls 中保存起来,如果 url 已经访问过就不再访问了,这样就可以避免形成回路,导致无限循环。

2. 改进深度优先客户端程序


假定给定图 G 的初始状态是所有顶点均未曾访问过。在 G 中任选一顶点 v 为初始出发点(圆点),则深度优先遍历可以定义如下:

  • 首先访问出发点v,并将其标记为已访问;

  • 然后依次从 v 触发搜索 v 的每个邻接点 w 。

  • 若 w 未被曾访问过,则以 w 为新的出发点继续进行深度优先遍历,直至图中所有和原点 v 有路径相通的顶点(以称为原点可达的顶点)均已被访问为止。

图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是 尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索 (Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图 的深度优先遍历,基本实现思想:

  • 访问顶点v;

  • 从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度 优先遍历;

  • 重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。

使用递归程序

改进客户端程序 client1.py 如下:

python">python"># 使用递归的程序
from bs4 import BeautifulSoup
import urllib.request


def spider(url):
    global urls  # 使用列表存储和标记已经访问过的节点
    if url not in urls:  # 未被访问过
        urls.append(url)
        try:
            data = urllib.request.urlopen(url)
            data = data.read()
            data = data.decode()
            soup = BeautifulSoup(data, "lxml")
            print(soup.find("h3").text)
            links = soup.select("a")
            for link in links:
                href = link["href"]
                url = start_url + "/" + href
                spider(url)
        except Exception as err:
            print(err)


start_url = "http://127.0.0.1:5000"
urls = []
spider(start_url)
print("The End")

使用栈的程序

改进客户端程序 client2.py 如下:

python">python"># 使用栈的程序
from bs4 import BeautifulSoup
import urllib.request


class Stack:
    def __init__(self):
        self.st = []

    def pop(self):
        return self.st.pop()

    def push(self, obj):
        self.st.append(obj)

    def empty(self):
        return len(self.st) == 0


def spider(url):
    global urls
    stack = Stack()
    stack.push(url)
    while not stack.empty():
        url = stack.pop()
        if url not in urls:
            urls.append(url)
            try:
                data = urllib.request.urlopen(url)
                data = data.read()
                data = data.decode()
                soup = BeautifulSoup(data, "lxml")
                print(soup.find("h3").text)
                links = soup.select("a")
                for i in range(len(links) - 1, -1, -1):
                    href = links[i]["href"]
                    url = start_url + "/" + href
                    stack.push(url)
            except Exception as err:
                print(err)


start_url = "http://127.0.0.1:5000"
urls = []
spider(start_url)
print("The End")

这两个程序结果一样,如下:

3. 改进广度优先客户端程序


图的广度优先遍历BFS算法是一个分层搜索的过程,和树的层序遍历算法类同,它也需要一个队列以保持遍历过的顶点顺序,以便按出队的顺序再去访问这些顶点的邻接顶点。基本实现思想:

(1)顶点v入队列。
(2)当队列非空时则继续执行,否则算法结束。
(3)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。
(4)查找顶点v的第一个邻接顶点col。
(5)若v的邻接顶点col未被访问过的,则col入队列。
(6)继续查找顶点v的另一个新的邻接顶点col,转到步骤(5)。直到 顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。

广度优先遍历图是以顶点v为起始点,由近至远,依次访问和v有路径相通 而且路径长度为1,2,……的顶点。为了使“先被访问顶点的邻接点”先 于“后被访问顶点的邻接点”被访问,需设置队列存储访问的顶点。

使用队列的程序

改进客户端程序 client3.py 如下:

python">python"># 使用队列的程序
from bs4 import BeautifulSoup
import urllib.request


class Queue:
    def __init__(self):
        self.st = []

    def fetch(self):
        return self.st.pop(0)  # 出队列,弹出列表头的元素

    def enter(self, obj):  # 入队
        self.st.append(obj)

    def empty(self):
        return len(self.st) == 0


def spider(url):
    global urls
    queue = Queue()
    queue.enter(url)
    while not queue.empty():
        url = queue.fetch()
        if url not in urls:
            try:
                urls.append(url)
                data = urllib.request.urlopen(url)
                data = data.read()
                data = data.decode()
                soup = BeautifulSoup(data, "lxml")
                print(soup.find("h3").text)
                links = soup.select("a")
                for link in links:
                    href = link["href"]
                    url = start_url + "/" + href
                    if url not in urls:
                        queue.enter(url)
            except Exception as err:
                print(err)


start_url = "http://127.0.0.1:5000"
urls = []
spider(start_url)
print("The End")

程序运行结果如下:


http://www.niftyadmin.cn/n/101804.html

相关文章

vue中render函数的作用和参数(vue2中render函数用法)

render 函数是 Vue2.x 新增的一个函数、主要用来提升节点的性能&#xff0c;它是基于 JavaScript 计算。使用 Render 函数将 Template 里面的节点解析成虚拟的 Dom 。Vue 推荐在绝大多数情况下使用模板来创建 HTML。然而在一些场景中&#xff0c;需要 JavaScript 的完全编程能力…

C语言学习及复习笔记-【14】C文件读写

14 C文件读写 14.1打开文件 您可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件&#xff0c;这个调用会初始化类型 FILE 的一个对象&#xff0c;类型 FILE包含了所有用来控制流的必要的信息。下面是这个函数调用的原型&#xff1a; FILE *fopen( const char…

Facebook广告投放运营中的关键成功因素是什么?

在当今数字化的时代&#xff0c;广告投放已经成为了各种企业获取市场份额和增加品牌曝光的重要手段之一。Facebook作为全球最大的社交媒体平台之一&#xff0c;其广告投放运营的成功&#xff0c;将直接影响企业的品牌推广和市场营销效果。本文将探讨Facebook广告投放运营中的关…

Linux学习(8.8)文件与目录管理重点总结回顾

目录 权限与命令之间的关系 重点回顾 以下内容转载自鸟哥的Linux私房菜 权限与命令之间的关系 一、让使用者能进入某目录成为『可工作目录』的基本权限为何&#xff1a; 可使用的命令&#xff1a;例如 cd 等变换工作目录的命令&#xff1b;目录所需权限&#xff1a;使用者…

Boosting Crowd Counting via Multifaceted Attention之人群密度估计实践

这周闲来无事&#xff0c;看到一篇前不久刚发表的文章&#xff0c;是做密集人群密度估计的&#xff0c;这块我之前虽然也做过&#xff0c;但是主要是基于检测的方式实现的&#xff0c;这里提出来的方法还是比较有意思的&#xff0c;就拿来实践一下。论文在这里&#xff0c;感兴…

如何使用Kafka可靠地发送消息-《Kafka权威指南(第二版)》阅读笔记

可靠性是系统而不是某个独立组件的一个属性&#xff0c;所以&#xff0c;在讨论Kafka的可靠性保证时&#xff0c;需要从系统的整体出发。说到可靠性&#xff0c;那些与Kafka集成的系统与Kafka本身一样重要。正因为可靠性是系统层面的概念&#xff0c;所以它不只是某个个体的事情…

SOEM 源码解析 ecx_init_redundant

/* Initialise lib in redundant NIC mode* 在冗余网卡模式下初始化lib库* param[in] context context struct* 上下文结构体* param[in] redport pointer to redport, redundant port data* 指向冗余端口的指针&#xff…

不需要高深技术,只需要Python:创建一个可定制的HTTP服务器!

目录 1、编写服务端代码,命名为httpserver.py文件。 2、编写网页htmlcss文件&#xff0c;命名为index.html和style.css文件。 3、复制htmlcss到服务端py文件同一文件夹下。 4、运行服务端程序。 5、浏览器中输入localhost:8080显示如下&#xff1a; 要编写一个简单的能发布…