3.1 网站树的爬起路径

news2024/9/30 21:20:23

一个网站往往由很多相互关联的网页组成,每个网页上都可能包含我们所要关心的数据,那么我们怎么样获取这些数据呢?显然我们必须穿梭于各个网页之间,那么按什么样的规则穿梭呢?常用的有深度优先广 度优先方法。为了说明这两种方法的工作过程,本节特意设计一个简单的网站。

1. Web服务网站


设计好books.html, program.html, database.html, netwwork.html, mysql.html, java.html, python.html等网页文件以utf-8的编码存储在文件夹,各个文件的内容如下:

  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>
        <ahref="mysql.html">MySQL数据库</a>
    </li>
</ul>
  1. program.html

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

<h3>计算机网络</h3>
  1. mysql.html

<h3>MySQL数据库</h3>
  1. python.html

<h3>Python程序设计</h3>
  1. java.html

<h3>Java程序设计</h3>

然后再用 FLask 设计一个 server.py 的 Web 程序来呈现它们:

import flask
import os
​
app=flask.Flask(__name__)
​
​
def getFile(fileName):
    data=b""
    ifos.path.exists(fileName):
        fobj=open(fileName, "rb")
        data=fobj.read()
        fobj.close()
    return data
​
​
@app.route("/")
defindex():
    return getFile("books.html")
​
​
@app.route("/<section>")
def process(section):
    data=""
    if section!="":
        data=getFile(section)
    return data
​
​
if__name__=="__main__":
    app.run()
​

搭建完 web 网站,访问http://127.0.0.1:5000网址后执行 index 函数,返回 books.html的网页


这些网页的结构实际上是一棵树:


2. 递归程序爬取数据


设计一个客户端程序client.py爬取这个网站各个网页的<h3>的标题值,

设计的思想如下:
1. 从books.html出发;
2.访问一个网页,获取<h3>标题;
3.获取这个网页中所有<a>超级链接的 href 值形成links列表;
4.循环links列表,对于每个链接link都指向另外一个网页,递归回到 2
5.继续links的下一个link,直到遍历所有link为止;

因此程序是一个递归调用得过程,

客户端程序 client.py 如下:

from bs4 import BeautifulSoup
import urllib.request
​
​
def spider(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
            # print(url)
            spider(url)
    except Exceptionas err:
        print(err)
​
​
start_url="http://127.0.0.1:5000"
spider(start_url)
print("The End")
​

运行结果如下:

显然这种递归程序都是采用深度优先得方法遍历树。

3. 深度优先爬取数据


如果不使用递归程序实现深度优先的顺序爬取网站数据,也可以设计一个Stack 来完成。Python中的列表list就是一个栈,很容易设计自己的一个栈Stack类:

class Stack:
    def __init__(self):
        self.st= []
​
    def pop(self):  # 出栈
        return self.st.pop()
        # pop([index=-1]) 默认弹出的是列表的最后一个元素。
​
    def push(self, obj):  # 入栈
        self.st.append(obj)
​
    def empty(self):  # 判断栈是否为空
        return len(self.st) ==0

采用 Stack 类后可以设计深度优先的顺序爬取数据的客户端程序的思想如下:

第一个url入栈;
如果栈为空程序结束,如不为空,出栈一个url,爬取它的<h3>标题值;
获取url站点的所有超级链接<a>的 href 值,组成链接列表links,把这些链接全部压栈;
回到 2

客户端程序 client2.py 如下:

# 深度优先爬取数据,使用list实现栈类,实现网站数据的爬取
import urllib.request
from bs4 import BeautifulSoup
​
​
class Stack:
    def __init__(self):
        self.st= []
​
    def pop(self):  # 出栈
        return self.st.pop()  # 与广度相比,出栈最后一个元素
        # pop([index=-1]) 默认弹出的是列表的最后一个元素。
​
    def push(self, obj):  # 入栈
        self.st.append(obj)
​
    def empty(self):  # 判断栈是否为空
        return len(self.st) ==0
​
​
def spider(url):
    stack=Stack()
    stack.push(url)
    while not stack.empty():
        url=stack.pop()
        try:
            data=urllib.request.urlopen(url)
            data=data.read().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 Exceptionas err:
            print(err)
​
​
start_url="http://127.0.0.1:5000"
spider(start_url)
print("The End")
​

运行结果如下:


4. 广度优先爬取数据


遍历网站树还有一种广度优先的顺序,这要使用到队列,在Python中实现一个队列十分简单,Python中的列表list就是一个队列,很容易设计自己的一个队列Queue类:

class Queue:
    def __init__(self):
        self.st= []
​
    def fetch(self):  # 出列
        return self.st.pop(0) # 与深度优先相比
        # 弹出队列第一个元素(index=0)
​
    def enter(self, obj):  # 入列
        self.st.append(obj)
​
    def empty(self):  # 判断列是否为空
        return len(self.st) ==0

设计广度优先的顺序爬取数据的客户端程序的思想如下:

1. 第一个url入列;
2. 如果列空程序结束,如不为空出列一个url,爬取它的<h3>标题值;
3. 获取url站点的所有超级链接<a>的href值,组成链接列表links,把这些 链接全部入 队列
4. 回到 2

客户端程序 client3.py 如下:

# 广度优先爬取数据
from bs4 import BeautifulSoup
import urllib.request


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

    def fetch(self):  # 出列
        return self.st.pop(0)  # 与深度优先相比
        # 弹出队列第一个元素(index=0)

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

    def empty(self):  # 判断列是否为空
        return len(self.st) == 0


def spider(url):
    queue = Queue()
    queue.enter(url)
    while not queue.empty():
        url = queue.fetch()
        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
                queue.enter(url)
        except Exception as err:
            print(err)


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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/373187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

0402换元积分法-不定积分

文章目录1 第一类换元法1.1 定理11.2 例题1.2 常见凑微分形式1.2.1常见基本的导数公式的逆运算1.2.2被积函数含有三角函数2 第二类换元法2.1 定理22.2 常见第二换元代换方法2.2.1 三角代换-弦代换2.2.2 三角代换-切代换2.2.3 三角代换-割代换2.2.4 三角代换汇总2.2.5 倒代换2.2…

java基础系列(六) sleep()和wait() 区别

一.前言 关于并发编程这块, 线程的一些基础知识我们得搞明白, 本篇文章来说一下这两个方法的区别,对Android中的HandlerThread机制原理可以有更深的理解, HandlerThread源码理解,请查看笔者的这篇博客: HandlerThread源码理解_handlerthread 源码_broadview_java的博客-CSDN博…

requests库---(1)requests简介

目录&#xff1a;导读 request简介 requests安装 requests发送get请求 requests请求post 返回值其他内容 写在最后 在做接口测试&#xff0c;接口自动化测试的时候都会用到很多工具&#xff0c;如postman、jmeter、pytest等工具&#xff0c;除了这些工具外&#xff0c;我…

ESP32设备驱动-MAX30100心率监测传感器驱动

MAX30100心率监测传感器驱动 1、MAX30100介绍 MAX30100 是一款集成脉搏血氧饱和度和心率监测传感器解决方案。 它结合了两个 LED、一个光电探测器、优化的光学器件和低噪声模拟信号处理,以检测脉搏血氧饱和度和心率信号。 MAX30100 采用 1.8V 和 3.3V 电源供电,可通过软件…

单机模拟kafka分布式集群(演示生产、消费数据过程)

用单机搭建kafka伪分布式集群&#xff0c;其实集群的概念并不复杂 先说明一下&#xff0c;以下的每个服务启动后都需要新开一个终端来启动另外的服务(因为是集群&#xff0c;自然会用多个终端) 首先下载kafka 提取码&#xff1a;dvz4 或者直接去官网下载kafka_2.11-1.0.0.tgz t…

DevOps实战50讲-(1)彻底理解DevOps

持续坚持原创输出&#xff0c;点击蓝字关注我吧软件质量保障:所寫即所思&#xff5c;一个阿里质量人对测试的所感所悟。浅谈软件开发流程软件开发流程是从需求分析、设计、编码、测试到上线等一系列环节的步骤和活动。通常来说&#xff0c;软件开发流程可以分为以下几个阶段&am…

Vue3电商项目实战-商品详情模块7【21-商品详情-评价组件-头部渲染、22-商品详情-评价组件-实现列表】

文章目录21-商品详情-评价组件-头部渲染22-商品详情-评价组件-实现列表21-商品详情-评价组件-头部渲染 目的&#xff1a;根据后台返回的评价信息渲染评价头部内容。 yapi 平台可提供模拟接口&#xff0c;当后台接口未开发完毕或者没有数据的情况下&#xff0c;可以支持前端的开…

CentOS 7安装Docker并使用tomcat测试

文章目录环境准备Docker安装安装tomcat环境准备 CentOS 7以上版本linux内核版本需要在3.10以上&#xff0c;可通过uname -r 查看系统内核。 Docker安装 检查docker安装源 yum list docker yum安装docker &#xff1a; yum install docker.x86_64 启动 docker &#xff1a; s…

操作系统权限提升(十六)之绕过UAC提权-CVE-2019-1388 UAC提权

系列文章 操作系统权限提升(十二)之绕过UAC提权-Windows UAC概述 操作系统权限提升(十三)之绕过UAC提权-MSF和CS绕过UAC提权 操作系统权限提升(十四)之绕过UAC提权-基于白名单AutoElevate绕过UAC提权 操作系统权限提升(十五)之绕过UAC提权-基于白名单DLL劫持绕过UAC提权 注&a…

QML Item和Rectangle详解

1.Item和Rectangle Item类型是Qt Quick中所有可视项的基本类型。 Qt Quick中的所有可视项都继承Item。尽管Item对象没有视觉外观&#xff0c;但它定义了视觉项中常见的所有属性&#xff0c;例如x和y位置、宽度和高度、锚定和键处理支持。 Rectangle继承自Item&#xff0c;多…

数组初始化方式与decimal.InvalidOperation

数组初始化方式与decimal.InvalidOperation调用函数主函数: 数组声明不同带来的报错与否1. 报错decimal.InvalidOperation的数组初始化版本2. 可行的初始化版本输出结果1. 报错时的内容2. 正常的输出计算结果原因&#xff08;是否是数组与列表不同引起&#xff08;&#xff1f;…

因果推断10--一种大规模预算约束因果森林算法(LBCF)

论文&#xff1a;A large Budget-Constrained Causal Forest Algorithm 论文&#xff1a;http://export.arxiv.org/pdf/2201.12585v2.pdf 目录 0 摘要 1 介绍 2 问题的制定 3策略评价 4 方法 4.1现有方法的局限性。 4.2提出的LBCF算法 5验证 5.1合成数据 5.2离线生…

gitlab部署使用,jenkins部署使用

gitlab部署使用&#xff0c;jenkins部署使用gitlab下载gitlab安装gitlab使用gitlab设置中文修改管理员密码创建组,创建项目,创建用户jenkins下载jenkins安装jenkin使用jenkins更改管理员密码配置拉取代码配置登录gitlab拉取代码的账号密码配置项目配置gitlab仓库配置构建构建构…

动态分区分配计算

动态分区分配 内存连续分配管理分为&#xff1a; 单一连续分配固定分区分配动态分区分配&#xff08;本篇所讲&#xff09; 首次适应算法&#xff08;First Fit&#xff0c;FF&#xff09; 该算法又称最先适应算法&#xff0c;要求空闲分区按照首地址递增的顺序排列。 优点…

数据结构——树

深度优先/广度优先遍历深度优先&#xff1a;访问根节点对根节点的 children 挨个进行深度优先遍历const tree {val: "a",children: [{val: "b",children: [{val: "d",children: [],},{val: "e",children: [],},],},{val: "c&quo…

可靠性设计

目录 一、可靠性设计概述 二、冗余的类型 三、冗余系统的设计 1.N版本程序设计 2.恢复块设计 3.防卫式程序设计 4.双机容错 一、可靠性设计概述 可靠性指系统能够正常运行的概率。如何设计出一个具有高可靠性的系统呢&#xff1f;可以利用避错技术&#xff0c;容错技术…

【LeetCode】剑指 Offer 16. 数值的整数次方 p110 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/shu-zhi-de-zheng-shu-ci-fang-lcof/ 1. 题目介绍&#xff08;16. 数值的整数次方&#xff09; 实现 pow(x, n) &#xff0c;即计算 x 的 n 次幂函数&#xff08;即&#xff0c;xn&#xff09;。不得使用库函数&#xff0c;…

文献计量分析方法:Citespace安装教程

Citespace是一款由陈超美教授开发的可用于海量文献可视化分析的软件&#xff0c;可对Web of Science&#xff0c;Scopus&#xff0c;Pubmed&#xff0c;CNKI等数据库的海量文献进行主题、关键词&#xff0c;作者单位、合作网络&#xff0c;期刊、发表时间&#xff0c;文献被引等…

数据结构入门5-2(数和二叉树)

目录 注&#xff1a; 树的存储结构 1. 双亲表示法 2. 孩子表示法 3. 重要&#xff1a;孩子兄弟法&#xff08;二叉树表示法&#xff09; 森林与二叉树的转换 树和森林的遍历 1. 树的遍历 2. 森林的遍历 哈夫曼树及其应用 基本概念 哈夫曼树的构造算法 1. 构造过程 …

响应性基础API

一.什么是proxy和懒代理&#xff1f;什么是proxy?proxy对象是用于定义基本操作的自定义行为(如&#xff1a;属性查找&#xff0c;赋值&#xff0c;枚举&#xff0c;函数调用等等)。什么是懒代理&#xff1f;懒代理&#xff1a;在初始化的时候不会进行全部代理&#xff0c;而是…