zoukankan      html  css  js  c++  java
  • python之Beautiful Soup的基本用法

    Beautiful Soup就是Python的一个HTML或XML的解析库,可以用它来方便地从网页中提取数据。它有如下三个特点:

    • Beautiful Soup提供一些简单的、Python式的函数来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
    • Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为UTF-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时你仅仅需要说明一下原始编码方式就可以了。
    • Beautiful Soup已成为和lxml、html6lib一样出色的Python解释器,为用户灵活地提供不同的解析策略或强劲的速度。

    首先,我们要安装它:pip install bs4,然后安装 pip install beautifulsoup4.

    一、Beautiful Soup支持的解析器

     下面我们以lxml解析器为例:

    from bs4 import BeautifulSoup
    soup = BeautifulSoup('<p>Hello</p>', 'lxml')
    print(soup.p.string)

    结果:

    Hello

    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')
    #调用prettify()方法。这个方法可以把要解析的字符串以标准的缩进格式输出
    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><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('输出结果为title节点加里面的文字内容: ',soup.title)
    print('输出它的类型: ',type(soup.title))
    print('输出节点的文本内容: ',soup.title.string)
    print('结果是节点加其内部的所有内容: ',soup.head)
    print('结果是第一个p节点的内容: ',soup.p)
    print('利用name属性获取节点的名称: ',soup.title.name)
    #这里需要注意的是,有的返回结果是字符串,有的返回结果是字符串组成的列表。
    # 比如,name属性的值是唯一的,返回的结果就是单个字符串。
    # 而对于class,一个节点元素可能有多个class,所以返回的是列表。
    print('每个节点可能有多个属性,比如id和class等: ',soup.p.attrs)
    print('选择这个节点元素后,可以调用attrs获取所有属性: ',soup.p.attrs['name'])
    print('获取p标签的name属性值: ',soup.p['name'])
    print('获取p标签的class属性值: ',soup.p['class'])
    print('获取第一个p节点的文本: ',soup.p.string)

    结果:

    输出结果为title节点加里面的文字内容:
    <title>The Dormouse's story</title>
    输出它的类型:
    <class 'bs4.element.Tag'>
    输出节点的文本内容:
    The Dormouse's story
    结果是节点加其内部的所有内容:
    <head><title>The Dormouse's story</title></head>
    结果是第一个p节点的内容:
    <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
    利用name属性获取节点的名称:
    title
    每个节点可能有多个属性,比如id和class等:
    {'class': ['title'], 'name': 'dromouse'}
    选择这个节点元素后,可以调用attrs获取所有属性:
    dromouse
    获取p标签的name属性值:
    dromouse
    获取p标签的class属性值:
    ['title']
    获取第一个p节点的文本:
    The Dormouse's story

    在上面的例子中,我们知道每一个返回结果都是bs4.element.Tag类型,它同样可以继续调用节点进行下一步的选择。

    html = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'lxml')
    print('获取了head节点元素,继续调用head来选取其内部的head节点元素:
    ',soup.head.title)
    print('继续调用输出类型:
    ',type(soup.head.title))
    print('继续调用输出内容:
    ',soup.head.title.string)

    结果:

    获取了head节点元素,继续调用head来选取其内部的head节点元素:
     <title>The Dormouse's story</title>
    继续调用输出类型:
     <class 'bs4.element.Tag'>
    继续调用输出内容:
     The Dormouse's story

    三、方法选择器

    (1)find_all()
    find_all,顾名思义,就是查询所有符合条件的元素。给它传入一些属性或文本,就可以得到符合条件的元素,它的功能十分强大。

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

    他的用法:

    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('查询所有ul节点,返回结果是列表类型,长度为2:
    ',soup.find_all(name='ul'))
    print('每个元素依然都是bs4.element.Tag类型:
    ',type(soup.find_all(name='ul')[0]))
    #将以上步骤换一种方式,遍历出来
    for ul in soup.find_all(name='ul'):
        print('输出每个u1:',ul.find_all(name='li'))
    #遍历两层
    for ul in soup.find_all(name='ul'):
        print('输出每个u1:',ul.find_all(name='li'))
        for li in ul.find_all(name='li'):
            print('输出每个元素:',li.string)

    结果:

    查询所有ul节点,返回结果是列表类型,长度为2:
     [<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>]
    每个元素依然都是bs4.element.Tag类型:
     <class 'bs4.element.Tag'>
    输出每个u1: [<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
    输出每个u1: [<li class="element">Foo</li>, <li class="element">Bar</li>]
    输出每个u1: [<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
    输出每个元素: Foo
    输出每个元素: Bar
    输出每个元素: Jay
    输出每个u1: [<li class="element">Foo</li>, <li class="element">Bar</li>]
    输出每个元素: Foo
    输出每个元素: Bar

    (2) attrs()

    除了根据节点名查询,我们也可以传入一些属性来查询,示例如下:

    html='''
    <div class="panel">
        <div class="panel-heading">
            <h4>Hello</h4>
        </div>
        <div class="panel-body">
            <ul class="list" id="list-1" name="elements">
                <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('返回符合id为list-1的所有节点:
    ',soup.find_all(attrs={'id': 'list-1'}))
    print('返回符合name为elements的所有节点:
    ',soup.find_all(attrs={'name': 'elements'}))
    #对于一些常用的属性,比如id和class等,我们可以不用attrs来传递
    print('返回符合id为list-1的所有节点(简单版):
    ',soup.find_all(id='list-1'))
    #而对于class来说,由于class在Python里是一个关键字,所以后面需要加一个下划线
    print('返回符合name为elements的所有节点(简单版):
    ',soup.find_all(class_='element'))

    结果:

    返回符合id为list-1的所有节点:
     [<ul class="list" id="list-1" name="elements">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    <li class="element">Jay</li>
    </ul>]
    返回符合name为elements的所有节点:
     [<ul class="list" id="list-1" name="elements">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    <li class="element">Jay</li>
    </ul>]
    返回符合id为list-1的所有节点(简单版):
     [<ul class="list" id="list-1" name="elements">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    <li class="element">Jay</li>
    </ul>]
    返回符合name为elements的所有节点(简单版):
     [<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>]

    (3) text
    text参数可用来匹配节点的文本,传入的形式可以是字符串,可以是正则表达式对象,示例如下:

    import re
    html='''
    <div class="panel">
        <div class="panel-body">
            <a>Hello, this is a link</a>
            <a>Hello, this is a link, too</a>
        </div>
    </div>
    '''
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'lxml')
    #这里在find_all()方法中传入text参数,该参数为正则表达式对象
    # 结果返回所有匹配正则表达式的节点文本组成的列表。
    print('含link列表:
    ',soup.find_all(text=re.compile('link')))

    结果:

    列表:
     ['Hello, this is a link', 'Hello, this is a link, too']

    (4) find()

    除了find_all()方法,还有find()方法,只不过后者返回的是单个元素,也就是第一个匹配的元素,而前者返回的是所有匹配的元素组成的列表。示例如下:

    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.find(name='ul'))
    print('返回第一个匹配的节点元素类型:
    ',type(soup.find(name='ul')))
    print('返回第一个匹配的节点元素:
    ',soup.find(class_='list'))

    结果:

    返回第一个匹配的节点元素:
     <ul class="list" id="list-1">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    <li class="element">Jay</li>
    </ul>
    返回第一个匹配的节点元素类型:
     <class 'bs4.element.Tag'>
    返回第一个匹配的节点元素:
     <ul class="list" id="list-1">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    <li class="element">Jay</li>
    </ul>

    四、CSS选择器

    Beautiful Soup还提供了另外一种选择器,那就是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('选择panel下的panel-heading标签:
    ',soup.select('.panel .panel-heading'))
    print('选择ul下的li标签:
    ',soup.select('ul li'))
    print('选择list-2下的element标签:
    ',soup.select('#list-2 .element'))
    print('返回第一个u1的类型:
    ',type(soup.select('ul')[0]))
    #嵌套选择
    for ul in soup.select('ul'):
        print('打印每个u1下的li标签:
    ',ul.select('li'))
    #尝试获取每个ul节点的id属性:
    for ul in soup.select('ul'):
        print('打印每个u1下的id的内容:
    ',ul['id'])
        print('打印每个u1下的id的内容(另一种方法):
    ',ul.attrs['id'])
    #获取文本
    for li in soup.select('li'):
        print('获取li的文本信息:', li.get_text())
        print('获取li的文本信息(另一种方法):', li.string)

    结果:

    选择panel下的panel-heading标签:
     [<div class="panel-heading">
    <h4>Hello</h4>
    </div>]
    选择ul下的li标签:
     [<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>]
    选择list-2下的element标签:
     [<li class="element">Foo</li>, <li class="element">Bar</li>]
    返回第一个u1的类型:
     <class 'bs4.element.Tag'>
    打印每个u1下的li标签:
     [<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
    打印每个u1下的li标签:
     [<li class="element">Foo</li>, <li class="element">Bar</li>]
    打印每个u1下的id的内容:
     list-1
    打印每个u1下的id的内容(另一种方法):
     list-1
    打印每个u1下的id的内容:
     list-2
    打印每个u1下的id的内容(另一种方法):
     list-2
    获取li的文本信息: Foo
    获取li的文本信息(另一种方法): Foo
    获取li的文本信息: Bar
    获取li的文本信息(另一种方法): Bar
    获取li的文本信息: Jay
    获取li的文本信息(另一种方法): Jay
    获取li的文本信息: Foo
    获取li的文本信息(另一种方法): Foo
    获取li的文本信息: Bar
    获取li的文本信息(另一种方法): Bar

    到此,Beautiful Soup的用法基本就介绍完了,最后做一下简单的总结。

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

    原文链接:https://blog.csdn.net/qq_35490191/article/details/80598620

  • 相关阅读:
    栈和其他寄存器大小
    checksec的安装及初步使用(新版)
    KMP算法之Next数组详解
    向上取整的三种方法
    C++STL(Standard Template Library,即标准模版库)——Map容器
    JS基础语法一
    JS函数学习
    JS对象学习(二)
    JavaStript对象学习(一)
    CSS3新特性学习(2)
  • 原文地址:https://www.cnblogs.com/xiao02fang/p/13269984.html
Copyright © 2011-2022 走看看