python爬蟲之BeautifulSoup4庫的簡單用法

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

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