• BS4


    Beautiful Soup 库一般被称为bs4库,支持Python3,是我们写爬虫非常好的第三方库。因用起来十分的简便流畅。所以也被人叫做“美味汤”。下文会介绍该库的最基本的使用。

    安装 Beautiful Soup

    Beautiful Soup 4 通过PyPi发布,所以如果你无法使用系统包管理安装,那么也可以通过easy_install 或 pip 来安装。包的名字是 beautifulsoup4 ,这个包兼容Python2和Python3。

    easy_install beautifulsoup4

    pip install beautifulsoup4

    如果你没有安装 easy_install 或 pip ,那你也可以 下载BS4的源码 ,然后通过setup.py来安装。

    Python setup.py install

    安装解析器

    Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是lxml。根据操作系统不同,可以选择下列方法来安装lxml:

    apt-get install Python-lxml

    easy_install lxml

    pip install lxml

    另一个可供选择的解析器是纯Python实现的html5lib, html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:

    apt-get install Python-html5lib

    easy_install html5lib

    pip install html5lib

    下表列出了主要的解析器,以及它们的优缺点:

    解析器使用方法优势劣势
    Python标准库 BeautifulSoup(markup,"html.parser")
    • Python的内置标准库
    • 执行速度适中
    • 文档容错能力强
    • Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
    lxml HTML 解析器 BeautifulSoup(markup,"lxml")
    • 速度快
    • 文档容错能力强
    • 需要安装C语言库
    lxml XML 解析器

    BeautifulSoup(markup,["lxml-xml"])

    BeautifulSoup(markup,"xml")

    • 速度快
    • 唯一支持XML的解析器
    • 需要安装C语言库
    html5lib BeautifulSoup(markup,"html5lib")
    • 最好的容错性
    • 以浏览器的方式解析文档
    • 生成HTML5格式的文档
    • 速度慢
    • 不依赖外部扩展

    推荐使用lxml作为解析器,因为效率更高。在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib,因为那些Python版本的标准库中内置的HTML解析方法不够稳定。

    提示:如果一段HTML或XML文档格式不正确的话,那么在不同的解析器中返回的结果可能是不一样的,查看 解析器之间的区别 了解更多细节。

    这里我们先简单的讲解一下bs4库的使用,暂时不去考虑如何从web上抓取网页,假设我们需要爬去的html是如下这么一段:

    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
    http://example.com/elsie" class="sister" id="link1">Elsie,
    http://example.com/lacie" class="sister" id="link2">Lacie and
    http://example.com/tillie" class="sister" id="link3">Tillie;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    </html>
    1 #导入bs4模块
    2 from bs4 import BeautifulSoup
    3 soup = BeautifulSoup(html,'html.parser')
    4 #输出结果
    5 print(soup.prettify())

    结果:

    `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
    http://example.com/elsie" class="sister" id="link1"&gt;Elsie,
    http://example.com/lacie" class="sister" id="link2"&gt;Lacie and
    http://example.com/tillie" class="sister" id="link3"&gt;Tillie;
    and they lived at the bottom of a well.
      </p>
      <p class="story">
       ...
      </p>
     </body>
    </html>

    可以看到bs4库将网页文件变成了一个soup的类型,事实上,bs4库 是解析、遍历、维护、“标签树“的功能库。

    通俗一点说就是: bs4库把html源代码重新进行了格式化,从而方便我们对其中的节点、标签、属性等进行操作。

     1 #找到文档的title
     2 print(soup.title)
     3 # <title>The Dormouse's story</title>
     4 
     5 #title的name值
     6 print(soup.title.name)
     7 # u'title'
     8 
     9 #title中的字符串String
    10 print(soup.title.string)
    11 # u'The Dormouse's story'
    12 
    13 #title的父亲节点的name属性
    14 print(soup.title.parent.name)
    15 # u'head'
    16 
    17 #文档的第一个找到的段落
    18 print(soup.p)
    19 # <p class="title"><b>The Dormouse's story</b></p>
    20 
    21 #找到的p的class属性值
    22 print(soup.p['class'])
    23 # u'title'
    24 
    25 #找到a标签
    26 print(soup.a)
    27 # http://example.com/elsie" id="link1">Elsie
    28 
    29 #找到所有的a标签
    30 print(soup.find_all('a'))
    31 # [http://example.com/elsie" id="link1">Elsie,
    32 #  http://example.com/lacie" id="link2">Lacie,
    33 #  http://example.com/tillie" id="link3">Tillie]
    34 
    35 #找到id值等于3的a标签
    36 print(soup.find(id="link3"))
    37 # http://example.com/tillie" id="link3">Tillie

    从文档中找到所有<a>标签的链接:

    1 for link in soup.find_all('a'):
    2     print(link.get('href'))
    3     # http://example.com/elsie
    4     # http://example.com/lacie
    5     # http://example.com/tillie

    从文档中获取所有文字内容:

    print(soup.get_text())
    
    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.
    ...

     对象的种类

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

    • Tag:和html中的Tag基本没有区别,可以简单上手使用

    • NavigableString: 被包裹在tag内的字符串

    • BeautifulSoup: 表示一个文档的全部内容,大部分的时候可以把他看做一个tag对象,支持遍历文档树和搜索文档树方法。

    • Comment:这是一个特殊的NavigableSting对象,在出现在html文档中时,会以特殊的格式输出,比如注释类型。

     搜索文档树的最简单的方法就是搜索你想获取tag的的name:

    1 soup.head
    2 # <head><title>The Dormouse's story</title></head>
    3 
    4 soup.title
    5 # <title>The Dormouse's story</title>

    如果你还想更深入的获得更小的tag:例如我们想找到body下的被b标签包裹的部分

    1 soup.body.b
    2 # <b>The Dormouse's story</b>

    获取所有的标签,这个时候需要find_all()方法,他返回一个列表类型。

    tag=soup.find_all('a')  #返回的是列表
    # [<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>]
    
    #假设我们要找到a标签中的第二个元素:
    need = tag[1]
    #简单吧

    子节点

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

     1 head_tag = soup.head
     2 head_tag
     3 # <head><title>The Dormouse's story</title></head>
     4 
     5 head_tag.contents
     6 [<title>The Dormouse's story</title>]
     7 title_tag = head_tag.contents[0]
     8 print(title_tag)
     9 # <title>The Dormouse's story</title>
    10 title_tag.contents
    11 # [u'The Dormouse's story']
    • 另外通过tag的 .children生成器,可以对tag的子节点进行循环:
    1 for child in title_tag.children:
    2     print(child)
    3     # The Dormouse's story
    • 这种方式只能遍历出子节点。如何遍历出子孙节点呢?

    子孙节点:比如 head.contents 的子节点是<title>The Dormouse's story</title>,这里 title本身也有子节点:‘The Dormouse‘s story’ 。这里的‘The Dormouse‘s story’也叫作head的子孙节点.

    1 for child in head_tag.descendants:
    2     print(child)
    3     # <title>The Dormouse's story</title>
    4     # The Dormouse's story

    找到tag下的所有的文本内容

    1. 如果该tag只有一个子节点(NavigableString类型):直接使用tag.string就能找到。
    2. 如果tag有很多个子、孙节点,并且每个节点里都string:

    我们可以用迭代的方式将其全部找出:

     1 for string in soup.strings:
     2     print(repr(string))
     3     # u"The Dormouse's story"
     4     # u'
    
    '
     5     # u"The Dormouse's story"
     6     # u'
    
    '
     7     # u'Once upon a time there were three little sisters; and their names were
    '
     8     # u'Elsie'
     9     # u',
    '
    10     # u'Lacie'
    11     # u' and
    '
    12     # u'Tillie'
    13     # u';
    and they lived at the bottom of a well.'
    14     # u'
    
    '
    15     # u'...'
    16     # u'
    '

    输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容:(全部是空格的行会被忽略掉,段首和段末的空白会被删除)

     1 for string in soup.stripped_strings:
     2     print(repr(string))
     3     # u"The Dormouse's story"
     4     # u"The Dormouse's story"
     5     # u'Once upon a time there were three little sisters; and their names were'
     6     # u'Elsie'
     7     # u','
     8     # u'Lacie'
     9     # u'and'
    10     # u'Tillie'
    11     # u';
    and they lived at the bottom of a well.'
    12     # u'...'

    父节点

    继续分析文档树,每个tag或字符串都有父节点:被包含在某个tag中

    .parent

    通过 .parent 属性来获取某个元素的父节点.在例子的文档中,<head>标签是<title>标签的父节点:

    1 title_tag = soup.title
    2 title_tag
    3 # <title>The Dormouse's story</title>
    4 title_tag.parent
    5 # <head><title>The Dormouse's story</title></head>

    文档title的字符串也有父节点:<title>标签

    1 title_tag.string.parent
    2 # <title>The Dormouse's story</title>

    文档的顶层节点比如<html>的父节点是 BeautifulSoup 对象:

    1 html_tag = soup.html
    2 type(html_tag.parent)
    3 # <class 'bs4.BeautifulSoup'>

    BeautifulSoup 对象的 .parent 是None:

    1 print(soup.parent)
    2 # None

    .parents

    通过元素的 .parents 属性可以递归得到元素的所有父辈节点,下面的例子使用了 .parents方法遍历了<a>标签到根节点的所有节点.

     1 link = soup.a
     2 link
     3 # <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
     4 for parent in link.parents:
     5     if parent is None:
     6         print(parent)
     7     else:
     8         print(parent.name)
     9 # p
    10 # body
    11 # html
    12 # [document]
    13 # None

    有关兄弟节点、回退和前进以及等内容和子节点、父节点差不多,详情请参考官方文档

  • 相关阅读:
    IO文件
    eclipse快捷键
    异常
    多例模式
    单例模式
    访问控制权限
    系统常见包

    查找
    【avalon】offsetParent
  • 原文地址:https://www.cnblogs.com/freeman818/p/7095930.html
Copyright © 2020-2023  润新知