Beautiful Soup(五)--其他相關

[Top]

輸出

格式化輸出

prettify() 方法將Beautiful Soup的文檔樹格式化後以Unicode編碼輸出,每個XML/HTML標籤都獨佔一行

markup = '<a href="http://example.com/">I linked to <i>example.com</i></a>'
soup = BeautifulSoup(markup)
soup.prettify()
# '<html>\n <head>\n </head>\n <body>\n  <a href="http://example.com/">\n...'

print(soup.prettify())
# <html>
#  <head>
#  </head>
#  <body>
#   <a href="http://example.com/">
#    I linked to
#    <i>
#     example.com
#    </i>
#   </a>
#  </body>
# </html>

BeautifulSoup 對象和它的tag節點都可以調用 prettify() 方法:

print(soup.a.prettify())
# <a href="http://example.com/">
#  I linked to
#  <i>
#   example.com
#  </i>
# </a>

壓縮輸出

如果只想得到結果字符串,不重視格式,那麼可以對一個 BeautifulSoup 對象或 Tag 對象使用Python的 unicode() 或 str() 方法:

str(soup)
# '<html><head></head><body><a href="http://example.com/">I linked to <i>example.com</i></a></body></html>'

unicode(soup.a)
# u'<a href="http://example.com/">I linked to <i>example.com</i></a>'

str() 方法返回UTF-8編碼的字符串,可以指定 編碼 的設置.

還可以調用 encode() 方法獲得字節碼或調用 decode() 方法獲得Unicode.

輸出格式

Beautiful Soup輸出是會將HTML中的特殊字符轉換成Unicode,比如“&lquot;”:

soup = BeautifulSoup("&ldquo;Dammit!&rdquo; he said.")
unicode(soup)
# u'<html><head></head><body>\u201cDammit!\u201d he said.</body></html>'

如果將文檔轉換成字符串,Unicode編碼會被編碼成UTF-8.這樣就無法正確顯示HTML特殊字符了:

str(soup)
# '<html><head></head><body>\xe2\x80\x9cDammit!\xe2\x80\x9d he said.</body></html>'

get_text()

如果只想得到tag中包含的文本內容,那麼可以嗲用 get_text() 方法,這個方法獲取到tag中包含的所有文版內容包括子孫tag中的內容,並將結果作爲Unicode字符串返回:

markup = '<a href="http://example.com/">\nI linked to <i>example.com</i>\n</a>'
soup = BeautifulSoup(markup)

soup.get_text()
u'\nI linked to example.com\n'
soup.i.get_text()
u'example.com'

可以通過參數指定tag的文本內容的分隔符:

# soup.get_text("|")
u'\nI linked to |example.com|\n'

還可以去除獲得文本內容的前後空白:

# soup.get_text("|", strip=True)
u'I linked to|example.com'

或者使用 .stripped_strings 生成器,獲得文本列表後手動處理列表:

[text for text in soup.stripped_strings]
# [u'I linked to', u'example.com']

指定文檔解析器

如果僅是想要解析HTML文檔,只要用文檔創建 BeautifulSoup 對象就可以了.Beautiful Soup會自動選擇一個解析器來解析文檔.但是還可以通過參數指定使用那種解析器來解析當前文檔.

BeautifulSoup 第一個參數應該是要被解析的文檔字符串或是文件句柄,第二個參數用來標識怎樣解析文檔.如果第二個參數爲空,那麼Beautiful Soup根據當前系統安裝的庫自動選擇解析器,解析器的優先數序: lxml, html5lib, Python標準庫.在下面兩種條件下解析器優先順序會變化:

    要解析的文檔是什麼類型: 目前支持, “html”, “xml”, 和 “html5”
    指定使用哪種解析器: 目前支持, “lxml”, “html5lib”, 和 “html.parser”

安裝解析器 章節介紹了可以使用哪種解析器,以及如何安裝.

如果指定的解析器沒有安裝,Beautiful Soup會自動選擇其它方案.目前只有 lxml 解析器支持XML文檔的解析,在沒有安裝lxml庫的情況下,創建 beautifulsoup 對象時無論是否指定使用lxml,都無法得到解析後的對象

解析器之間的區別

Beautiful Soup爲不同的解析器提供了相同的接口,但解析器本身時有區別的.同一篇文檔被不同的解析器解析後可能會生成不同結構的樹型文檔.區別最大的是HTML解析器和XML解析器,看下面片段被解析成HTML結構:

BeautifulSoup("<a><b /></a>")
# <html><head></head><body><a><b></b></a></body></html>

因爲空標籤<b />不符合HTML標準,所以解析器把它解析成<b></b>

同樣的文檔使用XML解析如下(解析XML需要安裝lxml庫).注意,空標籤<b />依然被保留,並且文檔前添加了XML頭,而不是被包含在<html>標籤內:

BeautifulSoup("<a><b /></a>", "xml")
# <?xml version="1.0" encoding="utf-8"?>
# <a><b/></a>

HTML解析器之間也有區別,如果被解析的HTML文檔是標準格式,那麼解析器之間沒有任何差別,只是解析速度不同,結果都會返回正確的文檔樹.

但是如果被解析文檔不是標準格式,那麼不同的解析器返回結果可能不同.下面例子中,使用lxml解析錯誤格式的文檔,結果</p>標籤被直接忽略掉了:

BeautifulSoup("<a></p>", "lxml")
# <html><body><a></a></body></html>

使用html5lib庫解析相同文檔會得到不同的結果:

BeautifulSoup("<a></p>", "html5lib")
# <html><head></head><body><a><p></p></a></body></html>

html5lib庫沒有忽略掉</p>標籤,而是自動補全了標籤,還給文檔樹添加了<head>標籤.

使用pyhton內置庫解析結果如下:

BeautifulSoup("<a></p>", "html.parser")
# <a></a>

與lxml [7] 庫類似的,Python內置庫忽略掉了</p>標籤,與html5lib庫不同的是標準庫沒有嘗試創建符合標準的文檔格式或將文檔片段包含在<body>標籤內,與lxml不同的是標準庫甚至連<html>標籤都沒有嘗試去添加.

因爲文檔片段“<a></p>”是錯誤格式,所以以上解析方式都能算作”正確”,html5lib庫使用的是HTML5的部分標準,所以最接近”正確”.不過所有解析器的結構都能夠被認爲是”正常”的.

不同的解析器可能影響代碼執行結果,如果在分發給別人的代碼中使用了 BeautifulSoup ,那麼最好註明使用了哪種解析器,以減少不必要的麻煩.

編碼

任何HTML或XML文檔都有自己的編碼方式,比如ASCII 或 UTF-8,但是使用Beautiful Soup解析後,文檔都被轉換成了Unicode:

markup = "<h1>Sacr\xc3\xa9 bleu!</h1>"
soup = BeautifulSoup(markup)
soup.h1
# <h1>Sacré bleu!</h1>
soup.h1.string
# u'Sacr\xe9 bleu!'

這不是魔術(但很神奇),Beautiful Soup用了 編碼自動檢測 子庫來識別當前文檔編碼並轉換成Unicode編碼. BeautifulSoup 對象的 .original_encoding 屬性記錄了自動識別編碼的結果:

soup.original_encoding
'utf-8'

編碼自動檢測 功能大部分時候都能猜對編碼格式,但有時候也會出錯.有時候即使猜測正確,也是在逐個字節的遍歷整個文檔後才猜對的,這樣很慢.如果預先知道文檔編碼,可以設置編碼參數來減少自動檢查編碼出錯的概率並且提高文檔解析速度.在創建 BeautifulSoup 對象的時候設置 from_encoding 參數.

下面一段文檔用了ISO-8859-8編碼方式,這段文檔太短,結果Beautiful Soup以爲文檔是用ISO-8859-7編碼:

markup = b"<h1>\xed\xe5\xec\xf9</h1>"
soup = BeautifulSoup(markup)
soup.h1
<h1>νεμω</h1>
soup.original_encoding
'ISO-8859-7'

通過傳入 from_encoding 參數來指定編碼方式:

soup = BeautifulSoup(markup, from_encoding="iso-8859-8")
soup.h1
<h1>םולש</h1>
soup.original_encoding
'iso8859-8'

少數情況下(通常是UTF-8編碼的文檔中包含了其它編碼格式的文件),想獲得正確的Unicode編碼就不得不將文檔中少數特殊編碼字符替換成特殊Unicode編碼,“REPLACEMENT CHARACTER” (U+FFFD, �) [9] . 如果Beautifu Soup猜測文檔編碼時作了特殊字符的替換,那麼Beautiful Soup會把 UnicodeDammit 或 BeautifulSoup 對象的 .contains_replacement_characters 屬性標記爲 True .這樣就可以知道當前文檔進行Unicode編碼後丟失了一部分特殊內容字符.如果文檔中包含�而 .contains_replacement_characters 屬性是 False ,則表示�就是文檔中原來的字符,不是轉碼失敗.

輸出編碼

通過Beautiful Soup輸出文檔時,不管輸入文檔是什麼編碼方式,輸出編碼均爲UTF-8編碼,下面例子輸入文檔是Latin-1編碼:

markup = b'''
<html>
  <head>
    <meta content="text/html; charset=ISO-Latin-1" http-equiv="Content-type" />
  </head>
  <body>
    <p>Sacr\xe9 bleu!</p>
  </body>
</html>
'''

soup = BeautifulSoup(markup)
print(soup.prettify())
# <html>
#  <head>
#   <meta content="text/html; charset=utf-8" http-equiv="Content-type" />
#  </head>
#  <body>
#   <p>
#    Sacré bleu!
#   </p>
#  </body>
# </html>

注意,輸出文檔中的<meta>標籤的編碼設置已經修改成了與輸出編碼一致的UTF-8.

如果不想用UTF-8編碼輸出,可以將編碼方式傳入 prettify() 方法:

print(soup.prettify("latin-1"))
# <html>
#  <head>
#   <meta content="text/html; charset=latin-1" http-equiv="Content-type" />
# ...

還可以調用 BeautifulSoup 對象或任意節點的 encode() 方法,就像Python的字符串調用 encode() 方法一樣:

soup.p.encode("latin-1")
# '<p>Sacr\xe9 bleu!</p>'

soup.p.encode("utf-8")
# '<p>Sacr\xc3\xa9 bleu!</p>'

如果文檔中包含當前編碼不支持的字符,那麼這些字符將唄轉換成一系列XML特殊字符引用,下面例子中包含了Unicode編碼字符SNOWMAN:

markup = u"<b>\N{SNOWMAN}</b>"
snowman_soup = BeautifulSoup(markup)
tag = snowman_soup.b

SNOWMAN字符在UTF-8編碼中可以正常顯示(看上去像是☃),但有些編碼不支持SNOWMAN字符,比如ISO-Latin-1或ASCII,那麼在這些編碼中SNOWMAN字符會被轉換成“&#9731”:

print(tag.encode("utf-8"))
# <b>☃</b>

print tag.encode("latin-1")
# <b>&#9731;</b>

print tag.encode("ascii")
# <b>&#9731;</b>

Unicode, dammit! (靠!)

編碼自動檢測 功能可以在Beautiful Soup以外使用,檢測某段未知編碼時,可以使用這個方法:

from bs4 import UnicodeDammit
dammit = UnicodeDammit("Sacr\xc3\xa9 bleu!")
print(dammit.unicode_markup)
# Sacré bleu!
dammit.original_encoding
# 'utf-8'

如果Python中安裝了 chardet 或 cchardet 那麼編碼檢測功能的準確率將大大提高.輸入的字符越多,檢測結果越精確,如果事先猜測到一些可能編碼,那麼可以將猜測的編碼作爲參數,這樣將優先檢測這些編碼:

dammit = UnicodeDammit("Sacr\xe9 bleu!", ["latin-1", "iso-8859-1"])
print(dammit.unicode_markup)
# Sacré bleu!
dammit.original_encoding
# 'latin-1'

編碼自動檢測 功能中有2項功能是Beautiful Soup庫中用不到的
智能引號

使用Unicode時,Beautiful Soup還會智能的把引號 [10] 轉換成HTML或XML中的特殊字符:

markup = b"<p>I just \x93love\x94 Microsoft Word\x92s smart quotes</p>"

UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="html").unicode_markup
# u'<p>I just &ldquo;love&rdquo; Microsoft Word&rsquo;s smart quotes</p>'

UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="xml").unicode_markup
# u'<p>I just &#x201C;love&#x201D; Microsoft Word&#x2019;s smart quotes</p>'

也可以把引號轉換爲ASCII碼:

UnicodeDammit(markup, ["windows-1252"], smart_quotes_to="ascii").unicode_markup
# u'<p>I just "love" Microsoft Word\'s smart quotes</p>'

很有用的功能,但是Beautiful Soup沒有使用這種方式.默認情況下,Beautiful Soup把引號轉換成Unicode:

UnicodeDammit(markup, ["windows-1252"]).unicode_markup
# u'<p>I just \u201clove\u201d Microsoft Word\u2019s smart quotes</p>'

矛盾的編碼

有時文檔的大部分都是用UTF-8,但同時還包含了Windows-1252編碼的字符,就像微軟的智能引號 [10] 一樣.一些包含多個信息的來源網站容易出現這種情況. UnicodeDammit.detwingle() 方法可以把這類文檔轉換成純UTF-8編碼格式,看個簡單的例子:

snowmen = (u"\N{SNOWMAN}" * 3)
quote = (u"\N{LEFT DOUBLE QUOTATION MARK}I like snowmen!\N{RIGHT DOUBLE QUOTATION MARK}")
doc = snowmen.encode("utf8") + quote.encode("windows_1252")

這段文檔很雜亂,snowmen是UTF-8編碼,引號是Windows-1252編碼,直接輸出時不能同時顯示snowmen和引號,因爲它們編碼不同:

print(doc)
# ☃☃☃�I like snowmen!�

print(doc.decode("windows-1252"))
# ☃☃☃“I like snowmen!”

如果對這段文檔用UTF-8解碼就會得到 UnicodeDecodeError 異常,如果用Windows-1252解碼就回得到一堆亂碼.幸好, UnicodeDammit.detwingle() 方法會吧這段字符串轉換成UTF-8編碼,允許我們同時顯示出文檔中的snowmen和引號:

new_doc = UnicodeDammit.detwingle(doc)
print(new_doc.decode("utf8"))
# ☃☃☃“I like snowmen!”

UnicodeDammit.detwingle() 方法只能解碼包含在UTF-8編碼中的Windows-1252編碼內容,但這解決了最常見的一類問題.

在創建 BeautifulSoup 或 UnicodeDammit 對象前一定要先對文檔調用 UnicodeDammit.detwingle() 確保文檔的編碼方式正確.如果嘗試去解析一段包含Windows-1252編碼的UTF-8文檔,就會得到一堆亂碼,比如: ☃☃☃“I like snowmen!”.

UnicodeDammit.detwingle() 方法在Beautiful Soup 4.1.0版本中新增

解析部分文檔

如果僅僅因爲想要查找文檔中的<a>標籤而將整片文檔進行解析,實在是浪費內存和時間.最快的方法是從一開始就把<a>標籤以外的東西都忽略掉. SoupStrainer 類可以定義文檔的某段內容,這樣搜索文檔時就不必先解析整篇文檔,只會解析在 SoupStrainer 中定義過的文檔. 創建一個 SoupStrainer 對象並作爲 parse_only 參數給 BeautifulSoup 的構造方法即可.

SoupStrainer

SoupStrainer 類接受與典型搜索方法相同的參數:name , attrs , recursive , text , **kwargs 。下面舉例說明三種 SoupStrainer 對象:

from bs4 import SoupStrainer

only_a_tags = SoupStrainer("a")

only_tags_with_id_link2 = SoupStrainer(id="link2")

def is_short_string(string):
    return len(string) < 10

only_short_strings = SoupStrainer(text=is_short_string)

再拿“愛麗絲”文檔來舉例,來看看使用三種 SoupStrainer 對象做參數會有什麼不同:

html_doc = """
<html><head><title>The Dormouse's story</title></head>

<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>
"""

print(BeautifulSoup(html_doc, "html.parser", parse_only=only_a_tags).prettify())
# <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>

print(BeautifulSoup(html_doc, "html.parser", parse_only=only_tags_with_id_link2).prettify())
# <a class="sister" href="http://example.com/lacie" id="link2">
#  Lacie
# </a>

print(BeautifulSoup(html_doc, "html.parser", parse_only=only_short_strings).prettify())
# Elsie
# ,
# Lacie
# and
# Tillie
# ...
#

還可以將 SoupStrainer 作爲參數傳入 搜索文檔樹 中提到的方法.這可能不是個常用用法,所以還是提一下:

soup = BeautifulSoup(html_doc)
soup.find_all(only_short_strings)
# [u'\n\n', u'\n\n', u'Elsie', u',\n', u'Lacie', u' and\n', u'Tillie',
#  u'\n\n', u'...', u'\n']

常見問題

代碼診斷

如果想知道Beautiful Soup到底怎樣處理一份文檔,可以將文檔傳入 diagnose() 方法(Beautiful Soup 4.2.0中新增),Beautiful Soup會輸出一份報告,說明不同的解析器會怎樣處理這段文檔,並標出當前的解析過程會使用哪種解析器:

from bs4.diagnose import diagnose
data = open("bad.html").read()
diagnose(data)

# Diagnostic running on Beautiful Soup 4.2.0
# Python version 2.7.3 (default, Aug  1 2012, 05:16:07)
# I noticed that html5lib is not installed. Installing it may help.
# Found lxml version 2.3.2.0
#
# Trying to parse your data with html.parser
# Here's what html.parser did with the document:
# ...

diagnose() 方法的輸出結果可能幫助你找到問題的原因,如果不行,還可以把結果複製出來以便尋求他人的幫助

文檔解析錯誤

文檔解析錯誤有兩種.一種是崩潰,Beautiful Soup嘗試解析一段文檔結果卻拋除了異常,通常是 HTMLParser.HTMLParseError .還有一種異常情況,是Beautiful Soup解析後的文檔樹看起來與原來的內容相差很多.

這些錯誤幾乎都不是Beautiful Soup的原因,這不會是因爲Beautiful Soup得代碼寫的太優秀,而是因爲Beautiful Soup沒有包含任何文檔解析代碼.異常產生自被依賴的解析器,如果解析器不能很好的解析出當前的文檔,那麼最好的辦法是換一個解析器.更多細節查看 安裝解析器 章節.

最常見的解析錯誤是 HTMLParser.HTMLParseError: malformed start tag 和 HTMLParser.HTMLParseError: bad end tag .這都是由Python內置的解析器引起的,解決方法是 安裝lxml或html5lib

最常見的異常現象是當前文檔找不到指定的Tag,而這個Tag光是用眼睛就足夠發現的了. find_all() 方法返回 [] ,而 find() 方法返回 None .這是Python內置解析器的又一個問題: 解析器會跳過那些它不知道的tag.解決方法還是 安裝lxml或html5lib

版本錯誤

SyntaxError: Invalid syntax (異常位置在代碼行: ROOT_TAG_NAME = u’[document]’ ),因爲Python2版本的代碼沒有經過遷移就在Python3中窒息感
ImportError: No module named HTMLParser 因爲在Python3中執行Python2版本的Beautiful Soup
ImportError: No module named html.parser 因爲在Python2中執行Python3版本的Beautiful Soup
ImportError: No module named BeautifulSoup 因爲在沒有安裝BeautifulSoup3庫的Python環境下執行代碼,或忘記了BeautifulSoup4的代碼需要從 bs4 包中引入
ImportError: No module named bs4 因爲當前Python環境下還沒有安裝BeautifulSoup4

解析成XML

默認情況下,Beautiful Soup會將當前文檔作爲HTML格式解析,如果要解析XML文檔,要在 BeautifulSoup 構造方法中加入第二個參數 “xml”:

soup = BeautifulSoup(markup, "xml")

當然,還需要 安裝lxml

解析器的錯誤

如果同樣的代碼在不同環境下結果不同,可能是因爲兩個環境下使用不同的解析器造成的.例如這個環境中安裝了lxml,而另一個環境中只有html5lib, 解析器之間的區別 中說明了原因.修復方法是在 BeautifulSoup 的構造方法中中指定解析器
因爲HTML標籤是 大小寫敏感 的,所以3種解析器再出來文檔時都將tag和屬性轉換成小寫.例如文檔中的 會被轉換爲 .如果想要保留tag的大寫的話,那麼應該將文檔 解析成XML .

雜項錯誤

UnicodeEncodeError: ‘charmap’ codec can’t encode character u’\xfoo’ in position bar (或其它類型的 UnicodeEncodeError )的錯誤,主要是兩方面的錯誤(都不是Beautiful Soup的原因),第一種是正在使用的終端(console)無法顯示部分Unicode,參考 Python wiki ,第二種是向文件寫入時,被寫入文件不支持部分Unicode,這時只要用 u.encode(“utf8”) 方法將編碼轉換爲UTF-8.
KeyError: [attr] 因爲調用 tag[‘attr’] 方法而引起,因爲這個tag沒有定義該屬性.出錯最多的是 KeyError: ‘href’ 和 KeyError: ‘class’ .如果不確定某個屬性是否存在時,用 tag.get(‘attr’) 方法去獲取它,跟獲取Python字典的key一樣
AttributeError: ‘ResultSet’ object has no attribute ‘foo’ 錯誤通常是因爲把 find_all() 的返回結果當作一個tag或文本節點使用,實際上返回結果是一個列表或 ResultSet 對象的字符串,需要對結果進行循環才能得到每個節點的 .foo 屬性.或者使用 find() 方法僅獲取到一個節點
AttributeError: ‘NoneType’ object has no attribute ‘foo’ 這個錯誤通常是在調用了 find() 方法後直節點取某個屬性 .foo 但是 find() 方法並沒有找到任何結果,所以它的返回值是 None .需要找出爲什麼 find() 的返回值是 None .

如何提高效率

Beautiful Soup對文檔的解析速度不會比它所依賴的解析器更快,如果對計算時間要求很高或者計算機的時間比程序員的時間更值錢,那麼就應該直接使用 lxml .

換句話說,還有提高Beautiful Soup效率的辦法,使用lxml作爲解析器.Beautiful Soup用lxml做解析器比用html5lib或Python內置解析器速度快很多.

安裝 cchardet 後文檔的解碼的編碼檢測會速度更快

解析部分文檔 不會節省多少解析時間,但是會節省很多內存,並且搜索時也會變得更快.

Beautiful Soup 3

Beautiful Soup 3是上一個發佈版本,目前已經停止維護.Beautiful Soup 3庫目前已經被幾個主要的linux平臺添加到源裏:

$ apt-get install Python-beautifulsoup

在PyPi中分發的包名字是 BeautifulSoup :

$ easy_install BeautifulSoup

$ pip install BeautifulSoup

或通過 Beautiful Soup 3.2.0源碼包 安裝

Beautiful Soup 3的在線文檔查看 這裏 ,當然還有 中文版 ,然後再讀本片文檔,來對比Beautiful Soup 4中有什新變化.

遷移到BS4

只要一個小變動就能讓大部分的Beautiful Soup 3代碼使用Beautiful Soup 4的庫和方法—-修改 BeautifulSoup 對象的引入方式:

from BeautifulSoup import BeautifulSoup

修改爲:

from bs4 import BeautifulSoup

如果代碼拋出 ImportError 異常“No module named BeautifulSoup”,原因可能是嘗試執行Beautiful Soup 3,但環境中只安裝了Beautiful Soup 4庫
如果代碼跑出 ImportError 異常“No module named bs4”,原因可能是嘗試運行Beautiful Soup 4的代碼,但環境中只安裝了Beautiful Soup 3.

雖然BS4兼容絕大部分BS3的功能,但BS3中的大部分方法已經不推薦使用了,就方法按照 PEP8標準 重新定義了方法名.很多方法都重新定義了方法名,但只有少數幾個方法沒有向下兼容.

上述內容就是BS3遷移到BS4的注意事項

需要的解析器

Beautiful Soup 3曾使用Python的 SGMLParser 解析器,這個模塊在Python3中已經被移除了.Beautiful Soup 4默認使用系統的 html.parser ,也可以使用lxml或html5lib擴展庫代替.查看 安裝解析器 章節

因爲 html.parser 解析器與 SGMLParser 解析器不同,它們在處理格式不正確的文檔時也會產生不同結果.通常 html.parser 解析器會拋出異常.所以推薦安裝擴展庫作爲解析器.有時 html.parser 解析出的文檔樹結構與 SGMLParser 的不同.如果發生這種情況,那麼需要升級BS3來處理新的文檔樹.

方法名的變化

renderContents -> encode_contents
replaceWith -> replace_with
replaceWithChildren -> unwrap
findAll -> find_all
findAllNext -> find_all_next
findAllPrevious -> find_all_previous
findNext -> find_next
findNextSibling -> find_next_sibling
findNextSiblings -> find_next_siblings
findParent -> find_parent
findParents -> find_parents
findPrevious -> find_previous
findPreviousSibling -> find_previous_sibling
findPreviousSiblings -> find_previous_siblings
nextSibling -> next_sibling
previousSibling -> previous_sibling

Beautiful Soup構造方法的參數部分也有名字變化:

BeautifulSoup(parseOnlyThese=...) -> BeautifulSoup(parse_only=...)
BeautifulSoup(fromEncoding=...) -> BeautifulSoup(from_encoding=...)

爲了適配Python3,修改了一個方法名:

Tag.has_key() -> Tag.has_attr()

修改了一個屬性名,讓它看起來更專業點:

Tag.isSelfClosing -> Tag.is_empty_element

修改了下面3個屬性的名字,以免雨Python保留字衝突.這些變動不是向下兼容的,如果在BS3中使用了這些屬性,那麼在BS4中這些代碼無法執行.

UnicodeDammit.Unicode -> UnicodeDammit.Unicode_markup``
Tag.next -> Tag.next_element
Tag.previous -> Tag.previous_element

生成器

將下列生成器按照PEP8標準重新命名,並轉換成對象的屬性:

childGenerator() -> children
nextGenerator() -> next_elements
nextSiblingGenerator() -> next_siblings
previousGenerator() -> previous_elements
previousSiblingGenerator() -> previous_siblings
recursiveChildGenerator() -> descendants
parentGenerator() -> parents

所以遷移到BS4版本時要替換這些代碼:

for parent in tag.parentGenerator():
    ...

替換爲:

for parent in tag.parents:
    ...

(兩種調用方法現在都能使用)

BS3中有的生成器循環結束後會返回 None 然後結束.這是個bug.新版生成器不再返回 None .

BS4中增加了2個新的生成器, .strings 和 stripped_strings . .strings 生成器返回NavigableString對象, .stripped_strings 方法返回去除前後空白的Python的string對象.

XML

BS4中移除了解析XML的 BeautifulStoneSoup 類.如果要解析一段XML文檔,使用 BeautifulSoup 構造方法並在第二個參數設置爲“xml”.同時 BeautifulSoup 構造方法也不再識別 isHTML 參數.

Beautiful Soup處理XML空標籤的方法升級了.舊版本中解析XML時必須指明哪個標籤是空標籤. 構造方法的 selfClosingTags 參數已經不再使用.新版Beautiful Soup將所有空標籤解析爲空元素,如果向空元素中添加子節點,那麼這個元素就不再是空元素了.

實體

HTML或XML實體都會被解析成Unicode字符,Beautiful Soup 3版本中有很多處理實體的方法,在新版中都被移除了. BeautifulSoup 構造方法也不再接受 smartQuotesTo 或 convertEntities 參數. 編碼自動檢測 方法依然有 smart_quotes_to 參數,但是默認會將引號轉換成Unicode.內容配置項 HTML_ENTITIES , XML_ENTITIES 和 XHTML_ENTITIES 在新版中被移除.因爲它們代表的特性已經不再被支持.

如果在輸出文檔時想把Unicode字符轉換成HTML實體,而不是輸出成UTF-8編碼,那就需要用到 輸出格式 的方法.

遷移雜項

Tag.string 屬性現在是一個遞歸操作.如果A標籤只包含了一個B標籤,那麼A標籤的.string屬性值與B標籤的.string屬性值相同.

多值屬性 比如 class 屬性包含一個他們的值的列表,而不是一個字符串.這可能會影響到如何按照CSS類名哦搜索tag.

如果使用 find* 方法時同時傳入了 text 參數 和 name 參數 .Beautiful Soup會搜索指定name的tag,並且這個tag的 Tag.string 屬性包含text參數的內容.結果中不會包含字符串本身.舊版本中Beautiful Soup會忽略掉tag參數,只搜索text參數.

BeautifulSoup 構造方法不再支持 markupMassage 參數.現在由解析器負責文檔的解析正確性.

很少被用到的幾個解析器方法在新版中被移除,比如 ICantBelieveItsBeautifulSoup 和 BeautifulSOAP .現在由解析器完全負責如何解釋模糊不清的文檔標記.

prettify() 方法在新版中返回Unicode字符串,不再返回字節流.

BeautifulSoup3 文檔

[1] BeautifulSoup的google討論組不是很活躍,可能是因爲庫已經比較完善了吧,但是作者還是會很熱心的儘量幫你解決問題的.
[2] (1, 2) 文檔被解析成樹形結構,所以下一步解析過程應該是當前節點的子節點
[3] 過濾器只能作爲搜索文檔的參數,或者說應該叫參數類型更爲貼切,原文中用了 filter 因此翻譯爲過濾器
[4] 元素參數,HTML文檔中的一個tag節點,不能是文本節點
[5] (1, 2, 3, 4, 5) 採用先序遍歷方式
[6] (1, 2) CSS選擇器是一種單獨的文檔搜索語法, 參考 http://www.w3school.com.cn/css/css_selector_type.asp
[7] 原文寫的是 html5lib, 譯者覺得這是願文檔的一個筆誤
[8] wrap含有包裝,打包的意思,但是這裏的包裝不是在外部包裝而是將當前tag的內部內容包裝在一個tag裏.包裝原來內容的新tag依然在執行 wrap() 方法的tag內
[9] 文檔中特殊編碼字符被替換成特殊字符(通常是�)的過程是Beautful Soup自動實現的,如果想要多種編碼格式的文檔被完全轉換正確,那麼,只好,預先手動處理,統一編碼格式
[10] (1, 2) 智能引號,常出現在microsoft的word軟件中,即在某一段落中按引號出現的順序每個引號都被自動轉換爲左引號,或右引號.

轉載自:http://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id44

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章