輸出
格式化輸出
prettify() 方法將Beautiful Soup的文檔樹格式化后以Unicode編碼輸出,每個XML/HTML標簽都獨占一行
>>> markup = '<a >I linked to <i>example.com</i></a>'
>>> soup = BeautifulSoup(markup)
>>> soup.prettify()
'<html>\n <body>\n <a >\n I linked to\n <i>\n example.com\n </i>\n </a>\n </body
>\n</html>'
>>> print(soup.prettify())
<html>
<body>
<a >
I linked to
<i>
example.com
</i>
</a>
</body>
</html>
BeautifulSoup 對象和它的tag節點都可以調用 prettify() 方法:
>>> print(soup.a.prettify())
<a >
I linked to
<i>
example.com
</i>
</a>
壓縮輸出
如果只想得到結果字符串,不重視格式,那么可以對一個 BeautifulSoup 對象或 Tag 對象使用Python的 unicode() 或 str() 方法:
>>> str(soup)
'<html><body><a >I linked to <i>example.com</i></a></body></html>'
str() 方法返回UTF-8編碼的字符串,可以指定 編碼 的設置.
還可以調用 encode() 方法獲得字節碼或調用 decode() 方法獲得Unicode.
輸出格式
Beautiful Soup輸出是會將HTML中的特殊字符轉換成Unicode,比如“&lquot;”:
soup = BeautifulSoup("“Dammit!” 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 >\nI linked to <i>example.com</i>\n</a>'
>>> soup = BeautifulSoup(markup)
>>> soup.get_text()
'\nI linked to example.com\n'
>>> soup.i.get_text()
'example.com'
可以通過參數指定tag的文本內容的分隔符:
>>> soup.get_text("/")
'\nI linked to /example.com/\n'
還可以去除獲得文本內容的前后空白:
>>> soup.get_text("/",strip=True)
'I linked to/example.com'
或者使用 .stripped_strings 生成器,獲得文本列表后手動處理列表:
>>> [text for text in soup.stripped_strings]
['I linked to', '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><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 庫類似的,Python內置庫忽略掉了</p>標簽,與html5lib庫不同的是標準庫沒有嘗試創建符合標準的文檔格式或將文檔片段包含在<body>標簽內,與lxml不同的是標準庫甚至連<html>標簽都沒有嘗試去添加.
因為文檔片段“<a></p>”是錯誤格式,所以以上解析方式都能算作”正確”,html5lib庫使用的是HTML5的部分標準,所以最接近”正確”.不過所有解析器的結構都能夠被認為是”正常”的.
不同的解析器可能影響代碼執行結果,如果在分發給別人的代碼中使用了 BeautifulSoup ,那么最好注明使用了哪種解析器,以減少不必要的麻煩.
任重道遠