本文是對BeautifulSoup4官方文檔的簡化與填坑
1.安裝
1.1安裝Beautiful Soup4
利用python包管理工具pip可以十分簡單的安裝Beautiful Soup4
$ pip install beautifulsoup4
1.2安裝第三方解析器lxml提高運行效率
Beautiful Soup支持Python標準庫中的HTML解析器,還支持一些第三方的解析器,其中一個是 lxml .
安裝方法
$ pip install lxml
PS: win下安裝lxml有坑,如果pip安裝報錯,參考StackOverflow上提供的解決方法
2.使用方法
from bs4 import BeautifulSoup
soup = BeautifulSoup(open("index.html"))
print(soup.prettify())
首先,文檔被轉(zhuǎn)換成Unicode,并且HTML的實例都被轉(zhuǎn)換成Unicode編碼揉抵。然后,Beautiful Soup選擇最合適的解析器來解析這段文檔,如果手動指定解析器那么Beautiful Soup會選擇指定的解析器來解析文檔
2.1 Beautiful Soup的對象
Beautiful Soup將復雜HTML文檔轉(zhuǎn)換成一個復雜的樹形結(jié)構,每個節(jié)點都是Python對象,所有對象可以歸納為4種: Tag , NavigableString , BeautifulSoup , Comment .
Tag
Tag 對象與XML或HTML原生文檔中的tag相同:
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
# <class 'bs4.element.Tag'>
Tag中有name和attributes屬性
tag.name
# u'b'
tag['class']
# u'boldest'
tag的屬性可以被添加,刪除或修改. 再說一次, tag的屬性操作方法與字典一樣
NavigableString(可以遍歷的字符串)
字符串常被包含在tag內(nèi).Beautiful Soup用 NavigableString 類來包裝tag中的字符串:
tag.string
# u'Extremely bold'
type(tag.string)
# <class 'bs4.element.NavigableString'>
一個 NavigableString字符串與Python中的Unicode字符串相同,并且還支持包含在 遍歷文檔樹 和 搜索文檔樹 中的一些特性. 通過 unicode()方法可以直接將 NavigableString對象轉(zhuǎn)換成Unicode字符串:
unicode_string = unicode(tag.string)
unicode_string
# u'Extremely bold'
type(unicode_string)
# <type 'unicode'>
BeautifulSoup
BeautifulSoup
對象表示的是一個文檔的全部內(nèi)容.大部分時候,可以把它當作 Tag
對象,它支持 遍歷文檔樹 和 搜索文檔樹 中描述的大部分的方法.
因為 BeautifulSoup對象并不是真正的HTML或XML的tag,所以它沒有name和attribute屬性.但有時查看它的 .name屬性是很方便的,所以 BeautifulSoup對象包含了一個值為 “[document]” 的特殊屬性 .name
soup.name
# u'[document]'
Comment(注釋及特殊字符串)
Tag , NavigableString , BeautifulSoup 幾乎覆蓋了html和xml中的所有內(nèi)容,但是還有一些特殊對象.容易讓人擔心的內(nèi)容是文檔的注釋部分
PS:由于爬蟲一般不需要爬注釋,不展開躺屁。
2.2 遍歷文檔樹
PS:樹,好大的樹
獲取標簽內(nèi)容:
獲取標簽內(nèi)容和剝洋蔥差不多
soup = '''
<head><title>The Dormouse's story</title></head>
<title>Another Dormouse's story</title>
'''
soup.head
# <head><title>The Dormouse's story</title></head>
soup.head.title
# <title>The Dormouse's story</title>
soup.title
# <title>The Dormouse's story</title>
soup.title.string
The Dormouse's story
可以看到使用title只能獲取到第一個title经宏,可以用find_all()需要獲取所有title犀暑,并返回一個list:
soup.find_all('title')
# [<title>The Dormouse's story</title>,<title>Another Dormouse's story</title>]
.contents ,.children烁兰,.descendants:
.contents 和 .children 屬性僅包含tag的直接子節(jié)點
.contents 屬性相當于剝一層洋蔥皮耐亏,并返回list:
head_tag = '''
<head><title>The Dormouse's story</title><title>Another Dormouse's story</title></head>
'''
head_tag.content
# [<title>The Dormouse's story</title>, <title>Another Dormouse's story</title>]
.children是列表迭代器,用for輸出:
html_doc = """<head><title>The Dormouse's story</title><title>T Dormouse's story</title></head>"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'lxml')
print(soup.head.children)
for child in soup.head.children:
print(child)
# <list_iterator object at 0x10b66c710>
# <title>The Dormouse's story</title>
# <title>T Dormouse's story</title>
.descendants 屬性和.children類似沪斟,不同的是.children只能訪問一層子節(jié)點广辰,而可以對所有tag的子孫節(jié)點進行遞歸循環(huán)
.strings 和以及更好的 stripped_strings
如果tag中包含多個字符串 ,可以使用 .strings來循環(huán)獲取,stripped_strings用于去除所有空白內(nèi)容,包括段落間空行:
.parent和.parents
.parent 屬性可以用來獲取某個元素的父節(jié)點择吊,.parents 屬性可以遞歸得到元素的所有父輩節(jié)點
兄弟節(jié)點
.next_sibling 和 .previous_sibling李根,.next_siblings 和 .previous_siblings:
在文檔樹中,使用 .next_sibling 和 .previous_sibling 屬性來查詢兄弟節(jié)點,通過 .next_siblings 和 .previous_siblings 屬性可以對當前節(jié)點的兄弟節(jié)點迭代輸出:
回退和前進
.next_element 和 .previous_element几睛,.next_elements 和 .previous_elements
.next_element 屬性指向解析過程中下一個被解析的對象(字符串或tag),結(jié)果可能與 .next_sibling 相同,但通常是不一樣的.通過 .next_elements 和 .previous_elements 的迭代器就可以向前或向后訪問文檔的解析內(nèi)容,就好像文檔正在被解析一樣.
2.3搜索文檔樹
find_all()
使用 find_all() 類似的方法可以查找到想要查找的文檔內(nèi)容房轿,find_all( name , attrs , recursive , text , **kwargs )
- name 參數(shù)可以查找所有名字為 name 的tag,字符串對象會被自動忽略掉.
- 如果一個指定名字的參數(shù)不是搜索內(nèi)置的參數(shù)名,搜索時會把該參數(shù)當作指定名字tag的屬性來搜索,如果包含一個名字為 id 的參數(shù),Beautiful Soup會搜索每個tag的”id”屬性.搜索指定名字的屬性時可以使用的參數(shù)值包括 字符串 , 正則表達式 , 列表, True .
- 按照CSS類名搜索tag的功能非常實用,但標識CSS類名的關鍵字 class 在Python中是保留字,使用 class 做參數(shù)會導致語法錯誤.從Beautiful Soup的4.1.1版本開始,可以通過 class_ 參數(shù)搜索有指定CSS類名的tag:
- 通過 text 參數(shù)可以搜搜文檔中的字符串內(nèi)容.與 name 參數(shù)的可選值一樣, text 參數(shù)接受 字符串 , 正則表達式 , 列表, True . 看例子:
- find_all() 方法返回全部的搜索結(jié)構,如果文檔樹很大那么搜索會很慢.如果我們不需要全部結(jié)果,可以使用 limit 參數(shù)限制返回結(jié)果的數(shù)量.
- 調(diào)用tag的 find_all() 方法時,Beautiful Soup會檢索當前tag的所有子孫節(jié)點,如果只想搜索tag的直接子節(jié)點,可以使用參數(shù) recursive=False
find_all('b')
# 返回所有b標簽
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# body
# b
# 通過正則表達式返回含有b開頭的標簽
soup.find_all(["a", "b"])
# 返回含有a或b標簽的
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
soup.find_all(has_class_but_no_id)
# [<p class="title"><b>The Dormouse's story</b></p>,
# <p class="story">Once upon a time there were...</p>,
# <p class="story">...</p>]
# 自定一種方法
find()
find('tag')相當于find_all('tag',limit = 1)
find_next_siblings() 合 find_next_sibling(),find_previous_siblings() 和 find_previous_sibling()
find_next_siblings( name , attrs , recursive , text , **kwargs )
find_next_sibling( name , attrs , recursive , text , **kwargs )
這2個方法通過 .next_siblings 屬性對當tag的所有后面解析 [5] 的兄弟tag節(jié)點進行迭代, find_next_siblings() 方法返回所有符合條件的后面的兄弟節(jié)點, find_next_sibling() 只返回符合條件的后面的第一個tag節(jié)點.
ind_previous_siblings( name , attrs , recursive , text , **kwargs )
find_previous_sibling( name , attrs , recursive , text , **kwargs )
這2個方法通過 .previous_siblings 屬性對當前tag的前面解析 [5] 的兄弟tag節(jié)點進行迭代, find_previous_siblings() 方法返回所有符合條件的前面的兄弟節(jié)點, find_previous_sibling() 方法返回第一個符合條件的前面的兄弟節(jié)點
find_all_next() 和 find_next()所森,find_all_previous() 和 find_previous()
find_all_next( name , attrs , recursive , text , **kwargs )囱持,find_next( name , attrs , recursive , text , **kwargs )
這2個方法通過 .next_elements 屬性對當前tag的之后的tag和字符串進行迭代, find_all_next() 方法返回所有符合條件的節(jié)點, find_next() 方法返回第一個符合條件的節(jié)點
find_all_previous( name , attrs , recursive , text , **kwargs ),find_previous( name , attrs , recursive , text , **kwargs )
這2個方法通過 .previous_elements 屬性對當前節(jié)點前面 [5] 的tag和字符串進行迭代, find_all_previous() 方法返回所有符合條件的節(jié)點, find_previous() 方法返回第一個符合條件的節(jié)點.
2.4 CSS選擇器
2.5 修改文檔樹
由于目前我接觸到的爬蟲都很少涉及到修改數(shù)據(jù)焕济,有需要自行參看Beautifulsoup官方文檔
2.6 輸出
get_text()
如果只想得到tag中包含的文本內(nèi)容,那么可以嗲用 get_text() 方法,這個方法獲取到tag中包含的所有文版內(nèi)容包括子孫tag中的內(nèi)容,并將結(jié)果作為Unicode字符串返回:
PS:其他內(nèi)容請查看官方文檔