一、簡(jiǎn)介
BeautifulSoup是一個(gè)靈活方便的網(wǎng)頁(yè)解析庫(kù),處理高效,能夠自動(dòng)的將輸入文檔轉(zhuǎn)換為Unicode編碼,輸出文檔轉(zhuǎn)換為utf-8編碼,且支持多種解析器。其最主要的功能是從網(wǎng)頁(yè)抓取數(shù)據(jù)。
二、解析器
解析器 | 使用方法 | 優(yōu)勢(shì) | 劣勢(shì) |
---|---|---|---|
Python標(biāo)準(zhǔn)庫(kù) | BeautifulSoup(markup, ‘html.parser’) | python內(nèi)置的標(biāo)準(zhǔn)庫(kù),執(zhí)行速度適中 | Python3.2.2之前的版本容錯(cuò)能力差 |
lxml HTML解析器 | BeautifulSoup(markup, ‘lxml’) | 速度快、文檔容錯(cuò)能力強(qiáng) | 需要安裝C語(yǔ)言庫(kù) |
lxml XML解析器 | BeautifulSoup(markup ‘xml’) | 速度快,唯一支持XML的解析器 | 需要安裝C語(yǔ)言庫(kù) |
html5lib | BeautifulSoup(markup, ‘html5lib’) | 最好的容錯(cuò)性、以瀏覽器的方式解析文檔、生成HTML5格式的文檔 | 速度慢,不依賴(lài)外部拓展 |
三、基本使用步驟
3.1 獲取網(wǎng)頁(yè)源碼也可以通過(guò)字符串自己構(gòu)建一個(gè)網(wǎng)頁(yè)的源碼
# 給請(qǐng)求指定一個(gè)請(qǐng)求頭來(lái)模擬chrome瀏覽器
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'}
# 爬圖地址
addr = 'https://sc.chinaz.com/tupian/'
def getHtmlSource():
# 使用請(qǐng)求頭來(lái)模擬chrome瀏覽器訪問(wèn)網(wǎng)頁(yè),獲取頁(yè)面響應(yīng)結(jié)果
res = requests.get(addr, headers=headers).text
print(res)
requests.get().text
返回的是Unicode型的數(shù)據(jù),requests.get().content
返回的是bytes型的數(shù)據(jù)。如果只是使用.text來(lái)獲取頁(yè)面源碼的話,獲取的源碼中中文會(huì)亂碼??梢允褂靡幌路椒ń鉀Q中文亂碼:
(1)手動(dòng)指定頁(yè)面編碼
res = requests.get(addr, headers=headers)
res.encoding = 'UTF-8'
html_doc = res.text
(2)使用.content方法
html_doc = str(requests.get(addr, headers=headers).content, 'UTF-8')
3.2 使用解析器解析頁(yè)面響應(yīng)結(jié)果
# 使用自帶的html.parser解析頁(yè)面響應(yīng)結(jié)果
soup = BeautifulSoup(html_doc, 'html.parser')
# 使用lxml HTML解析器解析頁(yè)面響應(yīng)結(jié)果
soup = BeautifulSoup(html_doc, 'lxml')
# 使用lxml XML解析器解析頁(yè)面響應(yīng)結(jié)果
soup = BeautifulSoup(html_doc, 'xml')
# 使用html5lib解析頁(yè)面響應(yīng)結(jié)果
soup = BeautifulSoup(html_doc, 'html5lib')
四、四大對(duì)象種類(lèi)
Beautiful Soup將復(fù)雜HTML文檔轉(zhuǎn)換成一個(gè)復(fù)雜的樹(shù)形結(jié)構(gòu),每個(gè)節(jié)點(diǎn)都是Python對(duì)象,所有對(duì)象可以歸納為4種:
- Tag
- NavigableString
- BeautifulSoup
- Comment
4.1 Tag
Tag 通俗點(diǎn)講就是 HTML 中的一個(gè)個(gè)標(biāo)簽,例如:title
、head
、a
、p
等等 HTML 標(biāo)簽加上里面包括的內(nèi)容就是 Tag。但是注意,它查找的是在所有內(nèi)容中的第一個(gè)符合要求的標(biāo)簽。
# 創(chuàng)建BeautifulSoup對(duì)象
soup = BeautifulSoup(html_doc, 'html.parser')
# 通過(guò)Tag對(duì)象獲取title標(biāo)簽信息
print(soup.title)
## <title>圖片、圖片下載、高清圖片材</title>
# 通過(guò)Tag對(duì)象獲取a標(biāo)簽信息
print(soup.a)
## <a class="logo" href="/"><img src="../static/common/com_images/image.png"/></a>
Tag 它有兩個(gè)重要的屬性,是 name 和 attrs。
(1) name: 輸出標(biāo)簽的標(biāo)簽類(lèi)型名:
print(soup.title.name)
# title
print(soup.p.name)
# p
(2) attrs: 以字典的形式獲取標(biāo)簽的屬性:
# 獲取標(biāo)簽的所有屬性
soup.p.attrs
# 獲取標(biāo)簽的某個(gè)屬性
soup.p.attrs['js-do']
soup.p.get('js-do')
# 修改標(biāo)簽的屬性
soup.p.attrs['js-do'] = 'newContenct'
# 刪除標(biāo)簽的屬性
del soup.p.attrs['js-do']
4.2 NavigableString
注意作用是為了獲取標(biāo)簽內(nèi)部的文字。
# 獲取標(biāo)簽內(nèi)部文字
print(soup.title.string)
4.3 BeautifulSoup
BeautifulSoup 對(duì)象表示的是一個(gè)文檔的內(nèi)容。大部分時(shí)候,可以把它當(dāng)作 Tag 對(duì)象,是一個(gè)特殊的 Tag,我們也可以獲取它的屬性及名稱(chēng)。
# 獲取BeautifulSoup對(duì)象名稱(chēng)
print(soup.name)
# 獲取BeautifulSoup對(duì)象屬性
print(soup.attr)
4.4 Comment
Comment 對(duì)象是一個(gè)特殊類(lèi)型的 NavigableString 對(duì)象,如果標(biāo)簽內(nèi)部的內(nèi)容是注釋?zhuān)漭敵龅膬?nèi)容不包括注釋符號(hào)。
print(soup.a)
## <a class="logo" href=""><!-- zhushi --></a>
print(soup.a.string)
## zhushi
print(type(soup.a.string))
## <class 'bs4.element.Comment'>
五、搜索文檔樹(shù)
find(name, attrs, recursive, string, **kwargs)
:獲取匹配的第一個(gè)標(biāo)簽;find_all(name, attrs, recursive, string, limit, **kwargs)
:返回結(jié)果是值包含一個(gè)元素的列表;
-
name
:是根據(jù)標(biāo)簽的名稱(chēng)進(jìn)行匹配,name的值相當(dāng)于過(guò)濾條件,可以是一個(gè)具體的標(biāo)簽名,多個(gè)標(biāo)簽名組成的列表,或者是一個(gè)正在表達(dá)式,甚至是函數(shù)方法等等。 -
attrs
:是根據(jù)標(biāo)簽的屬性進(jìn)行匹配。 -
recursive
:是否遞歸搜索,默認(rèn)為T(mén)rue,會(huì)搜索當(dāng)前tag的所有子孫節(jié)點(diǎn),設(shè)置為False,則只搜索兒子節(jié)點(diǎn)。 -
string
:是根據(jù)標(biāo)簽的文本內(nèi)容去匹配。 -
limit
:設(shè)置查詢(xún)的結(jié)果數(shù)量。 -
kwargs
:也是根據(jù)標(biāo)簽的屬性進(jìn)行匹配,與attrs的區(qū)別在于寫(xiě)法不一樣,且屬性的key不能是保留字,也不能與其他參數(shù)名相同。
5.1 使用name進(jìn)行匹配
# 查找所有的<a>標(biāo)簽
soup.find_all(name="a") # 可以簡(jiǎn)寫(xiě)成 soup.find_all("a")
# 查找所有的<title>標(biāo)簽或者<link>標(biāo)簽
soup.find_all(name={'title', 'link'}) # 可以簡(jiǎn)寫(xiě)成 soup.find_all(['title', 'link'])
# 查找所有以a開(kāi)頭的標(biāo)簽
soup.find_all(name=re.compile("^a")) # 可以簡(jiǎn)寫(xiě)成 soup.find_all(re.compile("^a"))
# 查找有class屬性并且沒(méi)有id屬性的節(jié)點(diǎn)
soup.find_all(hasClassNoId)
def hasClassNoId(tag):
return tag.has_attr('class') and not tag.has_attr('id')
# 查找body里面所有標(biāo)簽
soup.find('body').find_all(True)
5.2 使用attrs進(jìn)行匹配
# 查找所有name屬性值為tb_name的標(biāo)簽
soup.find_all(attrs={"name": "tb_name"})
# 查找所有id屬性值為id_attr1或者id_attr2的標(biāo)簽
soup.find_all(attrs={'id': ['id_attr1', 'id_attr2']})
# 查找id屬性值中含有id_的所有標(biāo)簽
soup.find_all(attrs={'id':re.compiles('id_')})
# 查找含有id屬性的所有tag
soup.find_all(attrs={'id':True})
# 查找href屬性值中以.html結(jié)尾的所有標(biāo)簽
soup.find_all(attrs={'href': search_html})
def search_html(attr):
return attr and attr.lower().endswith('.html')
5.3 使用kwargs進(jìn)行匹配
也是通過(guò)標(biāo)簽的屬性進(jìn)行匹配,需要特別注意的是name屬性以及class屬性,name屬于與find_all方法的第一個(gè)參數(shù)名相同,這里使用name='屬性值'進(jìn)行查詢(xún)的話,如果是一個(gè)參數(shù)會(huì)與標(biāo)簽名進(jìn)行匹配,如果是多個(gè)參數(shù),則方法會(huì)報(bào)錯(cuò);而class是python的保留字,使用class屬性進(jìn)行匹配的時(shí)候需要寫(xiě)成class_='屬性值'的方式
# 查找<div>中name屬性值是backpage的所有標(biāo)簽
soup.find_all('div', name='backpage') ## 會(huì)報(bào)錯(cuò)
# 查找class屬性值是backpage的所有標(biāo)簽
soup.find_all(class_='backpage')
# 查找所有id屬性值為id_attr1或者id_attr2的標(biāo)簽
soup.find_all(id=['id_attr1', 'id_attr2'])
# 查找href的屬性值包含.html的所有的標(biāo)簽
soup.find_all(href=re.compile('.html'))
# 查找含有id屬性的所有tag
soup.find_all(id=True)
# 查找href屬性值中以.html結(jié)尾的所有標(biāo)簽
soup.find_all(href= search_html)
def search_html(attr):
return attr and attr.lower().endswith('.html')
5.4 使用string進(jìn)行匹配
需要注意的是這里返回標(biāo)簽的值,如果需要獲取到對(duì)應(yīng)的標(biāo)簽,可以使用previous_element屬性來(lái)獲得
# 查找標(biāo)簽的value是'上一頁(yè)'的所有value值
soup.find_all(string='上一頁(yè)')
# 查找標(biāo)簽的value是'上一頁(yè)'的所有標(biāo)簽
[value.previous_element for value in soup.find_all(string='上一頁(yè)')]
# 查找value是'上一頁(yè)'或者'下一頁(yè)'的所有value值
soup.find_all(string=['上一頁(yè)','下一頁(yè)'])
# 查找value中存在'頁(yè)'的所有value值
soup.find_all(string=re.compile('頁(yè)'))
# 查找在value值的所有的string
soup.find_all(string=True)
# 查找所有value值是以'頁(yè)'為結(jié)尾的value值
soup.find_all(string=search_string)
def search_string(string):
return string and string.lower().endswith('頁(yè)')
六、遍歷文檔樹(shù)
-
contents
:返回的是一個(gè)包含所有兒子節(jié)點(diǎn)的列表。 -
children
:返回的是一個(gè)包含所有兒子節(jié)點(diǎn)的迭代器。 -
descendants
:返回的是一個(gè)包含所有子孫節(jié)點(diǎn)的生成器。
contents、children只包含直接兒子節(jié)點(diǎn),descendants既包含兒子節(jié)點(diǎn)還包含孫子節(jié)點(diǎn)。
6.1 通過(guò)contents獲取目標(biāo)節(jié)點(diǎn)的所有子節(jié)點(diǎn)
tag_soup = soup.find('div', class_='container').contents
print(type(tag_soup))
for t in tag_soup:
if t != '\n': # 去掉換行符
print(t)
6.2 通過(guò)children獲取目標(biāo)節(jié)點(diǎn)的所有子節(jié)點(diǎn)
tag_soup = soup.find('div', class_='container').children
print(type(tag_soup))
for t in tag_soup:
if t != '\n': # 去掉換行符
print(t)
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-786086.html
6.3 通過(guò)descendants獲取目標(biāo)節(jié)點(diǎn)的所有子孫節(jié)點(diǎn)
tag_soup = soup.find('div', class_='container').descendants
print(type(tag_soup))
for t in tag_soup:
if t != '\n': # 去掉換行符
print(t)
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-786086.html
6.4 通過(guò)parents獲取目標(biāo)節(jié)點(diǎn)的所有祖先節(jié)點(diǎn)
tag_soup = soup.find('div', class_='container').parents
print(type(tag_soup))
for t in tag_soup:
if t != '\n': # 去掉換行符
print(t)
6.5 獲取目標(biāo)節(jié)點(diǎn)相關(guān)聯(lián)的其他節(jié)點(diǎn)
a_soup = soup.find('div', class_='container').a # 獲取div里面的第一個(gè)<a>標(biāo)簽
print(a_soup.parent) # 獲取<a>標(biāo)簽的父節(jié)點(diǎn)
print(a_soup.next_sibling) # 獲取<a>標(biāo)簽的下一個(gè)兄弟節(jié)點(diǎn)
print(a_soup.previous_sibling) # 獲取<a>標(biāo)簽的上一個(gè)兄弟節(jié)點(diǎn)
print(a_soup.next_siblings) # 獲取<a>標(biāo)簽下面的所有兄弟節(jié)點(diǎn)
print(a_soup.previous_siblings) # 獲取<a>標(biāo)簽上面的所有兄弟節(jié)點(diǎn)
七、css選擇器
7.1 通過(guò)標(biāo)簽名查找
# 查找所有title標(biāo)簽
soup.select('title')
# 查找div下的所有input標(biāo)簽
soup.select('div input')
# 查找html節(jié)點(diǎn)下的head節(jié)點(diǎn)下的title標(biāo)簽
soup.select("html head title")
7.2 通過(guò)id查找
# 查找id為id_text的標(biāo)簽
soup.select("#id_text")
# 查找id為id_text1、id_text2的標(biāo)簽
soup.select("#id_text1, #id_text2")
# 查找id為id_text1的input標(biāo)簽
soup.select('input#id_text1')
7.3 通過(guò)類(lèi)名查找
# 查找類(lèi)名為nextpage的標(biāo)簽
soup.select(".nextpage")
# 查找類(lèi)名為nextpage、active的標(biāo)簽
soup.select('.nextpage, .active')
# 查找類(lèi)名為nextpage的a標(biāo)簽
soup.select('a.nextpage')
7.4 通過(guò)屬性查找
# 選擇有href屬性的a標(biāo)簽
soup.select('a[href]')
# 選擇href屬性為index_2.html的a標(biāo)簽
soup.select('a[href="index_2.html"]')
# 選擇href以index開(kāi)頭的a標(biāo)簽
soup.select('a[href^="index"]')
# 選擇href以html結(jié)尾的a標(biāo)簽
soup.select('a[href$="html"]')
# 選擇href屬性包含index的a標(biāo)簽
soup.select('a[href*="index"]')
7.5 其他選擇器
# 查找div標(biāo)簽下的a標(biāo)簽
soup.select("div > a")
# 父節(jié)點(diǎn)中的第3個(gè)a標(biāo)簽
soup.select("a:nth-of-type(3)")
# a標(biāo)簽之后的input標(biāo)簽(a和input有共同父節(jié)點(diǎn))
soup.select("a~input")
到了這里,關(guān)于Python之BeautifulSoup庫(kù)詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!