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

本文介绍了BeautifulSoup库在Python中用于解析HTML和XML文档的便利性,包括简介、解析器的选择、准备工作、基本使用、提取节点名称、属性和内容,以及CSS选择器的运用。推荐使用lxml解析器以提升效率。
摘要由CSDN通过智能技术生成

        前面介绍了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 BeautifulSoup

soup = 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选择法。
  • 45
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值