Class 14 - 2 解析庫 -- Beautiful Soup

Beautiful Soup是 Python 的一個 HTML 或 XML 的解析庫,庫藉助網頁的結構和屬性等特性來解析網頁css

  1. 解析器
    • Beautiful Soup在解析時依賴解析器,除了支持 Python 標準庫中的 HTML 解析器外,還支持一些第三方解析器(好比 lxml )。 
    • 以上對比,lxml 解析器有解析 HTML 和 XML 的功能,速度’快,容錯能力強,因此推薦使用它。html

    • 若是使用 lxml,那麼在初始化 Beautiful Soup 時,能夠把第二個參數改成 lxml。例:正則表達式

      from bs4 import BeautifulSoup
      Soup = BeautifulSoup('<p>Hello</p>','lxml')
      print(Soup.p.string)
  2. 基本用法
    • html = '''
      <html><head><title>The Dormouse's story</title></head>
      <body>
      <p class ='title' name='dromouse'><b>The Dormouse's story</p></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
      View Code
      • 首先聲明變量 html,它是一個 HTML 字符串。須要注意的是,它並非一個完整的 HTML 字符串,由於 body 和 html 節點都沒有閉合。 接着,將它看成第一個參數傳給 BeautifulSoup 對 象,對象的第二個參數爲解析器的類型(這裏使用 lxml ),此時就完成了 BeaufulSoup 對象的初始化。 而後,將這個對象賦值給 soup 變量。數據結構

      • 接下來,調用 soup 的各個方法和屬性解析HTML 代碼。ide

      • 首先,調用 prettify()方法能夠把要解析的字符串以標準的縮進格式輸出注意:輸出結果裏面包含 body 和 html 節點,也就是說對於不標準的 HTML 字符串 Beautifol Soup , 能夠自動更正格式 這一步不是由 prettify()方法作的,而是在初始化 Beautifol Soup 時就完成了函數

      • 而後調用 soup.title.string,這其實是輸出 HTML 中 title 節點的文本內容。因此,soup.title 能夠選出 HTML 中的 title 節點,再調用 string 屬性就能夠獲得裏面的文本了,因此咱們能夠經過 簡單調用幾個屬性完成文本提取。this

  3. 節點選擇器spa

    • 直接調用節點的名稱就能夠選擇節點元素,再調用 string 屬性就能夠獲得節點內的文本。 若是單個節點結構層次很是清晰,能夠選用這種方式來解析3d

    • 選擇元素code

      • html = '''
        --snip--
        '''
        from bs4 import BeautifulSoup
        soup=BeautifulSoup(html,'lxml')
        print(soup.title)
        print(type(soup.title))
        print(soup.title.string)
        print(soup.head)
        print(soup.p)
        輸出:
        <title>The Dormouse's story</title>
        <class 'bs4.element.Tag'>
        The Dormouse's story
        <head><title>The Dormouse's story</title></head>
        <p class="title" name="dromouse"><b>The Dormouse's story</b></p>
        • 首先輸出 title 節點的選擇結果,輸出結果正是 title 節 點加里面的文字內容。

        • 接下來,輸出它的類型,是 bs4.element.Tag 類型,這是 Beautiful Soup 中一個 重要的數據結構。 通過選擇器選擇後,選擇結果都是這種 Tag 類型。 Tag 具備一些屬性,好比 調用string 屬性能夠獲得節點的文本內容,因此接下來的輸出結果正是節點的文本內容。嘗試選擇了 head 節點,也是節點加其內部的全部內容。

        • 選擇了 p 節點。 不過此次狀況比較特殊,咱們發現結果是第一個 p 節點的內容,後面的幾個 p 節點並無選到。 也就是說,當有多個節點時,這種選擇方式只會選擇到第一個匹配的節點,其餘的後面節點都會忽略

    • 提取信息      

      1. 獲取名稱

        • 利用 name 屬性獲取節點的名稱,選取 title 節點,而後調用 name屬性就能夠獲得節點名稱:

          print(soup.title.name)
          輸出:
          title
      2. 獲取屬性

        • 每一個節點可能有多個屬性,如 id class 等,選擇這個節點元素後,能夠調用 attrs 獲取全部屬性:
          print(soup.p.attrs)
          print(soup.p.attrs['name'])
          輸出:
          {'class':['title'], 'name':'dromouse'}
          dromouse

          attrs 的返回結果是字典形式,把選擇的節點的全部屬性和屬性值組合成一個字典。 若是要獲取 name 屬性,就至關於從字典中獲取某個鍵值,只須要用中括號加屬性名就能夠 好比,要獲取 name 屬性,就能夠經過 attrs['name'] 來獲得

        • 能夠不用寫 attrs ,直接在節點元素後面加中 括號,傳入屬性名就能夠獲取屬性值了。示例:
          print(soup.p['name'])
          print(soup.p['class'])
          輸出:
          dromouse
          ['title']

          注意:有的返回結果是字符串,有的返回結果是字符串組成的列表。好比, name 屬性的值是惟一的,返回的結果就是單個字符串。而對於 class 一個節點元素可能有多個 class 因此 返回的是列表

      3. 獲取內容
        • 能夠利用 string 屬性獲取節點元素包含的文本內容,如獲取第一個 p 節點的文本:
          print(soup.p.string)
          輸出:
          The Dormouse's story

          注意:這裏選擇到的 p 節點是第一個 p 節點,獲取的文本也是第一個 p 節點裏面的文本。

    • 嵌套選擇

      • 以上例子,每一個返回結果都是 bs4 element.Tag 類型,一樣能夠繼續調用節點進行下一步的選擇。如:獲取了 head 節點元素,能夠繼續調用 head 來選取內部的 head 節點元素:

        html = '''
        <html><head><title>The Dormouse's story</title></head>
        <body>
        '''
        from bs4 import BeautifulSoup
        soup=BeautifulSoup(html,'lxml')
        print(soup.head.title.string)
        print(type(soup.head.title))
        輸出:
        The Dormouse's story
        <class 'bs4.element.Tag'>

        第一行結果是調用 head 以後再次調用 title 而選擇的 title 節點元素。輸出類型仍然是 bs4.element.Tag 類型。在 Tag 類型的基礎上再次選擇獲得的依然仍是 Tag 類型,每次返回的結果都相同。因此這樣就能夠作嵌套選擇了。   最後,輸出它的 string 屬性,也就是節點裏的文本內容

    • 關聯選擇

      1. 子節點和子孫節點 

        • 選取節點元素以後,若是想要獲取它的直接子節點,能夠調用 contents 屬性。示例:

          html = '''
          <html>
          <head>
          <title>The Dormouse's story</title>
          </head>
          <body>
          <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">
          <span>Elsie</span>
          </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 class="story">...</p>
          '''
          from bs4 import BeautifulSoup
          soup=BeautifulSoup(html,'lxml')
          print(soup.p.contents)
          輸出:
          ['\n    Once upon a time there were three little sisters; and their names were\n    ', <a class="sister" href="http://example.com/elsie" id="link1">
          <span>Elsie</span>
          </a>, '\n', <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>, '\nand\n', <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>, '\nand they lived at the bottom of a well.\n']
          View Code

          返回結果是列表形式。p 節點裏既包含文本,又含節點,最後會將它們以列表形式 統一返回

          注意:列表中的每一個元素都是 p 節點的直接子節點。 如第一個a節點裏包含一層 span 節點,這至關於孫子節點了,可是返回結果並無單獨把 span 節點選出來。因此, contents 屬性獲得的結果是直接子節點的列表

          一樣,能夠調用 children 屬性獲得相應的結果:

          from bs4 import BeautifulSoup
          soup=BeautifulSoup(html,'lxml')
          print(soup.p.children)
          for i,child in enumerate(soup.p.children):   
          """enumerate() 函數用於將一個可遍歷的數據對象(如列表、元組或字符串)組合爲一個索引序列,同時列出數據和數據下標,通常用在 for 循環當中"""
          print(i,child) 輸出:
          <list_iterator object at 0x000002192389F630>
          0 
              Once upon a time there were three little sisters; and their names were
              
          1 <a class="sister" href="http://example.com/elsie" id="link1">
          <span>Elsie</span>
          </a>
          2 
          
          3 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
          4 
          and
          
          5 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
          6 
          and they lived at the bottom of a well.
          View Code

          調用了 children 屬性來選擇,返回結果是生成器類型。再使用 for 循環輸出相應的內容。

          若是要獲得全部的子孫節點的話,能夠調用 descendants 屬性:

          from bs4 import BeautifulSoup
          soup=BeautifulSoup(html,'lxml')
          print(soup.p.descendants)
          for i,child in enumerate(soup.p.descendants):
              print(i,child)
          輸出:
          <generator object descendants at 0x0000022B542F9410>
          0 
              Once upon a time there were three little sisters; and their names were
              
          1 <a class="sister" href="http://example.com/elsie" id="link1">
          <span>Elsie</span>
          </a>
          2 
          
          3 <span>Elsie</span>
          4 Elsie
          5 
          
          6 
          
          7 <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
          8 Lacie
          9 
          and
          
          10 <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
          11 Tillie
          12 
          and they lived at the bottom of a well.
          View Code

          返回結果是生成器。遍歷輸出能夠看到,輸出結果包含了 span 節點。descendants 會遞歸查詢全部子節點,獲得全部的子孫節點  

      1. 父節點和祖先節點

        • 若是要獲取某個節點元素的父節點,能夠調用 parent 屬性:

          from bs4 import BeautifulSoup
          soup=BeautifulSoup(html,'lxml')
          print(soup.a.parent)
          輸出:
          <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">
          <span>Elsie</span>
          </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>
          View Code

          這裏咱們選擇的是第一個 a節點的父節點元素。它的父節點是 p節點,輸出結果即是p節點及其內部的內容。 

          注意:這裏輸出的僅僅是 a 節點的直接父節點,而沒有再向外尋找父節點的祖先節點。若是想獲取全部的祖先節點,調用 parents 屬性

          html = '''
          <html>
          <body>
          <p class='story'>
              <a href="http://example.com/elsie" class="sister" id="link1">
          <span>Elsie</span>
          </a>
          </p>
          '''
          from bs4 import BeautifulSoup
          soup=BeautifulSoup(html,'lxml')
          print(soup.a.parents)
          print(list(enumerate(soup.a.parents)))
          輸出:
          <generator object parents at 0x0000011701B69410>
          [(0, <p class="story">
          <a class="sister" href="http://example.com/elsie" id="link1">
          <span>Elsie</span>
          </a>
          </p>), (1, <body>
          <p class="story">
          <a class="sister" href="http://example.com/elsie" id="link1">
          <span>Elsie</span>
          </a>
          </p>
          </body>), (2, <html>
          <body>
          <p class="story">
          <a class="sister" href="http://example.com/elsie" id="link1">
          <span>Elsie</span>
          </a>
          </p>
          </body></html>), (3, <html>
          <body>
          <p class="story">
          <a class="sister" href="http://example.com/elsie" id="link1">
          <span>Elsie</span>
          </a>
          </p>
          </body></html>)]
          View Code

          返回結果是生成器類型。用列表輸出了它的索引和內容,而列表中的元素就是 a 節點的祖先節點。

      2. 兄弟節點

        • html = '''
          <html>
          <body>
          <p class="story">
                   Once upon a time there were three sisters;and their names were    
          <a href="http://example.com/elsie" class="sister" id="link1">
          <span>Elsie</span>
          </a>
                   Hello
          <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>
          '''
          from bs4 import BeautifulSoup
          soup = BeautifulSoup(html, 'lxml')
          print('Next Sibling', soup.a.next_sibling)
          print('Prev Sibling', soup.a.previous_sibling)
          print('Next Sibling', list(enumerate(soup.a.next_siblings)))
          print('Prev Sibling', list(enumerate(soup.a.previous_siblings)))
          輸出:
          Next Sibling 
                   Hello
          
          Prev Sibling 
                   Once upon a time there were three sisters;and their names were    
          
          Next Sibling [(0, '\n         Hello\n'), (1, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>), (2, '\n    and\n'), (3, <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>), (4, '\n    and they lived at the bottom of a well.\n')]
          Prev Sibling [(0, '\n         Once upon a time there were three sisters;and their names were    \n')]
          View Code

          這裏調用了4 個屬性,其中 next_sibling和previous_sibling 獲取節點的下一個 上一個兄弟元素next_siblings和 previous_siblings 則分別返回全部前面和後面 兄弟節點的生成器

      3. 信息提取
        • html = '''
          <html>
          <body>
          <p class="story">
                   Once upon a time there were three sisters;and their names were    
          <a href="http://example.com/elsie" class="sister" id="link1">BOb</a><a href="http://example.com/lacie"
          class="sister" id="link2">Lacie</a>
          </p>
          '''
          from bs4 import BeautifulSoup
          soup = BeautifulSoup(html, 'lxml')
          print('Next Sibling:')
          print(type(soup.a.previous_sibling))
          print(soup.a.next_sibling)
          print(soup.a.next_sibling.string)
          print('Parent:')
          print(type(soup.a.parents))
          print(list(soup.a.parents)[0])
          print(list(soup.a.parents)[0].attrs['class'])
          輸出:
          Next Sibling:
          <class 'bs4.element.NavigableString'>
          <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
          Lacie
          Parent:
          <class 'generator'>
          <p class="story">
                   Once upon a time there were three sisters;and their names were    
          <a class="sister" href="http://example.com/elsie" id="link1">BOb</a><a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>
          </p>
          ['story']
          View Code

           若是返回結果是單個節點,能夠直接調用 string attrs 等屬性得到其文本和屬性;若是返回結果是多個節點的生成器,則能夠轉爲列表後取出某個元素,而後再調用 string attrs 等屬性獲 取其對應節點的文本和屬性。

      4. 方法選擇器

        • 前面所講選擇方法是經過屬性來選擇的,這種方法很是快,可是若是進行比較複雜的選擇的話,它就比較煩瑣,不夠靈活。

        • find_all()

          • 是查詢全部符合條件的元素給它傳入一些屬性或文本,就能夠獲得符合條件的元素。API 以下:

            find_all(name,attrs,recursive,text,**kwargs)
          1. 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 cass= "element">Bar</li>
              <li cass= "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(name='ul'))
              print(type(soup.find_all(name='ul')[0]))
              輸出:
              [<ul class="list" id="list-1">
              <li class="element">Foo</li>
              <li cass="element">Bar</li>
              <li cass="element">Jay</li>
              </ul>, <ul class="list list-small" id="list-2">
              <li class="element">Foo</li>
              <li class="element">Bar</li>
              </ul>]
              <class 'bs4.element.Tag'>
              View Code

              調用了 find_all()方法,傳入 name 參數,其參數值爲 ul。也就是說,想要查詢全部 ul 節點,返回結果是列表類型,長度爲2,每一個元素依然都是 bs4.element.Tag類型。

              由於都是 Tag 類型,因此依然能夠進行嵌套查詢 仍是一樣的文本,這裏查詢出全部 節點後, 再繼續查詢其內部的 li 節點:
              for ul in soup.find_all(name='ul'):
                  print(ul.find_all(name='li'))
              輸出:
              [<li class="element">Foo</li>, <li cass="element">Bar</li>, <li cass="element">Jay</li>]
              [<li class="element">Foo</li>, <li class="element">Bar</li>]

              返回結果是列表類型,列表中的每一個元素依然仍是 ag 類型。

              接下來,能夠遍歷每一個 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)
              輸出:
              [<li class="element">Foo</li>, <li cass="element">Bar</li>, <li cass="element">Jay</li>]
              Foo
              Bar
              Jay
              [<li class="element">Foo</li>, <li class="element">Bar</li>]
              Foo
              Bar
              View Code
          2. atrrs

            • 除了根據節點名查詢,咱們也能夠傳入一些屬性來查詢,示例:

              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 cass= "element">Bar</li>
              <li cass= "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'}))
              print(soup.find_all(attrs={'name':'elements'}))
              輸出:
              [<ul class="list" id="list-1" name="elements">
              <li class="element">Foo</li>
              <li cass="element">Bar</li>
              <li cass="element">Jay</li>
              </ul>]
              [<ul class="list" id="list-1" name="elements">
              <li class="element">Foo</li>
              <li cass="element">Bar</li>
              <li cass="element">Jay</li>
              </ul>]
              View Code

              查詢的時候傳入的是 attrs 參數,參數的類型是字典類型,如要查詢 id爲 list-1 的節 點,能夠傳入 attrs ={'id' :' list-1'}查詢條件,獲得的結果是列表形式,包含的內容就是符合id爲 list-1 的全部節點。以上示例,符合條件的元素個數是1,因此結果是長度爲 1 的列表。

              一些經常使用的屬性,好比 id 和 class 等,能夠不用 attrs 來傳遞。如,要查詢 id爲 list-1 的節點,能夠直接傳人 id 這個參數。換種方式查詢:

              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 cass= "element">Bar</li>
              <li cass= "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(id='list-1'))
              print(soup.find_all(class_ ='element'))
              輸出:
              [<ul class="list" id="list-1" name="elements">
              <li class="element">Foo</li>
              <li cass="element">Bar</li>
              <li cass="element">Jay</li>
              </ul>]
              [<li class="element">Foo</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
              View Code

              直接傳入 id = 'list-1', 就能夠查詢 id爲list-1的節點元素。對於 class 來講,因爲 class在Python 裏是一個關鍵字,因此後面須要加一個下劃線,即 class_ = 'element' ,返回結果依然是Tag。

          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')
              print(soup.find_all(text=re.compile('link')))
              輸出:
              ['Hello,this is a link', 'Hello,this is a link,too']

              這裏有兩個 a 節點,內部包含文本信息。這裏在 find_all() 方法傳人text 參數,該參數爲正則表達式對象,結果返回全部匹配正則表達式的節點文本組成的列表。

            • find()
              • find()方法返回單個元素 ,也就是第一個匹配的元素。示例:
                from bs4 import BeautifulSoup
                soup=BeautifulSoup(html,'lxml')
                print(soup.find(name='ul'))
                print(soup.find(class_ ='element'))
                print(type(soup.find(name='ul')))
                輸出:
                <ul class="list" id="list-1">
                <li class="element">Foo</li>
                <li cass="element">Bar</li>
                <li cass="element">Jay</li>
                </ul>
                <li class="element">Foo</li>
                <class 'bs4.element.Tag'>
                View Code

                返回結果再也不是列表形式,是第一個匹配的節點元素,類型依然是 Tag 類型。 

                還有許多查詢方法,其用方法與前面介紹的 find_all(), find() 方法徹底相同, 只不過查詢範圍不一樣
                • find_parents()和find_parents(): 前者返回 全部祖先節點,後者返回直接父節點
                • find_next_siblings()和find_next_sibling(): 前者返回後面全部的兄弟節點,後者返回後面第一個兄弟節點
                • find_previous_siblings()和find_previous_sibling(): 前者返回前面全部的兄弟節點 ,後者返回前面第一個兄弟節點
                • find_all_next()和find_previous(): 前者返回節點後全部符合條件的節點,後者返回第一個符合條件的節點
                • find_all_previous()和find_previous():前者返回節點後全部符合條件的節點,後者返回第 一個符合條件的節點
      5. 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 cass= "element">Bar</li>
          <li cass= "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'))
          print(type(soup.select('ul')[0]))
          輸出:
          [<div class="panel-heading">
          <h4>Hello</h4>
          </div>]
          [<li class="element">Foo</li>, <li cass="element">Bar</li>, <li cass="element">Jay</li>, <li class="element">Foo</li>, <li class="element">Bar</li>]
          [<li class="element">Foo</li>, <li class="element">Bar</li>]
          <class 'bs4.element.Tag'>
          View Code

          這裏用了CSS 選擇器,返回的結果均是符合 css 選擇器的節點組成的列表 。如, select( ’ ul li ’)則是選擇全部 ul 節點下面的全部li 節點,結果全部的 li 節點組成的列表。輸出列表中元素的類型依然是 Tag 類型。

        • 嵌套選擇
          • select()方法一樣支持嵌套選擇。如,先選擇全部 ul 節點,再遍歷每一個 ul 節點,選擇其 li節點,示例:
            from bs4 import BeautifulSoup
            soup=BeautifulSoup(html,'lxml')
            for ul in soup.select('ul'):
                print(ul.select('li'))
            輸出:
            [<li class="element">Foo</li>, <li cass="element">Bar</li>, <li cass="element">Jay</li>]
            [<li class="element">Foo</li>, <li class="element">Bar</li>]

            正常輸出了全部 ul 節點下全部 li 節點組成的列表

        • 獲取屬性  

          • 節點類型是 Tag 類型,獲取屬性能夠用原來的方法。仍然是以上的 HTML 文本, 嘗試獲取每一個 ul 節點的 id 屬性:
            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

            接傳入中括號和屬性名,以及經過 attrs 屬性獲取屬性值,均可以成功。

        • 獲取文本

          • 獲取文本,除了能夠用 string 屬性。還有一個方法,那就是 get_text() ,效果一致。示例:  

            from bs4 import BeautifulSoup
            soup=BeautifulSoup(html, 'lxml')
            for li in soup.select('li'):
                print('Get Text:',li.get_text())
                print('string:',li.string)
            輸出:
            Get Text: Foo
            string: Foo
            Get Text: Bar
            string: Bar
            Get Text: Jay
            string: Jay
            Get Text: Foo
            string: Foo
            Get Text: Bar
            string: Bar
            View Code

小結:

  1. 使用lxml解析庫,必要時使用html.parse.
  2. 節點篩選功能弱,可是速度快。
  3. 使用find()或者find_all()查詢匹配單個結果或者多個結果          
  4. CSS選擇器,可使用select()方法選擇
相關文章
相關標籤/搜索