BeautifulSoup4庫是一個用來解析網頁的庫,多用於對網頁數據的分析,整合,下面介紹一下他的安裝依舊很簡單pip install bs4
就可以,若使用pycharm的話,可以點擊settings然後搜索Project Interpreter,然後點擊加號搜索bs4,點擊install即可
以下是一些BeautifulSoup4的常用解析庫
解析器 | 使用方法 | 優勢 | 劣勢 |
---|---|---|---|
Python標準庫 | BeautifulSoup(markup, “html.parser”) | Python的內置標準庫,執行速度適中,文檔容錯能力強 | Python2.7.3和Python3.2.2之前的版本中文容錯能力差 |
lxml HTML解析器 | BeautifulSoup(markup, “lxml”) | 速度快,文檔容錯能力差 | 需要安裝C語言庫 |
lxml XMl解析器 | BeautifulSoup(markup, “xml”) | 速度快,唯一支持XML的解析器 | 需要安裝C語言庫 |
html5lib | BeautifulSoup(markup, “html5lib”) | 擁有最好的容錯性,以瀏覽器的方式解析文檔,生成HTML5格式的文檔 | 速度慢,不依賴外部擴展 |
下面介紹BeautifulSoup常用的方法
以下面的這一段代碼做例子(只是用來演示BeautifulSoup的用法)
<html>
<head>
<title>this is a title</title>
</head>
<body>
<p class="first" name="first">this is a p label</p>
<p class="second" name="second"><b>this is a p label, too</b></p>
<p class="third" name="third">also, a p label</p>
<a href="http://www.baidu.com" class="first" id="one">this is an a label</a>
<a href="http://www.baidu.com" class="second" id="two">this is an a label, too</a>
<a href="http://www.baidu.com" class="third" id="three">an a label also</a>
</body>
</html>
1.標籤選擇器
from bs4 import BeautifulSoup
text = '''<html>
<head><title>this is a title</title>
</head>
<body>
<p class="first" name="first">this is a p label</p>
<p class="second" name="second"><b>this is a p label, too</b></p>
<p class="third" name="third">also, a p label</p>
<a href="http://www.baidu.com" class="first" id="one">this is an a label</a>
<a href="http://www.baidu.com" class="second" id="two">this is an a label, too</a>
<a href="http://www.baidu.com" class="third" id="three">an a label also</a>
'''
# 這裏我定義了一個大的字符串就是上邊的那個測試代碼,注意我把</body></html>這倆閉合標籤刪掉了
soup = BeautifulSoup(text, "lxml")
print(soup.prettify())
(結果)太長了我就不粘了,你會發現,打印的就是整理好的HTML代碼,他把每個標籤都補上並且格式化了
################################################################
'''標籤選擇器'''
#### 選擇元素
print(soup.title) # 該方法會把title標籤和內容打印出來
(結果)<title>this is a title</title>
print(type(soup.title)) # 打印標籤的類型看看
(結果)<class 'bs4.element.Tag'> # 表示就是一個bs4的元素標籤
print(soup.head) # 打印head標籤和內容
(結果)<head><title>this is a title</title>
</head> # 因爲源字符串我們是有回車的 所以這裏有一個回車
print(soup.p)
(結果)<p class="first" name="first">this is a p label</p>
# 可以發現他只打印了第一個p標籤,這點要注意
#### 獲取屬性
soup = BeautifulSoup(text, 'lxml')
print(soup.p.attrs("name"))
(結果)first
print(soup.p["name"])
(結果)first
'''兩種方式都可以打印出name屬性的值,這裏的p依舊是隻獲取第一個p標籤的值'''
#### 獲取標籤的內容
print(soup.p.string)
(結果)this is a p label
'''string可以獲取該標籤裏的內容'''
#### 嵌套選擇
print(soup.head.title.string)
(結果)this is a title
'''就是通過層層迭代的形式吧title內容選出來'''
#### 子節點和子孫節點
print(soup.head.string)
(結果)None # 結果竟然是None
print(soup.head.contents)
(結果)[<title>this is a title</title>, '\n']
'''沒錯,string只可以打印標籤內部的字符串內容,對於嵌套的標籤就無能爲力
我們可以用contents來打印子標籤
'''
print(soup.body.children)
(結果)<list_iterator object at 0x000001DE702CB508>
'''沒錯,他返回了一個迭代器對象,我們可以通過一下方法遍歷出來'''
for i, child in enumerate(soup.body.children):
print(i, child)
(結果)
0
1 <p class="first" name="first">this is a p label</p>
2
3 <p class="second" name="second"><b>this is a p label, too</b></p>
4
5 <p class="third" name="third">also, a p label</p>
6
7 <a class="first" href="http://www.baidu.com" id="one">this is an a label</a>
8
9 <a class="second" href="http://www.baidu.com" id="two">this is an a label, too</a>
10
11 <a class="third" href="http://www.baidu.com" id="three">an a label also</a>
'''他會把每一個子內容都打印出來,連回車都不放過'''
print(soup.body.descendants)
(結果)
0
1 <p class="first" name="first">this is a p label</p>
2 this is a p label
3
4 <p class="second" name="second"><b>this is a p label, too</b></p>
5 <b>this is a p label, too</b>
6 this is a p label, too
7
8 <p class="third" name="third">also, a p label</p>
9 also, a p label
10
11 <a class="first" href="http://www.baidu.com" id="one">this is an a label</a>
12 this is an a label
13
14 <a class="second" href="http://www.baidu.com" id="two">this is an a label, too</a>
15 this is an a label, too
16
17 <a class="third" href="http://www.baidu.com" id="three">an a label also</a>
18 an a label also
'''我們可以看到descendants方法是吧所有的子孫節點打印了出來
第二個p標籤是有一個嵌套的,children沒有打印出來,而descandants則全都打印了出來
children只打印孩子節點,這點要區分開
'''
#### 獲取父節點和祖先節點
print(soup.a.parent)
(結果)
<body>
<p class="first" name="first">this is a p label</p>
<p class="second" name="second"><b>this is a p label, too</b></p>
<p class="third" name="third">also, a p label</p>
<a class="first" href="http://www.baidu.com" id="one">this is an a label</a>
<a class="second" href="http://www.baidu.com" id="two">this is an a label, too</a>
<a class="third" href="http://www.baidu.com" id="three">an a label also</a></body>
'''可以注意到他把第一個a標籤的父節點body打印了出來,
我們知道text裏邊的body是不完整的,這裏還把body補全了'''
print(soup.b.parents)
(結果)<generator object PageElement.parents at 0x0000013DB0A7E7C8>
# 可以發現這又是一個枚舉類型,我們用for遍歷他
for i, parent in enumerate(soup.b.praents):
print(i, parent)
(結果) #####這個是結果######################################
0 <p class="second" name="second"><b>this is a p label, too</b></p>
1 <body>
<p class="first" name="first">this is a p label</p>
<p class="second" name="second"><b>this is a p label, too</b></p>
<p class="third" name="third">also, a p label</p>
<a class="first" href="http://www.baidu.com" id="one">this is an a label</a>
<a class="second" href="http://www.baidu.com" id="two">this is an a label, too</a>
<a class="third" href="http://www.baidu.com" id="three">an a label also</a></body>
2 <html>
<head><title>this is a title</title>
</head>
<body>
<p class="first" name="first">this is a p label</p>
<p class="second" name="second"><b>this is a p label, too</b></p>
<p class="third" name="third">also, a p label</p>
<a class="first" href="http://www.baidu.com" id="one">this is an a label</a>
<a class="second" href="http://www.baidu.com" id="two">this is an a label, too</a>
<a class="third" href="http://www.baidu.com" id="three">an a label also</a></body></html>
3 <html>
<head><title>this is a title</title>
</head>
<body>
<p class="first" name="first">this is a p label</p>
<p class="second" name="second"><b>this is a p label, too</b></p>
<p class="third" name="third">also, a p label</p>
<a class="first" href="http://www.baidu.com" id="one">this is an a label</a>
<a class="second" href="http://www.baidu.com" id="two">this is an a label, too</a>
<a class="third" href="http://www.baidu.com" id="three">an a label also</a></body></html>
'''可以看到吧所有的祖先標籤都打印出來了
最後一個枚舉是吧整個文檔輸出了一遍,其實和倒數第二個一樣
'''
#### 兄弟節點
soup = BeautifulSoup(text, 'lxml')
for i,brother in enumerate(soup.p.next_siblings):
print(i, brother)
(結果) # 他會打印第一個p標籤下邊的所有並列的標籤
0
1 <p class="second" name="second"><b>this is a p label, too</b></p>
2
3 <p class="third" name="third">also, a p label</p>
4
5 <a class="first" href="http://www.baidu.com" id="one">this is an a label</a>
6
7 <a class="second" href="http://www.baidu.com" id="two">this is an a label, too</a>
8
9 <a class="third" href="http://www.baidu.com" id="three">an a label also</a>
for i, brother in enumerate(body.a.previous_siblings):
print(i, brother)
(結果)
0
1 <p class="third" name="third">also, a p label</p>
2
3 <p class="second" name="second"><b>this is a p label, too</b></p>
4
5 <p class="first" name="first">this is a p label</p>
6
'''打印第一個a標籤上邊的並列的所有標籤'''
2.標準選擇器
#### find_all()
soup = BeautifulSoup(text, 'lxml')
print(soup.find_all("p"))
(結果)
[<p class="first" name="first">this is a p label</p>,
<p class="second" name="second"><b>this is a p label, too</b></p>,
<p class="third" name="third">also, a p label</p>]
'''他返回了一個列表,裏邊是所有的p標籤,解決了soup.p的雞肋'''
print(soup.find_all('p')[0]) # 獲取第一個p標籤
#### attrs
print(soup.find_all(attrs={'class': 'first'}))
(結果)[<p class="first" name="first">this is a p label</p>,
<a class="first" href="http://www.baidu.com" id="one">this is an a label</a>]
'''可以看到他打印了所有Class爲first的標籤,其他標籤用法都一樣
對於id和class它本身自帶了id和Class的查找方法,如下所示
'''
print(soup.find_all(class_="first")
(結果)[<p class="first" name="first">this is a p label</p>,
<a class="first" href="http://www.baidu.com" id="one">this is an a label</a>]
'''可以看到和上邊的查詢結果是一樣的,這裏要注意class要寫作class_
主要原因是class本身在python中是類的意思,他是一個專有名詞,對於HTML裏邊的class,就要用class_代替
id 的用法就可以直接寫作find_all(id="first")
'''
#### find()
print(soup.find('p'))
(結果)<p class="first" name="first">this is a p label</p>
'''可以看到他只會返回一個,第一個元素,好吧相對於find_all()稍微有點雞肋'''
3.CSS
選擇器
soup = BeautifulSoup(text, 'lxml')
print(soup.select(".first"))
(結果)[<p class="first" name="first">this is a p label</p>,
<a class="first" href="http://www.baidu.com" id="one">this is an a label</a>]
'''可以看到他可以把class爲first的全部選擇出來,前邊加.就是class, 加#就是id'''
print(soup.select("p"))
(結果)[<p class="first" name="first">this is a p label</p>,
<p class="second" name="second"><b>this is a p label, too</b></p>,
<p class="third" name="third">also, a p label</p>]
'''可以看到他也可以選擇標籤和jquery很像很像
也可以嵌套選擇,如下
'''
print(soup.select("body p b"))
(結果)[<b>this is a p label, too</b>]
#### 獲取屬性
temp = soup.select("p")
for i in temp:
print(i['id'])
print(i.attrs['id'])
(結果)
['first']
['first']
['second']
['second']
['third']
['third']
'''可以看到兩種方式都可以把屬性的值打印出來'''
#### 獲取內容(最後一個)
temp = soup.select("p")
for i in temp:
print(i.get_text())
(結果)
this is a p label
this is a p label, too
also, a p label
完結撒花…以上就是BeautifulSoup的常用用法,多寫寫,多練練就OK