3.2 网站图的爬取路径
深度优先与广度优先方法都是遍历树的一种方法,但是网站的各个网页 之间的关系未必是树的结构,它们可能组成一个复杂的图形结构,即有回路。
如果在前面的网站中每个网页都加一条Home的语句,让每个网页都能回到主界面,那么网站的关系就是一个有回路的图。
1. 复杂的 Web网站
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>
database.html
<h3>数据库</h3>
<ul><li><a href="mysql.html">MySQL数据库</a></li>
</ul>
<a href="books.html">Home</a>
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>
network.html
<h3>计算机网络</h3>
<a href="books.html">Home</a>
mysql.html
<h3>MySQL数据库</h3>
<a href="books.html">Home</a>
python.html
<h3>Python程序设计</h3>
<a href="books.html">Home</a>
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 如下:
# 使用递归的程序
from bs4 import BeautifulSoup
import urllib.requestdef 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 + "/" + hrefspider(url)except Exception as err:print(err)start_url = "http://127.0.0.1:5000"
urls = []
spider(start_url)
print("The End")
使用栈的程序
改进客户端程序 client2.py 如下:
# 使用栈的程序
from bs4 import BeautifulSoup
import urllib.requestclass 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) == 0def spider(url):global urlsstack = 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 + "/" + hrefstack.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 如下:
# 使用队列的程序
from bs4 import BeautifulSoup
import urllib.requestclass 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) == 0def spider(url):global urlsqueue = 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 + "/" + hrefif 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")
程序运行结果如下:

相关文章:

3.2 网站图的爬取路径
深度优先与广度优先方法都是遍历树的一种方法,但是网站的各个网页 之间的关系未必是树的结构,它们可能组成一个复杂的图形结构,即有回路。如果在前面的网站中每个网页都加一条Home的语句,让每个网页都能回到主界面,那么…...
《SQL基础》12. SQL优化
SQL优化SQL优化数据插入insert优化大批量插入数据主键优化order by优化group by优化limit优化count优化count用法update优化SQL优化 数据插入 insert优化 如果我们需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化。 批量插入手动控制事务主键顺…...
fork之后是子进程先执行还是父进程先执行
CFS(完全公平调度器)是Linux内核2.6.23版本开始采用的进程调度器,它的基本原理是这样的:设定一个调度周期(sched_latency_ns),目标是让每个进程在这个周期内至少有机会运行一次,换一种说法就是每个进程等待CPU的时间最长不超过这个…...
2023年java初级面试题(5道)
一、两个对象值相同(x.equals(y) true),但却可有不同的hash code,这句话对不对?答:不对,如果两个对象x和y满足x.equals(y) true,它们的哈希码(hash code)应当相同。Java对于eqauls…...

【内网安全】——Linux权限维持
作者名:白昼安全主页面链接: 主页传送门创作初心: 以后赚大钱座右铭: 不要让时代的悲哀成为你的悲哀专研方向: web安全,后渗透技术每日鸡汤: 钱至少对于现在的我来说,的确是万能的在…...
Linux 真实使用内存计算
获取Linux内存信息,可通过cat /proc/meminfo查看,比如,Ubuntu 20.04.5 LTS上会显示以下信息: leoyaDESKTOP-LMR:~$ cat /proc/meminfo MemTotal: 16017572 kB MemFree: 15637472 kB MemAvailable: 15533140 kB Bu…...
Unity Jobsystem ECS
简介随着ECS的加入,Unity基本上改变了软件开发方面的大部分方法。ECS的加入预示着OOP方法的结束。随着实体组件系统ECS的到来,我们在Unity开发中曾使用的大量实践方法都必须进行改变以适应ECS,也许不少人需要些时间适应ECS的使用,…...
Java中创建线程有哪几种方式
1.继承Thread类 总结:通过继承 Thread 类,重写 run() 方法,而不是 start() 方法 Thread 类底层实现 Runnable 接口类只能单继承 接口可以多继承2.实现Runnable接口 总结:通过实现 Runnable 接口,实现 run() 方法,依然…...

C++【string类用法详细介绍string类模拟实现解析】
文章目录string 类用法介绍及模拟实现一、string介绍二、string类常用接口1. string类对象的常见构造接口2.string类对象的常见容量接口3.string类对象的常见修改接口4. string类对象的常见访问及遍历接口5.string其他接口1.不常用查找接口2.字符替换3.字符串拼接4.字符串排序5…...

常见的开发模型和测试模型
软件的生命周期软件开发阶段的生命周期需求分析->计划->设计->编码->测试->运维软件测试阶段的生命周期需求分期->测试计划->测试设计与开发->执行测试->测试评估开发模型瀑布模型可以看到,这个模型和我们上面的软件开发生命周期很相似采用的是线性…...
印度和印度尼西亚有什么关系吗?
印度和印度尼西亚,这两个国家很多人都比较熟悉。因为两国都是人口大国,而且经济总量也比较高,在全球还是有很大影响的。不过很多人刚看到这两个国家的时候,都会觉得这两个国家肯定有什么关系,要不然国名也不会这么像。…...

单调栈(C/C++)
目录 1. 单调栈的定义 2. 单调栈的常见用途 3. 案例分析 3.1 暴力解法 3.2 单调栈 4. 单调栈总结 1. 单调栈的定义 单调栈顾名思义,就是栈内的元素是单调的。根据栈内元素的单调性的不同,可以分为: 单调递增栈:栈内元素是单…...

算法设计与智能计算 || 专题一: 算法基础
专题一: 算法基础 文章目录专题一: 算法基础1. 算法的定义及特点1.1 算法的基本特征1.2 算法的基本要素1.3 算法的评定2 算法常见执行方法2.1 判断语句2.2 循环语句2.3 综合运用3. 计算复杂度4. 代码的重用5. 类函数的定义与使用5.1 定义类5.2 调用类函数1. 算法的定义及特点 …...

用javascript分类刷leetcode13.单调栈(图文视频讲解)
239. 滑动窗口最大值 (hard) 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1: 输入:nums [1,…...

英语基础语法学习(B站英语电力公司)
1. 句子结构 五大基本句型: 主谓主谓宾主谓宾宾主谓宾宾补主系表 谓语: 一般来说,谓语是指主语发出的动作。(动词)但是很多句子是没有动作的,但是还是必须要有谓语。(此时需要be动词&#x…...

【计算机网络】网络层IP协议
文章目录一、认识IP协议二、IP协议头部格式三、IP地址划分1. IP地址分类2. 子网划分四、IP地址数量危机1. IP地址的数量限制2. NAT技术五、私网IP和公网IP六、路由1. 认识路由2. 路由表生成算法一、认识IP协议 IP协议是Internet Protocol(互联网协议)的…...
Eclipse快捷键大全
编辑类快捷键Ctrl1: 快速修复(最经典的快捷键, 可以解决很多问题, 比如import类、try catch包围等)CtrlShiftF: 格式化当前代码CtrlShiftM: 添加类的import导入CtrlShiftO: 组织类的导入(既有CtrlShiftM的作用,又可以去除没用的导入, 一般用这个导入包)CtrlY: 重做(与CtrlZ相反…...

JavaScript 高级2 :构造函数和原型 d331702016e84f54b3594ae05e0eeac
JavaScript 高级2 :构造函数和原型 Date: January 16, 2023 Text: 构造函数和原型、继承、ES5中的新增方法 目标 能够使用构造函数创建对象 能够说出原型的作用 能够说出访问对象成员的规则 能够使用 ES5新增的一些方法 构造函数和原型 概述 在典型的 OOP 的…...
maven-war-plugin插件 overlays maven-war-plugin翻译
说明 翻译maven-war-plugin插件的部分内容 官方地址为:https://maven.apache.org/plugins/maven-war-plugin/index.html Overview 概述 Introduction 介绍 Apache Maven WAR Plugin apache maven war 插件 The WAR Plugin is responsible for collecting all artifa…...

【数据结构】初识二叉树(二叉树的入门知识)
初识二叉树一、树概念及结构1、树的概念2、树的相关概念3、树的表示4、树在实际中的运用(表示文件系统的目录树结构)二、二叉树概念及结构1、概念2、特殊的二叉树3、二叉树的性质4、二叉树的存储结构三、结语一、树概念及结构 1、树的概念 树是一种非线…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...