网页数据的解析提取(Beautiful Soup库详解)

2024-02-23 15:12

本文主要是介绍网页数据的解析提取(Beautiful Soup库详解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        前面介绍了lxml库和re库,(网页数据的解析提取(XPath的使用----lxml库详解)-CSDN博客 网页数据的解析提取(正则表达式----re库详解)-CSDN博客)。现在来介绍一个更为简便和强大的解析工具--Beautiful Soup,其借助网页的结构和属性等特性来解析网页。

目录

Beautiful Soup

1、 Beautiful Soup 的简介

2、解析器

3、准备工作

4、基本使用

5、提取信息

(1)获取名称

(2)获取属性

(3)获取内容

(4)嵌套选择

(5)关联选择

(6)方法选择器

6、CSS选择器

7、总结


Beautiful Soup

1、 Beautiful Soup 的简介

  简单来说, Beautiful Soup 是 Python的一个 HTML 或XML 的解析库, 我们用它可以方便地从网页中提取数据, 其官方解释如下:
  Beautiful Soup 提供一些简单的、Python 式的函数来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据, 因为简单, 所以无须很多代码就可以写出一个完整的应用程序。Beautiful Soup 自动将输入文档转换为Unicode 编码, 将输出文档转换为 utf-8编码。你不需要考虑编码方式, 除非文档没有指定具体的编码方式,这时你仅仅需要说明一下原始编码方式就可以了。Beautiful Soup 已成为和 lxml、html5lib一样出色的 Python 解释器, 为用户灵活提供不同的解析策略或强劲的速度。总而言之, 利用Beautiful Soup 可以省去很多烦琐的提取工作, 提高解析网页的效率。

2、解析器

        实际上, Beautiful Soup在解析时是依赖解析器的,它除了支持 Python标准库中的 HTML 解析器,还支持一些第三方解析器(例如lxml)。下表列出了 Beautiful Soup 支持的解析器。

解 析 器

使   

 

 

Python标准库

BeautifulSoup(markup,'html.parser')

Python 的内置标准库、执行速度适中、文档容错能力强

Python 2.7.3 或 3.2.2 前的版本中文容错能力差

LXML HTML解析器

BeautifulSoup(markup, 'lxml')

速度快、文档容错能力强

需要安装C语言库

LXML XML 解析器

BeautifulSoup(markup, 'xml')

速度快、唯一支持 XML 的解析器

需要安装C语言库

html5lib

BeautifulSoup(markup, 'htm15lib')

提供最好的容错性、以浏览器的方式解析文档、生成HTML5格式的文档

速度慢、不依赖外部扩

        通过上表的对比可以看出,LXML解析器有解析HTML 和XML的功能,而且速度快、容错能力强,所以推荐使用它。使用LXML 解析器, 只需在初始化 Beautiful Soup时, 把第二个参数改为 lxml即可:

from bs4 import BeautifulSoupsoup = BeautifulSoup('', 'lxml')print(soup. p. string)

        在后面, 统一用这个解析器演示 Beautiful Soup 的用法实例。

3、准备工作

        在开始之前, 请确保已经正确安装好 Beautiful Soup 和 lxml这两个库。Beautiful Soup 直接使用pip3 安装即可, 命令如下:

pip3 install beautifulsoup4

        更加详细的安装说明可以参考:https://setup.scrape.center/beautifulsoup 。另外,我们使用的是 lxml这个解析器,所以还需要额外安装lxml这个库。以上两个库都安装完成后,就可以进行接下来的学习了。

4、基本使用

        下面首先通过实例看看 Beautiful Soup的基本用法:

html= """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><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, 'lxml')
print(soup.prettify())
print(soup.title.string)

结果如下:

<html><head><title>The Dormouse's story</title></head><body><p class="title" name="dromouse"><b>The Dormouse's story</b></p><p class="story">Once upon a time there were three little sisters; and their names were<a class="sister" href="  http://example.com/elsie  " id="link1"><!--Elsie--></a>,<a class="sister" href="  http://example.com/lacie  " id="link2">Lacie</a>and<a class="sister" href="  http://example.com/tillie  " id="link3">Tillie</a>;
and they lived at the bottom of a well.</p><p class="story">…</p></body>
</html>The Dormouse's story

        这里首先声明一个变量 html,这是一个 HTML 字符串。但是需要注意的是,它并不是一个完整的 HTML 字符串,因为 body 节点和 html节点都没有闭合。接着,我们将它当作第一个参数传给BeautifulSoup 对象,该对象的第二个参数为解析器的类型(这里使用 1xml),此时就完成了BeaufulSoup对象的初始化。然后,将这个对象赋值给 soup 变量。之后就可以调用 soup的各个方法和属性解析这串HTML 代码了。

        首先,调用prettify方法。这个方法可以把要解析的字符串以标准的缩进格式输出。这里需要注意的是, 输出结果里包含 body 和 html节点, 也就是说对于不标准的 HTML 字符串 BeautifulSoup,可以自动更正格式。这一步不是由 prettify方法完成的,而是在初始化BeautifulSoup的时候就完成了。然后调用 soup. title. string, 这实际上是输出 HTML 中 title 节点的文本内容。所以, 通过soup. title 选出HTML 中的 title节点, 再调用string属性就可以得到title节点里面的文本了。

5、提取信息

        前面,演示了通过string属性获取文本的值,那么如何获取节点名称?如何获取节点属性的值呢?接下来统一来梳理一下信息的提取方式吧!下面统一以提取下面的html信息做示例:

html= """
<html><head><title>The Dormouse's story</title></head><body>
<p class="title" name="dromouse"><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>
"""

(1)获取名称

         利用name属性可以获取节点的名称。先选取title节点,再调用name属性就可以得到节点名称:

print(soup.title.name)

运行结果为:

title

(2)获取属性

        一个节点可能有多个属性,例如id和class等。可以选择该节点调用其attrs获取其所有属性,但attrs属性的返回结果是字典形式,包括所选择节点的所有属性和属性值。因此要获取name属性,相当于从字典中获取某个键值。

print(soup.p.attrs)
print(soup.p.attrs['name'])

运行结果为:

{'class': ['title'], 'name': 'dromouse'}
dromouse

        其实还有一种更为简单的方法,不用写attrs,直接在节点元素后面传入需要的属性名即可。例:

print(soup.p['name'])
print(soup.p['class'])

结果为:

dromouse
['title']

(3)获取内容

        利用string属性获取节点元素包含的文本内容,获取的是第一个p节点。

print(soup.p.string)

结果为:

The Dormouse's story

(4)嵌套选择

          在html中存在节点嵌套情况,假如:获取了head节点,就可以继续调用head选取其内部的head节点。

html= """
<html><head><title>The Dormouse's story</title></head><body>
<p class="title" name="dromouse"><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, 'lxml')
print(soup.head.title)
print(soup.head.title.string)

结果为:

<title>The Dormouse's story</title>
The Dormouse's story

        这里是head节点中嵌套了title点,通过.来选择节点的嵌套节点。

(5)关联选择

        有时候不能一步就选到想要的节点,需要先选中某一个节点,再以它为基准选子节点、父节点、兄弟节点。

  • 子节点和子孙节点

        选取节点后,想要获取它的直接子节点,可以调用contents属性,它返回的是列表形式的该节点的所有子节点 。如果想要子孙节点,可以用descendants属性,它返回的也是查询所有子节点,得到所有的子孙节点。

  • 父节点和祖先节点

        如果要获取某个节点元素的父节点,可以调用parent属性,其输出的是该节点的父节点的所有内容。 如果需要获取其所有祖先节点,可以调用parents属性。

  • 兄弟节点

        如果要获取同级节点,也就是兄弟节点该怎么办呢?使用next_sibling和previous_sibling分别用于获取节点的下一个和上一个兄弟节点,next_siblings和previous_siblings则分别返回后面和前面的所有兄弟节点。

(6)方法选择器

        前面讲的方法都是通过基于属性来选择的,但比较繁琐,还有一种更好的查询方法。

  • find_all

        查询所有符合条件的元素,可以传入需要的属性或文本来得到满足条件的元素。API如下:

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

name:根据元素或节点查询

attrs:根据属性值来查询

text:根据节点的文本来查询(可以是字符串或正则表达式)

  • find

        find_all是返回所有匹配的元素组成的列表,find是返回第一个匹配的元素,用法与find_all相同。        

        另外还有许多查询方法, 用法与介绍过的 find_all、find完全相同, 区别在于查询范围不同, 在此做一下简单的说明。

  • find_parents 和 find_parent: 前者返回所有祖先节点, 后者返回直接父节点。
  • find_next_siblings 和 find_next_sibling: 前者返回后面的所有兄弟节点, 后者返回后面第一个兄弟节点。
  • find_previous_siblings 和 find_previous_sibling: 前者返回前面的所有兄弟节点, 后者返回前面第一个兄弟节点。
  • find_all_next 和 find_next:前者返回节点后面所有符合条件的节点,后者返回后面第一个符合条件的节点。
  • find_all_previous 和 find_previous: 前者返回节点前面所有符合条件的节点, 后者返回前面第一个符合条件的节点。 

6、CSS选择器

        如果你熟悉Web开发,那么对CSS肯定不陌生。使用CSS选择器,只需要调用select方法,传入相应的CSS选择器即可。通过一个实例感受一下:

html = '''
<div class="panel"><div class="panel-heading"><h4>Hello</h4></div><div class="panel-body"><ul class="list" id="list-1"><li class="element">Foo</li><li class="element">Bar</li><li class="element">Jay</li></ul><ul class="list list-small" id="list-2"><li class="element">Foo</li><li class="element">Bar</li></ul></div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html,'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))

结果如下:

[<div class="panel-heading">
<h4>Hello</h4>
</div>]
[<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
[<li class="element">Foo</li>, <li class="element">Bar</li>]

         第一个打印的是class为panel节点的中的class为panel-heading的节点信息,第二个打印的是ul节点中的li节点信息,第三个打印id为list-2中class为elment的元素信息。

7、总结

  • 推荐使用lxml解析库,必要时用html.parser
  • 节点选择器筛选功能弱,但速度快
  • 建议用find和find_all方法查询匹配的单个结果或多个结果
  • 如果对CSS选择器熟悉,则可以用select选择法。

这篇关于网页数据的解析提取(Beautiful Soup库详解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Mysql 中的多表连接和连接类型详解

《Mysql中的多表连接和连接类型详解》这篇文章详细介绍了MySQL中的多表连接及其各种类型,包括内连接、左连接、右连接、全外连接、自连接和交叉连接,通过这些连接方式,可以将分散在不同表中的相关数据... 目录什么是多表连接?1. 内连接(INNER JOIN)2. 左连接(LEFT JOIN 或 LEFT

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

Linux内核之内核裁剪详解

《Linux内核之内核裁剪详解》Linux内核裁剪是通过移除不必要的功能和模块,调整配置参数来优化内核,以满足特定需求,裁剪的方法包括使用配置选项、模块化设计和优化配置参数,图形裁剪工具如makeme... 目录简介一、 裁剪的原因二、裁剪的方法三、图形裁剪工具四、操作说明五、make menuconfig

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

详解Java中的敏感信息处理

《详解Java中的敏感信息处理》平时开发中常常会遇到像用户的手机号、姓名、身份证等敏感信息需要处理,这篇文章主要为大家整理了一些常用的方法,希望对大家有所帮助... 目录前后端传输AES 对称加密RSA 非对称加密混合加密数据库加密MD5 + Salt/SHA + SaltAES 加密平时开发中遇到像用户的

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

Springboot使用RabbitMQ实现关闭超时订单(示例详解)

《Springboot使用RabbitMQ实现关闭超时订单(示例详解)》介绍了如何在SpringBoot项目中使用RabbitMQ实现订单的延时处理和超时关闭,通过配置RabbitMQ的交换机、队列和... 目录1.maven中引入rabbitmq的依赖:2.application.yml中进行rabbit

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初