栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

BeautifulSoap基本使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

BeautifulSoap基本使用

Beautiful Soup使用

文章目录
  • Beautiful Soup使用
    • 简介
    • 安装
    • 快速开始
      • 对象种类
      • 节点的定位
      • 信息提取
      • 关联选择
      • 方法选择器(搜索文档树)
      • CSS选择器
  • 参考资料

简介

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.

安装
  1. 在终端输入pip install beautifulsoup4。

  2. 然后安装解析器:pip install lxml。

Beautiful Soup也能支持其他解析器,这里使用lxml解析器。如果有更改解析器的需要,参看其[官方手册](Beautiful Soup 中文文档)。

快速开始

下面是一段html代码,后面会被多次用到,这段代码称其为文本1。

html = """
The Dormouse's story

The Dormouse's story

Once upon a time there were three little sisters; and their names were Elsie, Lacie and Tillie; and they lived at the bottom of a well.

...

"""
# 将上述文本1的代码放在同一py文件下,运行。观察结果
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.prettify())
print(soup.title.string)
  • 对于文本1,观察可知,标签没有闭合。但是在输出信息中,有

  • prettify()方法是将html文本按标准缩进格式返回。

  • tag.string:获取tag标签的文本内容。如果标签tag的内容中含有其他标签,则返回None。

以上仅是一个bs4使用的简单示例。我们从这个示例开始。

对象种类

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment .

  • Tag:是对html中标签(及其内容)和对应方法的封装。

  • NavigableString:字符串常被包含在tag内.Beautiful Soup用 NavigableString 类来包装tag中的字符串。这里注意理解:NavigableString就是对字符串及其方法的封装。

  • BeautifulSoup:对整个html文档内容及其方法的封装。

  • Comment:对注释内容及其方法的封装。Comment 对象是一个特殊类型的 NavigableString 对象。

所以,Beautiful Soup在解析html文档时,按照以上四种类型解析文档,并构成对应的树。
注意,BeautifulSoup在大部分情况下,可以当做Tag来使用。

节点的定位

解析html是为了获取标签中的信息。而要获得目标信息,首先需要定位到目标节点(标签)。

在Bs4中,使用tag.标签名的方式,可以定位到tag对象的第一个指定标签名的Tag对象。

示例:分析文本1

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(type(soup.title.string))
print(soup.head)
print(soup.p)

运行结果:

The Dormouse's story

The Dormouse's story

The Dormouse's story

The Dormouse's story

注意节点的类型:

soup.title是bs4.element.Tag类型的对象,soup.title.string是bs4.element.NavigableString类型的对象,其打印结果其实就是一段字符串。

信息提取

上面我们简单介绍了一下,如何定位到某个Tag节点。下面来介绍,如果获取该Tag节点的信息。

由于Tag对象是对标签内容及其方法的封装,可以直接通过.的方式访问其信息。

  • 获取Tag对象的类型
tag.name #获取标签名称:返回当前tag对象的标签名称。如果tag是

标签的封装,则返回'p'

  • 获取Tag对象的属性
tag['id']
tag.attrs['id'] #获取Tag节点的属性:这两种方式等价。使用中括号加上属性名
  • 获取Tag对象的文本内容(更具体的说,可以理解为,获取Tag节点的NavigableString子节点)
tag.string # 返回一个NavigableString对象

这个.string需要理解一下,一个Tag对象实际上对应一个标签,但是标签中的内容可以有纯字符串和子标签。这里的纯字符串被解析为NavigableString节点,而子标签被解析为Tag节点。

如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点,即NavigableString类型子节点。

如果一个tag仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同。

如果tag包含了多个子节点,tag就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None。

  • 获取Tag中的NavigableString对象以及子节点中的NavigableString对象。
#tag.strings   
#tag.stripped_strings #会忽略掉空格或空行。
#这两个方法都返回一个生成器 

for string in soup.strings:
    print(string)
关联选择

有时,不能一步定位到我们想要的节点。而需要先选中某一个节点,再以它为基准选择其子节点,父节点,兄弟节点等。

  • 子节点和子孙节点

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

tag的.children属性可以将tag的子节点以生成器方式输出:

print(soup.p.contents)
#结果为一列表

for child in soup.p.children:
    print(child)
#结果为多个子节点的单独输出

.contents和.children都是获取tag节点的直接子节点。如果要获取tag的所有子孙节点,那么使用.descendants属性。

.descendants 属性可以对所有tag的子孙节点进行先序遍历。

for child in soup.descendants:
    print(child)


  • 父节点和祖先节点

通过 .parent 属性来获取某个元素的父节点.

通过元素的 .parents 属性可以递归得到元素的所有父辈节点.

  • 兄弟节点

看一个简单例子:

sibling_soup = BeautifulSoup("text1text2")
print(sibling_soup.prettify())
# 
#  
#   
#    
#     text1
#    
#    
#     text2
#    
#   
#  
# 

因为标签和标签是同一层:他们是同一个元素的子节点,所以和可以被称为兄弟节点.一段文档以标准格式输出时,兄弟节点有相同的缩进级别.在代码中也可以使用这种关系.

在文档树中,使用 .next_sibling 和 .previous_sibling 属性来查询兄弟节点:

tag.next_sibling
tag.previous_sibling

在上述简单例子中,标签有 .next_sibling 属性,但是没有 .previous_sibling 属性,因为标签在同级节点中是第一个.同理,标签有 .previous_sibling 属性,却没有 .next_sibling 属性:

print(sibling_soup.b.previous_sibling)
# None
print(sibling_soup.c.next_sibling)
# None

例子中的字符串“text1”和“text2”不是兄弟节点,因为它们的父节点不同:

sibling_soup.b.string
# u'text1'

print(sibling_soup.b.string.next_sibling)
# None

值得注意:实际文档中的tag的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白.

下面给出一个html片段:

Elsie,
Lacie,
Tillie

如果以为第一个标签的 .next_sibling 结果是第二个标签,那就错了,真实结果是第一个标签和第二个标签之间的逗号和换行符:出错的原因是,没有深入理解BeautifulSoup的解析方式,节点应该有四种。

方法选择器(搜索文档树)

前面所讲的节点定位方法,都是基于html文档的结构,这种方式逻辑清晰,但是当文档结构复杂时,会很繁琐。所以接下来介绍更为强大的API。

下面将介绍两个API函数的使用。

find_all( name , attrs , recursive , string , **kwargs )
find( name , attrs , recursive , string , **kwargs )
  • find_all()

参数介绍:

  • name 参数可以查找所有名字为 name 的tag

  • attrs参数可以查找指定属性的tag,其中attrs为一字典,元素为属性名:属性值的键值对。

  • 调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False .

  • 通过 string 参数可以搜搜文档中的字符串内容.与 name 参数的可选值一样, string 参数接受 字符串 , 正则表达式 , 列表, True .

  • **kwargs参数:如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,

各个参数的使用:注:下面的html代码记为文本2

name

html='''

    
        Hello
    
    
        
  • Foo
  • Bar
  • Jay
  • Foo
  • Bar
''' from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'lxml') print(soup.find_all(name='ul')) print(type(soup.find_all(name='ul')[0])) for ul in soup.find_all(name='ul'): print(ul.find_all(name='li')) for ul in soup.find_all(name='ul'): print(ul.find_all(name='li')) for li in ul.find_all(name='li'): print(li.string)

运行结果:

[
  • Foo
  • Bar
  • Jay
,
  • Foo
  • Bar
] [
  • Foo
  • ,
  • Bar
  • ,
  • Jay
  • ] [
  • Foo
  • ,
  • Bar
  • ] [
  • Foo
  • ,
  • Bar
  • ,
  • Jay
  • ] Foo Bar Jay [
  • Foo
  • ,
  • Bar
  • ] Foo Bar
    • 从上可知,find_all会将查询到的节点以列表形式返回。列表中的元素为bs4.element.Tag类型。

    attrs

    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'lxml')
    print(soup.find_all(attrs={'id': 'list-1'}))
    print(soup.find_all(attrs={'name': 'elements'})) #还可以写成一下等价形式
    
    
    print(soup.find_all(id='list-1'))
    print(soup.find_all(class_='element')) #因为class为python关键字,所以使用
                                            #class_来加以区分。
    

    string

    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'lxml')
    print(soup.find_all(string=re.compile('link')))
    print(soup.find_all(text=re.compile('link')))#这两条语句等价
    
    
    

    这里的string=...与text=...等价。使用text=...是,将需要匹配的信息作为要查找的属性。

    • find()方法与find_all()类似,不介绍。
    CSS选择器

    如果熟悉Web开发,也可以使用CSS选择器来定位节点。
    使用select()方法。tag.select(),选择tag下的指定节点。

    以文本2中的html源码为示例:

    html='''
    

    Hello

    • Foo
    • Bar
    • Jay
    • Foo
    • Bar
    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'))
    print(type(soup.select('ul')[0]))
    

    运行结果:

    [

    Hello

    ] [
  • Foo
  • ,
  • Bar
  • ,
  • Jay
  • ,
  • Foo
  • ,
  • Bar
  • ] [
  • Foo
  • ,
  • Bar
  • ]

    select方法会将定位到的节点以列表形式返回,列表中的元素为bs4.element.Tag类型。

    参考资料
    • Python3 网络爬虫开发实战(第2版)

    • Beautiful Soup 中文文档

    转载请注明:文章转载自 www.mshxw.com
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号