【Python】BeautifulSoup

news/2025/2/2 15:02:00/

一、什么是BeautifulSoup

Beautiful Soup 简称 BS4(其中 4 表示版本号)是一个 Python 第三方库,它可以从 HTML 或 XML 文档中快速地提取指定的数据。

二、BS4下载安装

点击最下面的终端进如命令行界面

(进入成功界面:) 

由于 Bautiful Soup 是第三方库,因此需要单独下载,下载方式非常简单,执行以下命令即可安装:

pip install bs4
由于 BS4 解析页面时需要依赖文档解析器,所以 还需要安装 lxml 作为解析库
pip install lxml
Python 也自带了一个文档解析库 html.parser, 但是其解析速度要稍慢于 lxml。除了上述解析器外,还可以使用 html5lib 解析器,安装方式如下:
pip install html5lib
该解析器生成 HTML 格式的文档,但速度较慢。
“解析器容错”指的是被解析的文档发生错误或不符合格式时,通过解析器的容错性仍然可以按照既定的正确格式实现解析。

三、BS4解析对象

创建 BS4 解析对象是万事开头的第一步,这非常地简单,语法格式如下所示:

        1、导入bs4包

        2、创建bs解析对象


#导入解析包
from bs4 import BeautifulSoup
#创建beautifulsoup解析对象
soup = BeautifulSoup(html_doc, 'html.parser')

上述代码中,html_doc 表示要解析的文档,而 html.parser 表示解析文档时所用的解析器,此处的解析器也可以是 'lxml' 或者 'html5lib'。


#prettify()用于格式化输出html/xml文档

print(soup.prettify())

如果是外部文档,您也可以通过 open() 的方式打开读取,语法格式如下:

soup = BeautifulSoup(open('html_doc.html', encoding='utf8'), 'lxml')
# 'html_doc.html'是文件名,
# encoding='utf8'表示编码格式为utf-8,
#  'lxml'是解析器类型

四、BS4常用语法

下面对爬虫中经常用到的 BS4 解析方法做详细介绍。



Beautiful Soup 将 HTML 文档转换成一个树形结构,该结构有利于快速地遍历和搜索 HTML 文档。下面使用树状结构来描述一段 HTML 文档:

<html><head><title>c语言中文网</title></head><h1>c.biancheng.net</h1><p><b>一个学习编程的网站</b></p></body></html>

树状图如下所示:


文档树中的每个节点都是 Python 对象,这些对象大致分为四类:Tag , NavigableString , BeautifulSoup , Comment 。其中使用最多的是 Tag 和 NavigableString。

  • Tag:标签类,HTML 文档中所有的标签都可以看做 Tag 对象。
  • NavigableString:字符串类,指的是标签中的文本内容,使用 text、string、strings 来获取文本内容。
  • BeautifulSoup:表示一个 HTML 文档的全部内容,您可以把它当作一个特殊的 Tag 对象。
  • Comment:(注释类,输出的内容不包含注释符号)表示 HTML 文档中的注释内容以及特殊字符串,它是一个特殊的 NavigableString。

1) Tag节点

标签(Tag)是组成 HTML 文档的基本元素。在 BS4 中,通过标签名和标签属性可以提取出想要的内容。但是默认拿到第一个找到的标签及内容;

看一组简单的示例:

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>
"""from bs4 import BeautifulSoup
# prettify()按照标准的缩进格式的结构输出
print(soup.prettify())
# 获取第一个head标签的html代码
print(soup.head)
# 获取整个title标签的html代码
print(soup.title)
# 获取tag的名字
print(soup.title.name)
# 获取tag的内容,使用NavigableString类中的string、text、get_text()
print(soup.title.string)
# 获取tag父标签的名字
print(soup.title.parent.name)
# 获取第一个找到的p标签
print(soup.p)
# 获取第一个a标签
print(soup.a)
# 获取所有的a标签
print(soup.find_all('a'))
# 根据class_或id或attr(其他属性,比如type)寻找标签,如果有多个,则返回找到的第一个标签
print(soup.find(id="link3"))
# 从文档中找到所有<a>标签的链接:

for link in soup.find_all('a'):print(link.get('href'))
# 从文档中获取所有文字内容:
print(soup.get_text())

# 获取第一个b标签(b标签是p标签的子标签,想要拿到子标签必须先拿到父标签)

print(soup.p.b)

# 返回一个字典,里面是多有属性和值

print(soup.p.attrs)

# 查看返回的数据类型

print(type(soup.p))

# 根据属性,获取标签的属性值,返回值为列表

print(soup.p['class'])

# 给class属性赋值,此时属性值由列表转换为字符串

soup.p['class'] = ['Web', 'Site']
print(soup.p)

五、文档的遍历

一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点.Beautiful Soup提供了许多操作和遍历子节点的属性;


        比如 contents、 children 用来遍历子节点; parent 与parents 用来遍历父节点;而 next sibling 与 previous sibling 则用来遍历兄弟节点。示例如下:

注意: Beautiful Soup中字符串节点不支持这些属性,因为字符串没有子节点

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>
"""from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')

  tag的name

# 操作文档树最简单的方法就是告诉它你想获取的tag的name.如果想获取 <head> 标签,只要用 :soup.head

soup.head
# <head><title>The Dormouse's story</title></head>
soup.title
# <title>The Dormouse's story</title>
# 这是个获取tag的小窍门,可以在文档树的tag中多次调用这个方法. 下面的代码可以获取<body>标签中的第一个<b>标签:
soup.body.b
# <b>The Dormouse's story</b>

# 通过点取属性的方式只能获得当前名字的第一个tag:

soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

# 如果想要得到所有的<a>标签,或是通过名字得到比一个tag更多的内容的时候,就需要用到 Searching the tree 中描述的方法,比如: find_all()

soup.find_all('a')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

遍历子节点

1)contents

tag的 属性可以将tag的子节点以列表的方式输出

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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')# 获取bs的head标签
head_tag = soup.head
print(head_tag)
# <head><title>The Dormouse's story</title></head># 获取head标签的所有子节点
print(head_tag.contents)
# [<title>The Dormouse's story</title>]# 获取到的子节点可以通过下标来得到想要的子标签
title_tag = head_tag.contents[0]
print(title_tag)
# <title>The Dormouse's story</title>print(title_tag.contents)
# [u'The Dormouse's story']

2)children

获取Tag的所有子节点,返回一个生成器

for child in title_tag.children:print(child)# The Dormouse's story

六、文档的搜素

find_all() 与find() 是析 HTML 文档的常用方法,它们可以在 HTML 文档中按照一定的条件(相当于过滤器)查找所需内容。find() 与find_all() 的语法格式相似,希望大家在学习的时候,可以举一反三;


BS4 库中定义了许多用于搜索的方法,find() 与 find_all() 是最为关键的两个方法,其余方法的参数和使用与其类似。


1) find all()


find_all() 方法用来搜索当前 tag 的所有子节点,并判断这些节点是否符合过滤条件,最后以列表形式将符合条件的内容返回;

【语法格式如下】:

find_all(name, attrs, recursive, text, **kwargs)


【参数说明】:

  • name: 查找所有名字为 name 的 tag 标签,字符串对象会被自动忽略。
  • attrs: 按照属性名和属性值搜索 tag 标签,注意由于 class 是 Python 的关键字吗,所以要使用"class_"。
  • recursive: find all() 会搜索 tag 的所有子孙节点,设置recursive=False 可以只搜索 tag 的直接子节点。
  • text: 用来搜文档中的标签里的字符串内容,该参数可以接受字符串、正则表达式、列表、True。
  • limit: 由于 find all() 会返回所有的搜索结果,这样会影响执行效率,通过 imit 参数可以限制返回结果的数量。

from bs4 import BeautifulSoup
import rehtml_doc = """
<html><head><title>"c语言中文网"</title></head>
<body>
<p class="title"><b>c.biancheng.net</b></p>
<p class="website">一个学习编程的网站</p>
<a href="http://c.biancheng.net/python/" id="link1">python教程</a>
<a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>
<a href="http://c.biancheng.net/django/" id="link3">django教程</a>
<p class="vip">加入我们阅读所有教程</p>
<a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>
"""
#创建soup解析对象
soup = BeautifulSoup(html_doc, 'html.parser')
#查找所有a标签并返回
print(soup.find_all("a"))
#查找前两条a标签并返回
print(soup.find_all("a",limit=2))
#只返回两条a标签

最后以列表的形式返回输出结果,如下所示:

[<a href="http://c.biancheng.net/python/" id="link1">python教程</a>, <a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>, <a href="http://c.biancheng.net/django/" id="link3">django教程</a>, <a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>][<a href="http://c.biancheng.net/python/" id="link1">python教程</a>, <a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>]

按照标签属性以及属性值查找 HTML 文档,如下所示:

 

print(soup.find_all("p",class_="website"))
print(soup.find_all(id="link4"))

输出结果:

[<p class="website">一个学习编程的网站</p>]
[<a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>]

正则表达式、列表,以及 True 也可以当做过滤条件,使用示例如下:

#列表行书查找tag标签
print(soup.find_all(['b','a']))
#正则表达式匹配id属性值
print(soup.find_all('a',id=re.compile(r'.\d')))
print(soup.find_all(id=True))
#True可以匹配任何值,下面代码会查找所有tag,并返回相应的tag名称
for tag in soup.find_all(True):print(tag.name,end=" ")
#输出所有以b开始的tag标签
for tag in soup.find_all(re.compile("^b")):print(tag.name)

输出结果如下:

第一个print输出:
[<b>c.biancheng.net</b>, <a href="http://c.biancheng.net/python/" id="link1">python教程</a>, <a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>, <a href="http://c.biancheng.net/django/" id="link3">django教程</a>, <a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>]
第二个print输出:
[<a href="http://c.biancheng.net/python/" id="link1">python教程</a>, <a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>, <a href="http://c.biancheng.net/django/" id="link3">django教程</a>, <a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>]
第三个print输出:
[<a href="http://c.biancheng.net/python/" id="link1">python教程</a>, <a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>, <a href="http://c.biancheng.net/django/" id="link3">django教程</a>, <a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>]
第四个print输出:
html head title body p b p a a a p a
最后一个输出:
body b

BS4 为了简化代码,为 find_all() 提供了一种简化写法,如下所示:

#简化前
soup.find_all("a")
#简化后
soup("a")
上述两种的方法的输出结果是相同的。

2) find()

find() 方法与 find_all() 类似,不同之处在于 find_all() 会将文档中所有符合条件的结果返回,而 find() 仅返回一个符合条件的结果,所以 find() 方法没有limit参数。使用示例如下:

from bs4 import BeautifulSoup
import re
html_doc = """
<html><head><title>"c语言中文网"</title></head>
<body>
<p class="title"><b>c.biancheng.net</b></p>
<p class="website">一个学习编程的网站</p>
<a href="http://c.biancheng.net/python/" id="link1">python教程</a>
<a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>
<a href="http://c.biancheng.net/django/" id="link3">django教程</a>
<p class="vip">加入我们阅读所有教程</p>
<a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>
"""
#创建soup解析对象
soup = BeautifulSoup(html_doc, 'html.parser')
#查找第一个a并直接返回结果
print(soup.find('a'))
#查找title
print(soup.find('title'))
#匹配指定href属性的a标签
print(soup.find('a',href='http://c.biancheng.net/python/'))
#根据属性值正则匹配
print(soup.find(class_=re.compile('tit')))
#attrs参数值
print(soup.find(attrs={'class':'vip'}))

输出结果如下:

a标签:
<a href="http://c.biancheng.net/python/" id="link1">python教程</a>
指定href属性:
<a href="http://c.biancheng.net/python/" id="link1">python教程</a>
title:
<title>"c语言中文网"</title>
正则匹配:
<p class="title"><b>c.biancheng.net</b></p>
#attrs参数值
<p class="vip">加入我们阅读所有教程</p>

使用 find() 时,如果没有找到查询标签会返回 None,而 find_all() 方法返回空列表。示例如下:

print(soup.find('bdi'))
print(soup.find_all('audio'))

输出结果如下:

None
[]

两种写法的输出结果相同;

七、CSS选择器

BS4 支持大部分的 CSS 选择器,比如常见的标签选择器、类选择器、id 选择器,以及层级选择器。Beautiful Soup 提供了一个 select() 方法,通过向该方法中添加选择器,就可以在 HTML 文档中搜索到与之对应的内容


html_doc = """
<html><head><title>"c语言中文网"</title></head>
<body>
<p class="title"><b>c.biancheng.net</b></p>
<p class="website">一个学习编程的网站</p>
<a href="http://c.biancheng.net/python/" id="link1">python教程</a>
<a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>
<a href="http://c.biancheng.net/django/" id="link3">django教程</a>
<p class="vip">加入我们阅读所有教程</p>
<a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>
<p class="introduce">介绍:
<a href="http://c.biancheng.net/view/8066.html" id="link5">关于网站</a>
<a href="http://c.biancheng.net/view/8092.html" id="link6">关于站长</a>
</p>
"""
from bs4 import BeautifulSoupsoup = BeautifulSoup(html_doc, 'html.parser')#根据元素标签查找
print(soup.select('title'))#根据属性选择器查找
print(soup.select('a[href]'))#根据类查找
print(soup.select('.vip'))#后代节点查找
print(soup.select('html head title'))#查找兄弟节点
print(soup.select('p + a'))#根据id选择p标签的兄弟节点
print(soup.select('p ~ #link3'))#nth-of-type(n)选择器,用于匹配同类型中的第n个同级兄弟元素
print(soup.select('p ~ a:nth-of-type(1)'))#查找子节点
print(soup.select('p > a'))
print(soup.select('.introduce > #link5'))# 根据id查找
print(soup.select('#link1'))# 根据属性查找
print(soup.select('a[id="link6"]'))

输出结果:

第一个输出:
[<title>"c语言中文网"</title>]第二个输出:
[<a href="http://c.biancheng.net/python/" id="link1">python教程</a>, <a href="http://c.biancheng.net/c/" id="link2">c语言教程</a>, <a href="http://c.biancheng.net/django/" id="link3">django教程</a>, <a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>, <a href="http://c.biancheng.net/view/8066.html" id="link5">关于网站</a>, <a href="http://c.biancheng.net/view/8092.html" id="link6">关于站长</a>]第三个输出:
[<p class="vip">加入我们阅读所有教程</p>]第四个输出:
[<title>"c语言中文网"</title>]第五个输出:
[<a href="http://c.biancheng.net/python/" id="link1">python教程</a>, <a href="http://vip.biancheng.net/?from=index" id="link4">成为vip</a>]第六个输出:
[<a href="http://c.biancheng.net/django/" id="link3">django教程</a>]第七个输出:
[<a href="http://c.biancheng.net/python/" id="link1">python教程</a>]第八个输出:
[<a href="http://c.biancheng.net/view/8066.html" id="link5">关于网站</a>, <a href="http://c.biancheng.net/view/8092.html" id="link6">关于站长</a>]第九个输出:
[<a href="http://c.biancheng.net/view/8066.html" id="link5">关于网站</a>]第十个输出:
[<a href="http://c.biancheng.net/python/" id="link1">python教程</a>]第十一个输出:
[<a href="http://c.biancheng.net/view/8092.html" id="link6">关于站长</a>]


http://www.ppmy.cn/news/55531.html

相关文章

Spring 管理 Bean-IOC--基于 XML 配置bean

目录 Spring 管理 Bean-IOC--基于 XML 配置bean Spring 配置/管理 bean 介绍 Bean 管理包括两方面 Bean 配置方式 基于 XML 配置 bean 通过 spring 的ioc 容器, 获取一个bean 对象 获取 bean 的方式&#xff1a;按类型 Monster类 注意 xml配置 细节说明 通过构造器配置…

函数(详解)——C语言

Hello&#xff0c;友友们前段时间忙拖更了这么久&#xff0c;趁着五一假期好好卷上一波哈哈哈。好的&#xff0c;我们本期主要对C语言中的函数进行讲解。 1.什么是函数 在数学中也常常用到函数&#xff0c;但你对C语言中的函数有了解吗&#xff1f; 在C语言中函数是一段可重…

【计算机网络详解】——物理层(学习笔记)

&#x1f4d6; 前言&#xff1a;今天我们将一起探索电脑网络中最基础的一层&#xff0c;物理层。从摩斯电码到光纤传输的高速互联网时代&#xff0c;物理层在不断发展和创新。让我们一起深入到网络通讯的本质&#xff0c;探究物理层与我们的日常联系密不可分的原因。 目录 &…

java学习需要掌握的几个细节点,分享一下我找工作的技巧

现在想跟大家聊聊最近的一些想法和状态。最近学习的时间比较少&#xff0c;几乎没怎么学。没有像以前学的那么卷了&#xff0c;可以说。主要是心态受到了一些影响&#xff0c;比如网上看到说招个岗位几百比1这种。 另一个是自己的感受&#xff0c;现在投简历的回应包括能不能投…

Java中的String、StringBuffer和StringBuilder

文章目录 Java中的String、StringBuffer和StringBuilderString 类型特点操作 StringBuffer 类型特点操作 StringBuilder 类型特点操作 总结代码实践注意事项 Java中的String、StringBuffer和StringBuilder 在 Java 中&#xff0c;字符串是最常用的数据类型之一。 Java 中有三种…

新品首发丨计讯物联5G水利遥测终端机TY511-B3,推动5G+智慧水利再进化

当前&#xff0c;水利在全面感知、全面互联、智慧应用等方面较其他行业存在明显差距。基于物联网行业通信技术的不断突破和水利行业对高速移动通信的强烈需求&#xff0c;5G移动通信以高速率、大带宽、低时延、广连接等特点让水利数据快速高效地传输成为可能&#xff0c;逐渐成…

ecs思考

VPC网络诊断&#xff0c;从router看起&#xff0c;连接公有子网路有一个默认&#xff0c;再新增一条指向igw路由&#xff1b;连接私有子网路由有一个默认&#xff0c;再新增一条指向NAT网关的路由&#xff0c;其中NAT网关一定要在公有子网中&#xff0c;否则&#xff0c;私有子…

Java 怎样实现代理模式,有什么优缺点

一、介绍 代理模式是一种常见的设计模式&#xff0c;它可以为其他对象提供一种代理以控制对这个对象的访问。代理对象具有与被代理对象相同的接口&#xff0c;客户端无需知道代理对象和被代理对象的区别。代理模式可以应用于各种不同的场景&#xff0c;例如远程代理、虚拟代理…