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