Python 爬虫十六式 - 第五式:BeautifulSoup-美味的汤

2023-11-10 03:30

本文主要是介绍Python 爬虫十六式 - 第五式:BeautifulSoup-美味的汤,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

BeautifulSoup 美味的汤

学习一时爽,一直学习一直爽!

   Hello,大家好,我是Connor,一个从无到有的技术小白。上一次我们说到了 Xpath 的使用方法。Xpath 我觉得还是比较绕该怎么办呢???有没有更加简单易懂的方法呢?答案是肯定的,当然有更加简单易懂的方法了,那就是 BeautifulSoup 美味的汤。这个方法对于正则和 Xpath 来说更加的简单方便,更加易懂,能够节省我们大量的分析时间。

1.BeautifulSoup 的简介

  BeautifulSoup是一个HTML数据提取库。几乎没有什么数据可以难住BeautifulSoup。只要是你可以获取的到的数据,那么你都可以通过BeautifulSoup简单快捷的进行数据提取。是一款非常适合新手入门使用的数据提取库。当然,作为一个HTML数据提取库,requests 都有了官方中文文档,那么 BeautifulSoup 当然也不能少啊,你可以访问 BeautifulSoup 的官方中文文档:点我走起 >>>


2.BeautifulSoup 的安装

  既然我又来说到安装了,那就证明这个库和我们平常想的库不太一样,它具体的安装方法为:

pip install beautifulsoup4

  注意,是beautifulsoup4,并不是beautifulsoup,虽然我们beautifulsoup的叫,但人家实际叫beautifulsoup4,一定要记清楚哈。


3.BeautifulSoup 的基础使用

  安装完了,下面我们就正式开始使用,老规矩,我们先来一段html文档,然后逐一举例,来看BeautifulSoup如何使用:

  首先我们来随意编写一段html代码:

html = """
<html><head><title>Hello,Wrold</title></head><body><div class="book"><span><!--这里是注释的部分--></span><a href="https://www.baidu.com">百度一下,你就知道</a><img src="https://abc.jpg" /><p class="abc">这是一个示例</p></div></body>
</html>"""

3.1 简单的使用

  在进行内容提取之前,我们需要将获取的html内容转换成BeautifulSoup对象:

In [1]: from bs4 import BeautifulSoupIn [2]: soup = BeautifulSoup(html, "html5lib")In [3]: type(soup)
Out[3]: bs4.BeautifulSoup

  可以看的到,我们生成的对象是一个 bs4.BeautfulSoup 对象,我们所有的内容提取都基于这个对象。切记进行内容提取之前先生成 bs4.BeautifulSoup 对象。

3.2 解析器的使用

  在上面的语句中,大家可以看到我们使用了一个 html5lib 这是一个解析器,在构造BeautifulSoup 对象的时候,需要用到解析器。BeautifulSoup 支持python自带的解析器和少数第三方解析器。详细对比如下:

解析器使用方法优势劣势
Python标准库BeautifulSoup(html,"html.parser")Python的内置标准库。 执行速度适中。 文档容错能力强。Python 3.2.2前的版本文档容错能力差
lxml HTML 解析器BeautifulSoup(html, "lxml")速度快文档容错能力强需要安装C语言库
lxml XML 解析器BeautifulSoup(html, ["lxml","xml"]) BeautifulSoup(html, "xml")速度快 唯一支持XML的解析器需要安装C语言库
html5libBeautifulSoup(markup,"html5lib")最好的容错性 以浏览器的方式解析文档生成HTML5格式的文档速度慢但不依赖外部扩展

  一般来说,对于速度或性能要求不太高的话,还是建议大家使用 html5lib 来进行解析的,但是当规模达到一定程度的时候,解析速度就会影响到整体项目的快慢了,所以如果你对性能有要求的话,还是推荐使用 lxml 来进行解析的。具体的视情况而定吧。


3.3 节点对象

  BeautifulSoup将复杂的HTML文档转换成了一个树状的结构,每个节点都是一个Python对象,所有的对象都可以归纳为四类:TagNavigableStringBeautifulSoup,Commnet

3.3.1 Tag 对象

  Tag 就是我们平时所说的标签,Tag下拥有许多属性和方法,和前端类似,例如 a 标签一定会有它的href属性,某些属性是某些标签所独有的。下面我们来看一下如何提取一个 Tag 对象:

In [1]: soup = BeautifulSoup(html)In [2]: tag = soup.pIn [3]: type(tag)
Out[3]: bs4.element.Tag

  可以看的到,我们生成了一个 Tag 对象,我们再来看看 Tag 对象有哪些属性:

  • name属性:

  每一个tag标签都有name属性

In [4]: tag.name
Out[4]: 'p'
  • Attributes

  在html中,某个 Tag 可能有多个属性, Tag 属性使用和字典一样的方法取值:

In [5]: tag["class"]
Out[5]: ['abc']

如果某个 Tag 属性有多个值,那么返回的是一个列表:

In [6]: soup = BeautifulSoup('<p class="body strikeout"></p>')In [7]: soup.p['class']
Out[7]: ['body', 'strikeout']
  • get_text()

  通过 get_text() 方法我们可以获取某个 Tag 下所有的文本内容:

In [8]: soup.a.get_text()
Out[8]: '百度一下,你就知道'

3.3.2 NavigableString 对象

  NavigableString 的意思是可以遍历的字符串,一般被标签包裹在自种的文本就是NavigableString 格式:

In [9]: soup.p.string
Out[9]: '这是一个示例'In [10]: type(soup.p.string)
Out[10]: bs4.element.NavigableString

3.3.3 BeautifulSoup 对象

BeautifulSoup 对象就是通过解析网页所得到的对象,我们的 soup 即是 BeautifulSoup 对象:

In [1]: from bs4 import BeautifulSoupIn [2]: soup = BeautifulSoup(html, "html5lib")In [3]: type(soup)
Out[3]: bs4.BeautifulSoup

3.3.4 Comment 对象

Comment 对象是网页中的注释及特殊字符串,当你提取网页中的注释的时候,它会自动帮你生成Comment 对象:

In [4]: comment = soup.body.span.stringIn [5]: type(comment)
Out[5]: bs4.element.Comment

了解了 BeautifulSoup 的基础使用之后,我们来看一下 BeautifulSoup 的进阶用法:

4 BeautifulSoup 的高级用法

4.1 Tag与遍历文档树

  Tag 对象可以说 BeautifulSoup 中最为重要的对象,通过 BeautifulSoup 来提取数据基本都围绕着这个对象来进行操作。

  首先,一个节点中是可以包含多个子节点和多个字符串的。例如html节点中包含着headbody节点。所以BeautifulSoup就可以将一个HTML的网页用这样一层层嵌套的节点来进行表示。

  使用我们的例子,你可以这样做:

4.1.1 contents 和 children

  通过 contents 可以获取某个节点的所有子节点,包括里面的 NavigbleString 对象,获取的子节点是列表格式:

In [5]: soup.head.contents
Out[5]: [<title>Hello,Wrold</title>]

  通过 children 也可以获取某个节点的所有子节点,但是返回的是一个迭代器,这种方式使用起来比列表更加的省内存:

In [6]: tags = soup.head.childrenIn [7]: print(tags)
<list_iterator object at 0x000002E5B44E6860>In [8]: for tag in tags:...:     print(tag)...:<title>Hello,Wrold</title>

4.1.2 descendants

  上面的contentschildren获取的是某个节点的直接子节点,而无法获得子孙节点。通过descendants可以获得所有子孙节点,返回的结果跟children一样,需要迭代或者转类型使用。

In [15]: tags = soup.body.descendantsIn [16]: for tag in tags:...:     print(tag)...:<div class="book">
<span><!--这里是注释的部分--></span>
<a href="https://www.baidu.com">百度一下,你就知道</a>
<img src="https://abc.jpg"/>
<p class="abc">这是一个示例</p>
</div><span><!--这里是注释的部分--></span>
这里是注释的部分<a href="https://www.baidu.com">百度一下,你就知道</a>
百度一下,你就知道<img src="https://abc.jpg"/><p class="abc">这是一个示例</p>
这是一个示例

  通过上图我们可以看得出通过 descendants 首先找出了 body 标签的第一个子节点,然后将子节点中的字符串提取出来。提取出子节点的字符串之后再提取子节点的子节点,再将其内容提取出来。直到该节点不再拥有子节点。这么说可能有些抽象,我们来直接看图:

  是不是一目了然了???鬼知道我为了做这个图到底经历了什么…

4.1.3 string 和 strings

  我们常常会遇到需要获取某个节点中的文本值的情况,如果这个节点中只有一个字符串,那么使用string可以正常将其取出。

In [17]: soup.body.a.string
Out[18]: '百度一下,你就知道'

  但是如果一个节点下有多个节点中包含有字符串的时候,这时使用 string 方法就无法准确的取出字符串了,它无法确定你要取出的是哪个字符串,这时你需要使用 strings

In [19]: strings = soup.body.stringsIn [20]: strings
Out[20]: <generator object _all_strings at 0x000002E5B44EA1A8>In [21]: for string in strings:...:     print(string)...:
百度一下,你就知道
这是一个示例

  使用 strings 也会给你返回一个可迭代对象。当然,你会发现里面有很多的’\n’,’\t’啊等这样的转义字符,上面的程序中没有是因为为了美观我手动去掉了。如果你想要获取的内容中没有转义字符的话,你可以使用 stripped_strings 来去掉内容中的空白:

In [22]: strings = soup.body.stripped_stringsIn [23]: strings
Out[23]: <generator object stripped_strings at 0x000002E5B39DF3B8>In [24]: for string in strings:...:     print(string)...:
百度一下,你就知道
这是一个示例

4.1.4 父节点 parent 和 parents

  有的时候我们也需要去获取某个节点的父节点,就是当前节点的上一层节点:

In [25]: soup.a.parent
Out[25]:
<div class="book">
<span><!--这里是注释的部分--></span>
<a href="https://www.baidu.com">百度一下,你就知道</a>
<img src="https://abc.jpg"/>
<p class="abc">这是一个示例</p>
</div>

  如果使用 parents 的话将会递归获取该节点的所有父辈元素:

In [26]: soup.a.parents
Out[26]: <generator object parents at 0x000002E5B38C3150>

  同样这种方式获取的父辈元素也是一个可迭代对象,需要处理后才能使用


4.1.5 兄弟节点

  兄弟节点就是指当前节点同级节点。

  • next_sibling 和 previous_sibling

    兄弟节点选取的方法与当前节点的位置有关,next_sibling获取的是当前节点的下一个兄弟节点,previous_sibling获取的是当前节点的上一个兄弟节点。

    所以,兄弟节点中排第一个的节点是没有previous_sibling的,最后一个节点是没有next_sibling的。

    In [27]: soup.head.next_sibling
    Out[27]: '\n'In [28]: soup.head.previos_siblingIn [29]: soup.body.previous_sibling
    Out[29]: '\n'
    
  • next_siblings 和 previous_siblings

    相对应的,next_siblings获取的是下方所有的兄弟节点,previous_siblings获取的上方所有的兄弟节点。

    In [30]: [i.name for i in soup.head.next_siblings]
    Out[30]: [None, 'body', None]In [31]: [i.name for i in soup.body.next_siblings]
    Out[31]: [None]In [32]: [i.name for i in soup.body.previous_siblings]
    Out[32]: [None, 'head', None]
    

4.2. find_all()

  在前面我们讲了通过标签的属性来进行标签的访问的方法,大多都只适用于简单的一些场景,所以 BeautifulSoup 还提供了搜索整个文档树的方法,即 find_all()。该方法基本适用于任何节点:

4.2.1 通过 name 搜索

最简单的使用方式就是使用 name 属性进行搜索,你可以这样做:

In [33]: soup.find_all('a')
Out[33]: [<a href="https://www.baidu.com">百度一下,你就知道</a>]

  通过 find_all() 方法获取的内容是一个列表对象。如果你给的条件是一个列表,则会匹配列表里的全部标签,例如:

In [34]: soup.find_all(['a','p'])
Out[34]: [<a href="https://www.baidu.com">百度一下,你就知道</a>, <p class="abc">这是一个示例</p>]

  通过上面的例子我们可以看得出,我们可以看得到, BeautifulSoup 对象匹配出了所有的 a标签和 p 标签。


4.2.2 通过属性搜索

  除了通过 name 属性来进行匹配之外,我们还可以通过属性进行匹配。这个时候我们需要向 find_all() 方法传递一个字典参数:

In [35]: soup.find_all(attrs={'class':'book'})
Out[35]:
[<div class="book"><span><!--这里是注释的部分--></span><a href="https://www.baidu.com">百度一下,你就知道</a><img src="https://abc.jpg"/><p class="abc">这是一个示例</p></div>]

  如果一个标签有多个参数,为了查找的准确性,你也可以向attrs传递多个参数。


4.2.3 通过文本搜索

  在find_all()方法中,还可以根据文本内容来进行搜索。

In [36]: soup.find_all("a", text="百度一下,你就知道")
Out[36]: [<a href="https://www.baidu.com">百度一下,你就知道</a>]

可见找到的都是字符串对象,如果想要找到包含某个文本的tag,加上tag名即可。


4.2.4 限制查找范围为子节点

  find_all() 方法会默认的去所有的子孙节点中搜索,而如果将 recursive 参数设置为False,则可以将搜索范围限制在直接子节点中:

In [37]: soup.find_all("a",recursive=False)
Out[37]: []In [38]: soup.find_all("a",recursive=True)
Out[38]: [<a href="https://www.baidu.com">百度一下,你就知道</a>]

4.2.5 通过正则表达式来筛选结果

  在BeautifulSoup中,也是可以与re模块进行相互配合的,将re.compile编译的对象传入find_all()方法,即可通过正则来进行搜索。

In [39]: import reIn [40]: soup.find_all(re.compile("b"))
Out[40]:
[<body>
<div class="book">
<span><!--这里是注释的部分--></span>
<a href="https://www.baidu.com">百度一下,你就知道</a>
<img src="https://abc.jpg"/>
<p class="abc">这是一个示例</p>
</div>
</body>]

  可以看到,通过正则表达式,我们找到了所有以 b 开头的标签。正则怎么用我们会在之后的文章中详细的说的,大家不用着急。当然,正则除了能用在标签上,也可以用在属性上:

In [57]: soup.find_all(attrs={"class":re.compile("a")})
Out[57]: [<p class="abc">这是一个示例</p>]

4.3 CSS选择器

  在BeautifulSoup中,同样也支持使用CSS选择器来进行搜索。使用select(),在其中传入字符串参数,就可以使用CSS选择器的语法来找到tag:

In [58]: soup.select("title")
Out[58]: [<title>Hello,Wrold</title>]In [60]: soup.select(".book")
Out[60]:
[<div class="book"><span><!--这里是注释的部分--></span><a href="https://www.baidu.com">百度一下,你就知道</a><img src="https://abc.jpg"/><p class="abc">这是一个示例</p></div>]

下期预告:

   Xpath 和 BueatifulSoup 都很好用,但是有时候遇到复杂的选择也很麻烦,有没有能像Jquery一样快速通过css来选择的工具啊???当然有了!!!那就是我们的PyQuery,一个和JQuery就像亲兄弟一样的库,敬请期待下期—PyQuery,一个类似JQuery的库。

  好了,这就是今天最美味的汤了,不知道你喝了以后有什么感受,我是Connor,一个从无到有的技术小白,希望你能和我一同进步,一同成长!我们下期再见!

学习一时爽,一直学习一直爽!


系列文章连接:

Python 爬虫十六式 - 第一式:HTTP协议 >>>
Python 爬虫十六式 - 第二式:urllib 与 urllib3 >>>
Python 爬虫十六式 - 第三式:Requests的用法 >>>
Python 爬虫十六式 - 第四式: 使用Xpath提取网页内容 >>>
Python 爬虫十六式 - 第六式:JQuery的假兄弟-pyquery >>>
Python 爬虫十六式 - 第七式:正则的艺术 >>>
Python 爬虫十六式 - 第八式:实例解析 - 全书网 >>>

这篇关于Python 爬虫十六式 - 第五式:BeautifulSoup-美味的汤的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/380161

相关文章

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

Python+FFmpeg实现视频自动化处理的完整指南

《Python+FFmpeg实现视频自动化处理的完整指南》本文总结了一套在Python中使用subprocess.run调用FFmpeg进行视频自动化处理的解决方案,涵盖了跨平台硬件加速、中间素材处理... 目录一、 跨平台硬件加速:统一接口设计1. 核心映射逻辑2. python 实现代码二、 中间素材处

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Python实现快速扫描目标主机的开放端口和服务

《Python实现快速扫描目标主机的开放端口和服务》这篇文章主要为大家详细介绍了如何使用Python编写一个功能强大的端口扫描器脚本,实现快速扫描目标主机的开放端口和服务,感兴趣的小伙伴可以了解下... 目录功能介绍场景应用1. 网络安全审计2. 系统管理维护3. 网络故障排查4. 合规性检查报错处理1.

Python轻松实现Word到Markdown的转换

《Python轻松实现Word到Markdown的转换》在文档管理、内容发布等场景中,将Word转换为Markdown格式是常见需求,本文将介绍如何使用FreeSpire.DocforPython实现... 目录一、工具简介二、核心转换实现1. 基础单文件转换2. 批量转换Word文件三、工具特性分析优点局

Python中4大日志记录库比较的终极PK

《Python中4大日志记录库比较的终极PK》日志记录框架是一种工具,可帮助您标准化应用程序中的日志记录过程,:本文主要介绍Python中4大日志记录库比较的相关资料,文中通过代码介绍的非常详细,... 目录一、logging库1、优点2、缺点二、LogAid库三、Loguru库四、Structlogphp

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

Python海象运算符:=的具体实现

《Python海象运算符:=的具体实现》海象运算符又称​​赋值表达式,Python3.8后可用,其核心设计是在表达式内部完成变量赋值并返回该值,从而简化代码逻辑,下面就来详细的介绍一下如何使用,感兴趣... 目录简介​​条件判断优化循环控制简化​推导式高效计算​正则匹配与数据提取​性能对比简介海象运算符

python项目环境切换的几种实现方式

《python项目环境切换的几种实现方式》本文主要介绍了python项目环境切换的几种实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 如何在不同python项目中,安装不同的依赖2. 如何切换到不同项目的工作空间3.创建项目

python项目打包成docker容器镜像的两种方法实现

《python项目打包成docker容器镜像的两种方法实现》本文介绍两种将Python项目打包为Docker镜像的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录简单版:(一次成功,后续下载对应的软件依赖)第一步:肯定是构建dockerfile,如下:第二步