• 爬虫之BeautifulSoup库


    文档:https://beautifulsoup.readthedocs.io/zh_CN/latest/

    一、开始

    解析库

    # 安装解析库
    pip3 install lxml
    pip3 install html5lib
    

    基本使用

    html = """
    <html>
      <head>
      <title>The Dormouse's story</title>
      </head>
      <body>
        <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, "lxml")
    print(soup.prettify())    # 格式化代码,自动补全,容错处理
    print(soup.title.string)  # The Dormouse's story
    """
    <html>
      <head>
      <title>The Dormouse's story</title>
      </head>
      <body>
        <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
       </body>
    </html>
    """
    View Code

    二、标签选择器

    选择元素

    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">
          beautifulsoup4
          <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
          <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
          <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
        </p>
        <p class="story">...</p>
       </body>
    </html>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, "lxml")
    print(soup.title)       # <title>The Dormouse's story</title>
    print(type(soup.title)) # <class 'bs4.element.Tag'>
    print(soup.head)
    """
    <head>
    <title>The Dormouse's story</title>
    </head>
    """
    print(soup.p)  # <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
    View Code 

    获取名称

    from bs4 import BeautifulSoup
    html = "<html><title>The Dormouse's story</title></html>"
    soup = BeautifulSoup(html, "lxml")
    print(soup.title.name)  # title

    获取属性值

    from bs4 import BeautifulSoup
    html = """
    <p class="title" name="pd"><b>The Dormouse's story</b></p>
    """
    soup = BeautifulSoup(html, "lxml")
    print(soup.p.attrs["name"])  # pd
    print(soup.p["name"])        # pd

    获取内容

    from bs4 import BeautifulSoup
    html = """
    <p class="title" name="pd"><b>The Dormouse's story</b></p>
    """
    soup = BeautifulSoup(html, "lxml")
    print(soup.p.string)  # The Dormouse's story

    嵌套选择

    from bs4 import BeautifulSoup
    html = """
    <head>
    <title>The Dormouse's story</title>
    </head>
    """
    soup = BeautifulSoup(html, "lxml")
    print(soup.head.title.string)  # The Dormouse's story

    子节点和子孙节点

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

    from bs4 import BeautifulSoup
    html = """
    <p class="story">
    beautifulsoup4
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
    </p>
    """
    soup = BeautifulSoup(html, "lxml")
    print(soup.p.contents)
    # ['
    beautifulsoup4
    ', <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, '
    ', <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, '
    ', <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>, '
    ']
    View Code

    通过tag的 .children 生成器,可以对tag的子节点进行循环:

    html = """
    <html>
    <head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><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.p.children)  # <list_iterator object at 0x00000000031F6C88>
    for i, child in enumerate(soup.p.children):
        print(i, child)     # 0 <b>The Dormouse's story</b>
    View Code

    .contents 和 .children 属性仅包含tag的直接子节点。例如,<head>标签只有一个直接子节点<title>;

    但是<title>标签也包含一个子节点:字符串 "The Dormouse’s story",这种情况下字符串 "The Dormouse’s story" 也属于<head>标签的子孙节点,.descendants 属性可以对所有tag的子孙节点进行递归循环:

    html = """
    <html>
    <head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>
    <p class="story">...</p>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, "lxml")
    print(soup.p.descendants)  # <generator object descendants at 0x0000000000727200>
    for i, child in enumerate(soup.p.descendants):
        print(i, child)
    """
    0 <b>The Dormouse's story</b>
    1 The Dormouse's story
    """
    View Code

    上面的例子中,,<head>标签只有一个子节点,但是有2个子孙节点。

    父节点和祖先节点

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

    html = """
    <p class="title"><b>The Dormouse's story</b></p>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, "lxml")
    print(soup.b.parent)  # <p class="title"><b>The Dormouse's story</b></p>

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

    html = """
    <html><head><title>The Dormouse's story</title></head></html>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, "lxml")
    print(soup.title.parents)  # <generator object parents at 0x0000000000AA7200>
    for i, parent in enumerate(soup.title.parents):
        print(i, parent)
    """
    0 <head><title>The Dormouse's story</title></head>
    1 <html><head><title>The Dormouse's story</title></head></html>
    2 <html><head><title>The Dormouse's story</title></head></html>
    """
    View Code

    兄弟节点

    html = """
    <p class="story">
    Once upon a time there were three little sisters
    <a id="link1">Elsie</a>
    <a id="link2">Lacie</a>
    <a id="link3">Tillie</a>
    they lived at the bottom of a well
    </p>
    
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, "lxml")
    print(list(soup.a.next_siblings))
    print(list(soup.a.previous_siblings))
    """
    ['
    ', <a id="link2">Lacie</a>, '
    ', <a id="link3">Tillie</a>, '
    they lived at the bottom of a well
    ']
    ['
    Once upon a time there were three little sisters
    ']
    """
    View Code

    三、标准选择器

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

    name参数

    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_all("ul"))
    """
    [<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>]
    """
    for ul in soup.find_all("ul"):
        print(ul.find_all("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>]
    """
    print(type(soup.find_all("ul")[0]))  # <class 'bs4.element.Tag'>
    View Code

    attrs参数

    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_all(attrs={"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>]
    """
    View Code

    或者不使用attrs

    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>
        </div>
    </div>
    """
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, "lxml")
    print(soup.find_all(id="list-1"))
    """
    [<ul class="list" id="list-1">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    <li class="element">Jay</li>
    </ul>]
    """
    print(soup.find_all(class_="element"))
    # [<li class="element">Foo</li>, <li class="element">Bar</li>, <li class="element">Jay</li>]
    View Code

    text参数:不是返回标签,而是返回内容

    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_all(text="Foo"))  # ['Foo', 'Foo']
    View Code

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

    find返回单个元素,find_all返回所有元素。

    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("ul"))
    """
    <ul class="list" id="list-1">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    <li class="element">Jay</li>
    </ul>
    """
    print(soup.find("page"))  # None
    View Code

    find_parents() 和 find_parent()

    find_parents()返回所有祖先节点,find_parent()返回直接父节点。

    find_next_siblings() 和 find_next_sibling()

    find_next_siblings()返回后面所有兄弟节点,find_next_sibling()返回后面第一个兄弟节点。

    find_previous_siblings() 和 find_previous_sibling()

    find_previous_siblings()返回前面所有兄弟节点,find_previous_sibling()返回前面第一个兄弟节点。

    find_all_next() 和 find_next()

    find_all_next()返回节点后所有符合条件的节点,find_next()返回第一个符合条件的节点。

    find_all_previous() 和 find_previous()

    find_all_previous()返回节点后所有符合条件的节点,find_previous()返回第一个符合条件的节点。

    四、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"))
    """
    [<div class="panel-heading">
    <h4>Hello</h4>
    </div>]
    """
    print(soup.select("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>]
    print(soup.select("#list-2 .element"))
    # [<li class="element">Foo</li>, <li class="element">Bar</li>]
    print(soup.select("ul")[1])
    """
    <ul class="list list-small" id="list-2">
    <li class="element">Foo</li>
    <li class="element">Bar</li>
    </ul>
    """
    View Code
    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")
    for ul in soup.select("ul"):
        print(ul.select("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>]
    """
    View Code

    获取属性:

    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")
    for ul in soup.select("ul"):
        print(ul["id"])
        print(ul.attrs["id"])
    """
    list-1
    list-1
    list-2
    list-2
    """
    View Code

    获取内容:

    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")
    for li in soup.select("li"):
        print(li.get_text())
    """
    Foo
    Bar
    Jay
    Foo
    Bar
    """
    View Code

    五、总结

    • 推荐使用lxml解析库,必要时使用html.parser
    • 标签选择筛选功能弱但是速度快
    • 建议使用find()、find_all() 查询匹配单个结果或者多个结果
    • 如果对CSS选择器熟悉建议使用select()
    • 记住常用的获取属性和文本值的方法
  • 相关阅读:
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    线性表——数组实现
    this指针与const成员函数
    类对象拷贝是不是赋值操作??
    你真的理解内联函数吗?
    名字查找先于类型检查:函数重载与作用域
    谈谈函数调用
    推荐形参使用常量引用:void func(const T &);
  • 原文地址:https://www.cnblogs.com/believepd/p/10657866.html
Copyright © 2020-2023  润新知