天天看點

Python+requests之beautifulsoup4解析html

Beautiful Soup是一個可以從HTML或XML檔案中提取資料的Python庫, 它能夠通過你喜歡的轉換器實作慣用的文檔導航, 查找修改文檔

html解析器

下表列出了主要的

html

解析器,以及它們的優缺點

解析器 使用方法 優勢 劣勢
  Python标準庫    BeautifulSoup(markup, "html.parser")

  1. Python的内置标準庫

  2. 執行速度适中

  3. 文檔容錯能力強

  1. Python 2.7.3 or 3.2.2)前的版 本中文檔容錯能力差
  lxml HTML 解析器    BeautifulSoup(markup, "lxml")

  1. 速度快

  2. 文檔容錯能力強

  1. 需要安裝C語言庫
  lxml XML 解析器    BeautifulSoup(markup, ["lxml-xml"])         BeautifulSoup(markup, "xml")

  1. 速度快

  2. 唯一支援XML的解析器

 1. 需要安裝C語言庫
  html5lib    BeautifulSoup(markup, "html5lib")

  1. 最好的容錯性

  2. 以浏覽器的方式解析文檔

  3. 生成HTML5格式的文檔

  1. 速度慢 

  2. 不依賴外部擴充

我們對執行速度沒啥很大要求,是以主要用第一個

html.parser

Python

的标準庫可直接用,其它幾個需要安裝對應解析器

Beautiful Soup4

安裝

# 通過pip安裝
pip install beautifulsoup4
           

使用

将一段文檔(

html

字元串或一個檔案句柄)傳入

BeautifulSoup

的構造方法, 即可轉換成一個複雜的樹形結構,

html.parser

解析器會将其每個子節點解析為

Python

對象

from bs4 import BeautifulSoup
soup = BeautifulSoup(open("index.html" 'rb').read(), 'html.parser')    # 通過html檔案句柄
soup = BeautifulSoup("<html>data</html>", 'html.parser')               # 通過html字元串
           

Beautiful Soup将複雜HTML文檔轉換成一個複雜的樹形結構, 每個節點都是Python對象, 所有對象可以歸納為 4 種:

1. Tag:  标簽對象,與html 原生文檔中的 tag 相同,如:

soup = BeautifulSoup('<b id="sitven" class="title">sitven的部落格</b>', 'html.parser')
tag = soup.b        # 如果不存在則傳回None,如果存在多個則傳回第一個
print(type(tag))
# 列印結果: <class 'bs4.element.Tag'>
           

Name: 每個 tag 都有自己的名字

tag = soup.b
print(tag.name)
# 列印結果
# u'b'
           

一個tag可能有很多個屬性

<b class="boldest">

 有一個 “class” 的屬性,值為"boldest",tag的屬性的操作方法與字典相同:

print(tag["id"])
# 列印結果
#u'sitven'
           

也可以直接”點”取屬性, 比如: 

.attrs

 :

print(tag.attrs)
# 列印結果
# {'id': 'sitven', 'class': ['title']}
           

tag的屬性可以被添加,删除或修改.tag的屬性操作方法與字典一樣:

# 增
tag['value'] = '張大款'
print(tag)
# 列印結果:   <b class="title" id="sitven" value="張大款">sitven的部落格</b>
    
# 改
tag['calss'] = 'zdk'
print(tag)
# 列印結果:   <b class="zdk" id="sitven" value="張大款">sitven的部落格</b>
    
# 删
del tag['class']
print(tag)
# 列印結果:   <b id="sitven" value="張大款">sitven的部落格</b>

# key不存在
tag['class']
# 列印結果:   KeyError: 'class'

print(tag.get('class'))
# 列印結果:   None
           

2. NavigableString:  字元對象

字元串常被包含在tag内.Beautiful Soup用 

NavigableString

 類來包裝tag中的字元串

b = '<b id="sitven" class="title" >sitven的部落格</b>'
soup = BeautifulSoup(b, 'html.parser')
tag = soup.b
print(tag.string)
# 列印結果:  sitven的部落格
           

3. BeautifulSoup

BeautifulSoup

對象表示的是文檔的全部内容, 大部分時候可把它當作

Tag

對象, 它支援 周遊文檔樹和搜尋文檔樹中描述的大部分方法

4. Comment:  注釋對象。 

Tag

 , 

NavigableString

 , 

BeautifulSoup

 幾乎覆寫了html和xml中的所有内容, 但是還有一些特殊對象 - 注釋部分

markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup, 'html.parser')
comment = soup.b.string
print(type(comment))

# 列印結果:   <class 'bs4.element.Comment'>
           

但是當它出現在HTML文檔中時, 

Comment

 對象會使用特殊的格式輸出:

print(soup.b.prettify())
# <b>
#  <!--Hey, buddy. Want to buy a used parser?-->
# </b>
           

搜尋文檔樹

Beautiful Soup

定義了很多搜尋方法,常用的兩個:  

find()

 和 

find_all()

以“愛麗絲”文檔作為例子-html_doc.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" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" target="_blank" rel="external nofollow"  class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
           

find_all()

 方法搜尋目前tag的所有tag子節點,并判斷是否符合過濾器的條件, 傳回文檔中符合條件的所有tag,傳回list

格式:  find_all(name, attrs={}, recursive, string, **kwargs)

find()

 方法搜尋目前tag的所有tag子節點, 并判斷是否符合過濾器的條件, 傳回文檔中符合條件某個tag, 直接傳回結果或者None

格式:find(name, attrs={}, recursive, string, **kwargs)

參數

name

:查找所有名字為

name

的tag (比如:

soup.find_all(name="title"

),搜尋name為title的所有tag), 接受 字元串 , 正規表達式 , 清單, True等類型參數

from bs4 import BeautifulSoup
soup = BeautifulSoup(open("html_doc.hmtl", 'rb').read(), 'html.parser')
print(soup.find_all("title"))
# 列印結果: [<title>The Dormouse's story</title>]
           

參數

attrs

:  通過attrs字典中定義的屬性來搜尋tag(如果包含一個名字為 

id

 的參數, Beautiful Soup會搜尋每個tag的'id'屬性)

from bs4 import BeautifulSoup
soup = BeautifulSoup(open("html_doc.hmtl", 'rb').read(), 'html.parser')
# 搜尋id="link2”且class="sister的tag
print(soup.find_all(attrs={"id": "link2”, "class": "sister"})
# 列印結果: [<title>The Dormouse's story</title>]
           

參數

string

:  搜尋文檔中的字元串内容, 與

name

參數的可選值一樣, 參數

string

接受 字元串 , 正規表達式 , 清單, True等類型參數

例子:與參數name聯和使用, 搜尋内容裡面包含"Lacie"的<a>标簽

from bs4 import BeautifulSoup
soup = BeautifulSoup(open("html_doc.hmtl", 'rb').read(), 'html.parser')
soup = Get_Html(html=html_doc)
a = soup.find_all_label(name="a", string="Lacie")
print(a)
# 列印結果: [<a class="sister" href="http://example.com/lacie" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  id="link2">Lacie</a>]
           

例子:正規表達式比對

from bs4 import BeautifulSoup
soup = BeautifulSoup(open("html_doc.hmtl", 'rb').read(), 'html.parser')
soup = Get_Html(html=html_doc)
soup.find_all(string=re.compile("Dormouse"))
# 列印結果:  [u"The Dormouse's story", u"The Dormouse's story"]
           

參數

limit

:與SQL中的limit關鍵字類似,當搜尋到的結果數量達到 

limit

 的限制時,就停止搜尋傳回結果

例子:文檔樹中有3個tag符合搜尋條件,但結果隻傳回了2個,因為我們限制了傳回數量

from bs4 import BeautifulSoup
soup = BeautifulSoup(open("html_doc.hmtl", 'rb').read(), 'html.parser')
soup = Get_Html(html=html_doc)
print(soup.find_all("a", limit=2))
# 列印結果: [<a class="sister" href="http://example.com/elsie" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  id="link2">Lacie</a>]
           

參數

recursive

:  調用tag的 

find_all()

 方法時,Beautiful Soup會檢索目前tag的所有子孫節點,如果隻想搜尋tag的直接子節點,可以使用參數 

recursive=False