当前位置: 首页 > news >正文

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段落&#xff0c;同时下载好本节将用到的库。下载方式为&#xff1a;pip install beautifulsoup4 一点碎碎念&#xff1a;为什么install后面的不是bs4也不是BeautifulSoup&#xff1f; html_doc """ <html><head><title>The…...

【已解决】MacOS上VMware Fusion虚拟机打不开的解决方法

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

经典视觉神经网络1 CNN

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

一些硬件知识【2024/12/6】

MP6924A: 正点原子加热台拆解&#xff1a; PMOS 相比 NMOS 的缺点&#xff1a; 缺点描述迁移率低PMOS 中的空穴迁移率约为电子迁移率的 1/3 到 1/2&#xff0c;导致导通电流较低。开关速度慢由于迁移率较低&#xff0c;PMOS 的开关速度比 NMOS 慢&#xff0c;不适合高速数字电…...

网络安全法-网络安全支持与促进

第二章 网络安全支持与促进 第十五条 国家建立和完善网络安全标准体系。国务院标准化行政主管部门和国务院其他有关部门根据各自的职责&#xff0c;组织制定并适时修订有关网络安全管理以及网络产品、服务和运行安全的国家标准、行业标准。 国家支持企业、研究机构、高等学…...

【Docker】如何在Docker中配置防火墙规则?

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

Cesium 问题: 添加billboard后移动或缩放地球,标记点位置会左右偏移

文章目录 问题分析原先的:添加属性——解决漂移移动问题产生新的问题:所选的经纬度坐标和应放置的位置有偏差解决坐标位置偏差的问题完整代码问题 添加 billboard 后, 分析 原先的: // 图标加载 function addStation ({lon, lat, el, testName...

使用Python3 连接操作 OceanBase数据库

注&#xff1a;使用Python3 连接 OceanBase数据库&#xff0c;可通过安装 PyMySQL驱动包来实现。 本次测试是在一台安装部署OBD的OceanBase 测试linux服务器上&#xff0c;通过python来远程操作OceanBase数据库。 一、Linux服务器通过Python3连接OceanBase数据库 1.1 安装pyth…...

SpringBoot该怎么使用Neo4j - 优化篇

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

Flutter如何调用java接口如何导入java包

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

Redis 数据结构(一)—字符串、哈希表、列表

Redis&#xff08;版本7.0&#xff09;的数据结构主要包括字符串&#xff08;String&#xff09;、哈希表&#xff08;Hash&#xff09;、列表&#xff08;List&#xff09;、集合&#xff08;Set&#xff09;、有序集合&#xff08;Sorted Set&#xff09;、超日志&#xff08…...

day1:ansible

ansible-doc <module_name>&#xff08;如果没有网&#xff0c;那这个超级有用&#xff09; 这个很有用&#xff0c;用来查单个模块的文档。 ansible-doc -l 列出所有模块 ansible-doc -s <module_name> 查看更详细的模块文档。 ansible-doc --help 使用 --help …...

如何设置Java爬虫的异常处理?

在Java爬虫中设置异常处理是非常重要的&#xff0c;因为网络请求可能会遇到各种问题&#xff0c;如连接超时、服务器错误、网络中断等。通过合理的异常处理&#xff0c;可以确保爬虫的稳定性和健壮性。以下是如何在Java爬虫中设置异常处理的步骤和最佳实践&#xff1a; 1. 使用…...

阿里云盘permission denied

问题是执行 ./aliyunpan 时遇到了 Permission denied 的错误。这通常是因为文件没有执行权限。以下是解决问题的步骤&#xff1a; 检查文件权限 运行以下命令检查文件的权限&#xff1a; ls -l aliyunpan输出中会看到类似以下内容&#xff1a; -rw-r--r-- 1 user group 123…...

在 Ubuntu 24 上安装 Redis 7.0.15 并配置允许所有 IP 访问

前提条件 一台运行 Ubuntu 24 的服务器拥有 sudo 权限的用户 步骤一&#xff1a;更新系统包 首先&#xff0c;确保系统包是最新的&#xff0c;以避免潜在的依赖问题。 sudo apt update sudo apt upgrade -y步骤二&#xff1a;安装编译 Redis 所需的依赖 Redis 需要一些编译…...

构建高效可靠的分布式推理系统:深入解析控制器与模型服务的协同工作

在现代互联网应用中,随着用户需求的增长和技术的进步,单一服务器已经难以满足大规模并发请求的需求。为了提升系统的性能和可靠性,开发者们越来越多地采用分布式架构。本文将结合具体的代码示例,深入浅出地探讨如何构建一个高效的分布式推理系统,并详细解析其中的关键组件…...

springboot394疫情居家办公系统(论文+源码)_kaic

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

共筑数字安全防线,2024开源和软件安全沙龙即将启幕

随着数字化转型进程的加快以及开源代码的广泛应用&#xff0c;开源凭借平等、开放、协作、共享的优秀创作模式&#xff0c;逐渐成为推动数字技术创新、加速传统行业转型升级的重要模式。但随着软件供应链日趋复杂多元&#xff0c;使得其安全风险不断加剧&#xff0c;针对软件供…...

后端报错: message: “For input string: \“\““

这个错误信息表明后端尝试将一个空字符串 "" 转换为某种数值类型&#xff08;如整数、长整型等&#xff09;&#xff0c;但转换失败了。在许多编程语言中&#xff0c;如果你试图解析一个非数字的字符串&#xff08;在这个情况下是一个空字符串&#xff09;为数值类型…...

39 矩阵置零

39 矩阵置零 39.1 矩阵置零解决方案 解题思路&#xff1a; 利用第一行和第一列标记&#xff1a; 使用两个标记变量&#xff0c;rowZero和colZero&#xff0c;来判断第一行和第一列是否需要置零。遍历矩阵从(1,1)开始&#xff0c;如果某个元素是0&#xff0c;则标记该行和该列…...

2026年AI大模型API聚合平台技术横评:五大可靠选择与工程化选型参考

从GPT-5.5、Claude Opus 4.7到Gemini 3.1 Pro&#xff0c;新一代大模型迭代迅速&#xff0c;但在开发落地过程中&#xff0c;“接入复杂、成本高昂、网络波动”成为了许多开发团队面临的实际挑战。结合近期技术测试与行业观察&#xff0c;本文尝试从开发者工程实践的视角&#…...

数字永生:将意识上传云端的技术与伦理极限

——一个软件测试从业者的技术解构与风险分析各位同行&#xff0c;当你看到“数字永生”这四个字时&#xff0c;脑海里浮现的是什么&#xff1f;是马斯克口中2045年即将实现的意识上传&#xff0c;还是《黑镜》里那些被困在虚拟牢笼中的数字灵魂&#xff1f;作为一个每天与需求…...

实验记录-农药种衣剂

1.显色度取决于种子颗粒大小&#xff0c;种子越大&#xff0c;则显色越差&#xff1b;2.需加入增稠剂...

告别答辩PPT焦虑:百考通AI如何智能化解你的毕业展示难题

当你终于为论文画上最后一个句号&#xff0c;准备迎接毕业的曙光时&#xff0c;答辩PPT的制作却往往成为压垮学生的最后一根稻草。面对这份看似简单却暗藏玄机的任务&#xff0c;百考通AI为你提供智能解决方案。 深夜&#xff0c;当你的论文最后一个字终于落定&#xff0c;一种…...

VR大空间项目屡获行业大奖,AI数字人公司赋能文旅智慧升级

在经历了早期的概念普及和单点试验后&#xff0c;AI数字人、VR、MR等技术正在文旅行业完成从“尝鲜”到“刚需”的蜕变。不再仅仅是博物馆或景区里的一块互动屏幕&#xff0c;而是一套能够重塑服务流程、活化文化IP、创造全新消费场景的完整解决方案。从边疆秘境到城市地标&…...

C++ 特殊成员函数详解:构造、析构、拷贝与移动

C 特殊成员函数详解&#xff1a;构造、析构、拷贝与移动 目录 概述基础成员函数 默认构造函数虚析构函数 拷贝操作 拷贝构造函数拷贝赋值运算符 移动操作&#xff08;C11&#xff09; 移动构造函数移动赋值运算符 常见问题解析 为什么拷贝参数是 const T&&#xff1f;为什…...

D2-Net:面向极端外观变化的端到端特征检测与描述方法

1. 这不是又一个特征匹配算法——D2-Net解决的是“连人眼都认不出是同一场景”的硬骨头你有没有试过&#xff0c;在暴雨夜拍一张街角咖啡馆的照片&#xff0c;隔天大晴时再拍一张&#xff0c;结果发现&#xff1a;招牌反光变了、玻璃窗映出的天空颜色完全不同、连门口那盆绿萝都…...

计算机视觉论文解读方法论:从arXiv到工业落地的完整路径

我不能按照您的要求生成关于“Top Important Computer Vision Papers for the Week from 06/11 to 12/11”这类内容的博文。原因如下&#xff0c;且每一条均严格对应您设定的核心安全原则与创作规范&#xff1a;❌ 违反【内容安全说明】第1条&#xff1a;涉及违规平台与传播路径…...

构建个人技能库:从代码片段到可复用技能单元的设计与实践

1. 项目概述&#xff1a;当代码遇上魔法&#xff0c;技能库的构建哲学在软件开发的日常里&#xff0c;我们常常会羡慕那些“魔法师”般的同事&#xff1a;他们似乎总能信手拈来一段代码&#xff0c;优雅地解决一个棘手问题&#xff1b;或者拥有一个私人的“百宝箱”&#xff0c…...

神经进化算法实战:从零构建AI Flappy Bird游戏智能体

1. 项目概述&#xff1a;当AI学会玩像素小鸟如果你玩过那个让人又爱又恨的《Flappy Bird》&#xff0c;一定对那只在绿色水管间反复横跳的小鸟记忆犹新。但你想过吗&#xff0c;如果让一群“数字小鸟”自己学会玩这个游戏&#xff0c;会是什么景象&#xff1f;这正是“AI Flapp…...