python网络爬虫基础:html基础概念与遍历文档树
开始之前导入html段落,同时下载好本节将用到的库。下载方式为:pip install beautifulsoup4
一点碎碎念:为什么install后面的不是bs4也不是BeautifulSoup?
html_doc = """
<html><head><title>The Dormouse's story</title></head><body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
一、html基础与BeautifulSoup解析过程
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
首先导入BeautifulSoup库并对html文档对象进行解析。
HTML解析器把这段字符串转换成一连串的事件:打开<html>标签,打开<head>标签,打开<title>标签,添加一段字符串,关闭<title>标签等等。
解析后的html文档大体上可分为四类对象:Tag(标签)即 <html> <title> 等,一个Tag可能包含多个字符串或其它的Tag,称为子节点,字符串节点没有子节点。还有NavigableString(标签内文字)、Comment(注释)以及BeautifulSoup(文档整体)。
BeautifulSoup对象本身也是一个特殊的Tag,可视为html标签,只有一个。可以非严格认为soup.html==soup。
二、BeautifulSoup对象方法
前情提要:没有索引到实际段落会返回None,前提是上个节点有索引,因为对None继续索引会报错。此处要结合后续代码理解。
1.子孙节点
print(soup.head)
# <head><title>The Dormouse's story</title></head>
print(soup.head.title)
# <title>The Dormouse's story</title>
首先是通过点取属性的方式获取相应的文档标签,此方式只能获取到匹配到的第一个tag,同时支持链式操作,在输出结果中会保留匹配到的tag(这里与以下contents等方法区分)。
print(soup.head.contents)
# [<title>The Dormouse's story</title>]
print(soup.head.contents[0].contents)
# ["The Dormouse's story"]
contents方法用于获取某个tag内的所有(直接)子节点,返回列表,在输出结果中不会保留匹配到的tag。
for child in soup.children:print(child)
for child in soup.descendants:print(child)
children方法的作用与结果类似于contents,只不过返回的是生成器对象。descendants 方法用于获取某个tag内的所有子孙节点,同样返回生成器对象。children方法与descendants 方法均不会在输出结果中保留匹配到的tag。
到底什么叫“在输出结果中不保留匹配到的tag”呢?以下例子帮助理解。
for child in soup.head.descendants:print(child)print(child.name)
# <title>The Dormouse's story</title>
# title
# The Dormouse's story
# None
2.字符串节点
print(soup.head.string)
# The Dormouse's story
如果tag有一个NavigableString类型子节点(重点是只有一个),那么这个tag可以使用string方法得到该子节点(即字符串)。
如果一个tag仅有一个子节点,该子节点只有一个NavigableString 类型子节点,那么这个tag也可以使用string方法直接获取到内部字符串,同理,文档树深度可无限大,但是直到NavigableString子节点结束时只有一条枝干(即宽度始终为1)才能调用。
for string in soup.strings:print(repr(string))
for string in soup.stripped_strings:print(repr(string))
如果tag内包含多个字符串可以使用strings或者stripped_strings方法获取,同样为生成器对象。其中stripped_strings方法会过滤掉字符串中的空白内容:全部是空格的行会被忽略掉,段首和段末的空白会被删除。
3.父节点
大部分tag或字符串都有父节点:被包含在某个tag中,此tag即为其父节点。
title_tag = soup.title
print(title_tag.parent)
# <head><title>The Dormouse's story</title></head>
print(title_tag.string.parent)
# <title>The Dormouse's story</title>
通过parent方法可获取到某个元素的父节点。
<html>的父节点是 BeautifulSoup 对象。以下为树结构辨析,帮助理解:
print(type(soup.html.parent.parent))
# <class 'NoneType'>
print(type(soup.html.parent))
# <class 'bs4.BeautifulSoup'>
print(type(soup.html))
# <class 'bs4.element.Tag'>
print(type(soup))
# <class 'bs4.BeautifulSoup'>
通过parents方法可以递归得到元素的所有父辈节点,同样是生成器对象。
link = soup.a
for parent in link.parents:print(parent.name)
# p
# body
# html
# [document]
# 其中soup.name结果即为[document]
4.兄弟节点
ibling_soup = BeautifulSoup("<a><b>text1</b><c>text2</c></a>", 'html.parser')
print(sibling_soup.b.next_sibling)
# <c>text2</c>
print(sibling_soup.c.previous_sibling)
# <b>text1</b>
print(sibling_soup.b.previous_sibling)
# None
print(sibling_soup.c.next_sibling)
# None
兄弟节点定义:父节点相同的节点。next_sibling与previous_sibling分别表示“下一个兄弟节点”与“上一个兄弟节点”。从实际情况来说文档中tag的兄弟节点往往会出现字符串或者空白,这是由于解析html时标签之间的空白和换行也会被解析为字符串节点,其父节点与同级标签相同,符合兄弟节点定义。一般来说调用多次后总会得到想要的值,支持链式调用。
for sibling in soup.a.next_siblings:print(repr(sibling))
for sibling in soup.find(id="link3").previous_siblings:print(repr(sibling))
通过next_siblings和previous_siblings属性可以对当前节点的兄弟节点迭代输出,且同样是生成器对象。
last_a_tag = soup.find("a", id="link3")
'''
last_a_tag周围内容如下
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
'''
print(last_a_tag.next_sibling)
# ;
# and they lived at the bottom of a well.
print(last_a_tag.next_element)
# Tillie
# 解释 :解析器先进入<a>标签,然后是字符串“Tillie”,然后关闭</a>标签,然后是分号和剩余部分.所以next_element输出Tillie
next_element与previous_element类似于next_sibling与previous_sibling,不同的是前者是指向解析过程中下一个或上一个被解析的对象,这里需要了解BeautifulSoup的解析过程,前文已有提过不在赘述。
last_a_tag = soup.find("a", id="link3")
for element in last_a_tag.next_elements:print(repr(element))
# 'Tillie'
# ';\nand they lived at the bottom of a well.'
# '\n'
# <p class="story">...</p>
# '...'
# '\n'
next_elements和previous_elements为逐步解析,依旧是生成器对象。
相关文章:
python网络爬虫基础:html基础概念与遍历文档树
开始之前导入html段落,同时下载好本节将用到的库。下载方式为:pip install beautifulsoup4 一点碎碎念:为什么install后面的不是bs4也不是BeautifulSoup? html_doc """ <html><head><title>The…...

【已解决】MacOS上VMware Fusion虚拟机打不开的解决方法
在使用VMware Fusion时,不少用户可能会遇到虚拟机无法打开的问题。本文将为大家提供一个简单有效的解决方法,只需删除一个文件,即可轻松解决这一问题。 一、问题现象 在MacOS系统上,使用VMware Fusion运行虚拟机时,有…...

经典视觉神经网络1 CNN
一、概述 输入的图像都很大,使用全连接网络的话,计算的代价较高,图像也很难保留原本特征。 卷积神经网络(Convolutional Neural Network,CNN)是一种专门用于处理具有网格状结构数据的深度学习模型。主要应用…...

一些硬件知识【2024/12/6】
MP6924A: 正点原子加热台拆解: PMOS 相比 NMOS 的缺点: 缺点描述迁移率低PMOS 中的空穴迁移率约为电子迁移率的 1/3 到 1/2,导致导通电流较低。开关速度慢由于迁移率较低,PMOS 的开关速度比 NMOS 慢,不适合高速数字电…...
网络安全法-网络安全支持与促进
第二章 网络安全支持与促进 第十五条 国家建立和完善网络安全标准体系。国务院标准化行政主管部门和国务院其他有关部门根据各自的职责,组织制定并适时修订有关网络安全管理以及网络产品、服务和运行安全的国家标准、行业标准。 国家支持企业、研究机构、高等学…...

【Docker】如何在Docker中配置防火墙规则?
Docker本身并不直接管理防火墙规则;它依赖于主机系统的防火墙设置。不过,Docker在启动容器时会自动配置一些iptables规则来管理容器网络流量。如果你需要更细粒度地控制进出容器的流量,你需要在主机系统上配置防火墙规则。以下是如何在Linux主…...

Cesium 问题: 添加billboard后移动或缩放地球,标记点位置会左右偏移
文章目录 问题分析原先的:添加属性——解决漂移移动问题产生新的问题:所选的经纬度坐标和应放置的位置有偏差解决坐标位置偏差的问题完整代码问题 添加 billboard 后, 分析 原先的: // 图标加载 function addStation ({lon, lat, el, testName...
使用Python3 连接操作 OceanBase数据库
注:使用Python3 连接 OceanBase数据库,可通过安装 PyMySQL驱动包来实现。 本次测试是在一台安装部署OBD的OceanBase 测试linux服务器上,通过python来远程操作OceanBase数据库。 一、Linux服务器通过Python3连接OceanBase数据库 1.1 安装pyth…...

SpringBoot该怎么使用Neo4j - 优化篇
文章目录 前言实体工具使用 前言 上一篇中,我们的Cypher都用的是字符串,字符串拼接简单,但存在写错的风险,对于一些比较懒的开发者,甚至觉得之间写字符串还更自在快速,也确实,但如果在后期需要…...

Flutter如何调用java接口如何导入java包
文章目录 1. Flutter 能直接调用 Java 的接口吗?如何调用 Java 接口? 2. Flutter 能导入 Java 的包吗?步骤: 总结 在 Flutter 中,虽然 Dart 是主要的开发语言,但你可以通过**平台通道(Platform …...

Redis 数据结构(一)—字符串、哈希表、列表
Redis(版本7.0)的数据结构主要包括字符串(String)、哈希表(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)、超日志(…...

day1:ansible
ansible-doc <module_name>(如果没有网,那这个超级有用) 这个很有用,用来查单个模块的文档。 ansible-doc -l 列出所有模块 ansible-doc -s <module_name> 查看更详细的模块文档。 ansible-doc --help 使用 --help …...
如何设置Java爬虫的异常处理?
在Java爬虫中设置异常处理是非常重要的,因为网络请求可能会遇到各种问题,如连接超时、服务器错误、网络中断等。通过合理的异常处理,可以确保爬虫的稳定性和健壮性。以下是如何在Java爬虫中设置异常处理的步骤和最佳实践: 1. 使用…...
阿里云盘permission denied
问题是执行 ./aliyunpan 时遇到了 Permission denied 的错误。这通常是因为文件没有执行权限。以下是解决问题的步骤: 检查文件权限 运行以下命令检查文件的权限: ls -l aliyunpan输出中会看到类似以下内容: -rw-r--r-- 1 user group 123…...
在 Ubuntu 24 上安装 Redis 7.0.15 并配置允许所有 IP 访问
前提条件 一台运行 Ubuntu 24 的服务器拥有 sudo 权限的用户 步骤一:更新系统包 首先,确保系统包是最新的,以避免潜在的依赖问题。 sudo apt update sudo apt upgrade -y步骤二:安装编译 Redis 所需的依赖 Redis 需要一些编译…...
构建高效可靠的分布式推理系统:深入解析控制器与模型服务的协同工作
在现代互联网应用中,随着用户需求的增长和技术的进步,单一服务器已经难以满足大规模并发请求的需求。为了提升系统的性能和可靠性,开发者们越来越多地采用分布式架构。本文将结合具体的代码示例,深入浅出地探讨如何构建一个高效的分布式推理系统,并详细解析其中的关键组件…...

springboot394疫情居家办公系统(论文+源码)_kaic
摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统疫情居家办公系统信息管理难度大,容错率低&a…...

共筑数字安全防线,2024开源和软件安全沙龙即将启幕
随着数字化转型进程的加快以及开源代码的广泛应用,开源凭借平等、开放、协作、共享的优秀创作模式,逐渐成为推动数字技术创新、加速传统行业转型升级的重要模式。但随着软件供应链日趋复杂多元,使得其安全风险不断加剧,针对软件供…...
后端报错: message: “For input string: \“\““
这个错误信息表明后端尝试将一个空字符串 "" 转换为某种数值类型(如整数、长整型等),但转换失败了。在许多编程语言中,如果你试图解析一个非数字的字符串(在这个情况下是一个空字符串)为数值类型…...

39 矩阵置零
39 矩阵置零 39.1 矩阵置零解决方案 解题思路: 利用第一行和第一列标记: 使用两个标记变量,rowZero和colZero,来判断第一行和第一列是否需要置零。遍历矩阵从(1,1)开始,如果某个元素是0,则标记该行和该列…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

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