bs4,全稱BeautifulSoup 4
, 它是Python獨有的一種解析方式。也就是說只有Python語言才可以通過這種方式去解析資料。
BeautifulSoup 3 只支援Python2,所以已經被淘汰了。
官網的介紹是這樣的
Beautiful Soup 提供一些簡單的、python 式的函式用來處理導航、搜尋、修改分析樹等功能。它是一個工具箱,通過解析文件為使用者提供需要抓取的資料,因為簡單,所以不需要多少程式碼就可以寫出一個完整的應用程式。 Beautiful Soup 自動將輸入文件轉換為 Unicode 編碼,輸出文件轉換為 utf-8 編碼。你不需要考慮編碼方式,除非文件沒有指定一個編碼方式,這時,Beautiful Soup 就不能自動識別編碼方式了。然後,你僅僅需要說明一下原始編碼方式就可以了。 Beautiful Soup 已成為和 lxml、html6lib 一樣出色的 python 直譯器,為使用者靈活地提供不同的解析策略或強勁的速度。
看起來很複雜,我用自己的理解,通俗的解釋一下
我們知道一個網頁的原始碼,是由多個標籤組成,比如、
其他解析器的優缺點
一、bs4的安裝
pip install bs4
pip install lxml
使用bs4解析時,推薦使用lxml解析器。這個在用xpath解析的時候也會用到
二、bs4解析原理
- 首先例項化一個BeautifulSoup物件,並且將頁面原始碼載入到這個物件裡
- 呼叫BeautifulSoup物件中的相關屬性或者方法進行標籤定位和資料提取
1、如何例項化BeautifuSoup物件
a. 匯入bs4包
from bs4 import BeautifulSoup
b.例項化物件
網頁原始碼,又分為本地已經持久化的HTML檔案和網路上直接獲取的原始碼。
如果是本地已經持久化的檔案,可以通過下面的方式將原始碼載入到bs4物件中
fp = open('xxx.html', 'r', encoding='utf-8')
# lxml:解析器
soup = BeautifulSoup(fp, 'lxml')
如果是通過requests庫獲取的網頁原始碼,通過下面的方式進行載入
response = requests.get(url)
html = response.text
soup = BeautifulSoup(html, 'lxml')
c.資料解析的方法和屬性
bs4能夠將複雜的HTML轉換成一個樹形結構,每個節點都是Python物件。
soup.tagName(標籤名): 返回的是文件中第一次出現tagName對應的標籤及其相應內容
soup.tageName1.tageName2:返回tag1中tage2的標籤及其內容
soup.find:等同於soup.tagName,返回第一個匹配到的物件
soup.find_all:返回所有的匹配到的物件。
通過檢視原始碼會發現,find的本質其實就是呼叫了find_all, 然後返回第一個元素
引數解釋:
- name :要查詢的標籤名(字串、正則、方法、True)
- attrs: 標籤的屬性
- recursive: 遞迴
- text: 查詢文字
- **kwargs :其它 鍵值引數
def find(self, name=None, attrs={}, recursive=True, text=None,
**kwargs):
"""Return only the first child of this Tag matching the given
criteria."""
r = None
l = self.find_all(name, attrs, recursive, text, 1, **kwargs)
if l:
r = l[0]
return r
上圖是我從某網站擷取的部分畫面,翻譯成HTML如下(只保留了對本次分析有用的部分,為了方便閱讀刪除了地址的域名資訊)
<html>
<head><titel>測試Title</titel></head>
<body>
<div class="test">
<ul>
<li> <a href="zhaosi.html"><img src="123456789.jpg" /><p>尼古拉斯趙四</p></a> </li>
</ul>
</div>
<div class="nr_zt w1180">
<ul>
<li> <a id="star" href="zhengshuang.html"><img src="5940f2cd6b759.jpg" /><p>鄭爽</p></a> </li>
<li> <a id="star" href="zhuyilong.html"><img src="5b56e0fabf5bf.jpg" /><p>朱一龍</p></a> </li>
<li> <a id="star" href="zhoudongyu.html"><img src="5a28b93be8155.jpg" /><p>周冬雨</p></a> </li>
<li> <a id="star" href="huyitian_1.html"><img src="5aa36dfbe5f61.jpg" /><p>胡一天</p></a> </li>
<li> <a id="star" href="yiyangqianxi.html"><img src="5a28d243b0382.jpg" /><p>易烊千璽</p></a> </li>
<li> <a id="star" href="dilireba.html"><img src="5a28b69334087.jpg" /><p>迪麗熱巴</p></a> </li>
</ul>
</div>
</body>
</html>
看下面幾個例子
# 獲取第一個li標籤
# <li> <a href="http://www.win4000.com/mt/zhengshuang.html"><img src="http://pic1.win4000.com/tj/2017-06-14/5940f2cd6b759.jpg"/><p>鄭爽</p></a> </li>
print(soup.li)
# # 獲取第一個li標籤中a標籤
# <a href="http://www.win4000.com/mt/zhengshuang.html"><img src="http://pic1.win4000.com/tj/2017-06-14/5940f2cd6b759.jpg"/><p>鄭爽</p></a>
print(soup.li.a)
#獲取第一個li標籤中a標籤
print(soup.find('li').a)
# 獲取所有li標籤
print(soup.find_all('li'))
# 獲取title標籤
print(soup.title)
# 獲取a標籤的父級標籤
print(soup.a.parent)
# 獲取a標籤的父級標籤的名字
print(soup.a.parent.name)
如何獲取HTML中的href?
分析:href是a標籤中的一個屬性,而a標籤又在li標籤中
在bs4中提取標籤中的屬性可以通過attrs來獲取
from bs4 import BeautifulSoup
fp = open('baidu.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')
# 如果獲取一個可以這樣寫
result = soup.a.attrs['href']
# zhaosi.html
print(result)
# 獲取全部,可通過先獲取a標籤 然後遍歷獲取
all_result = soup.find_all('a')
for i in all_result:
print(i.attrs['href'])
print("* " * 40)
# 如果我只想獲取id = star的href,需要先對id進行篩選
# 返回所有包含id=star的a標籤
star_result = soup.find_all('a', id='star')
for i in star_result:
print(i.attrs['href'])
# 返回包含id的標籤(只要有id屬性,並且有值的標籤都返回)
soup.find_all(id=True)
# 假設尼古拉斯趙四 不是第一個a標籤中的內容.提取對應的href
# 需要先定位class=‘test’對應div的位置
# 方法一:
result = soup.find('div', 'test')
print(result.a['href'])
# 方法二(class為python中關鍵字,因此查詢html中的class屬性需要新增個下劃線 class_)
result1 = soup.find('div', class_='test')
print(result1.a['href'])
# 方法三
result2 = soup.find('div', attrs={'class': 'test'})
# 獲取第一個a標籤中的文字內容
print(soup.a.text)
a_result = soup.find_all('a')
for i in a_result:
# 生成的是一個迭代器
print(i.strings)
print(list(i.strings))
print(i.string)
print(i.text)
其他補充
# 返回子孫節點
# children返回迭代器
result = soup.a.children
for i in result:
print(i)
# 返回子孫節點, contents返回列表
r = soup.a.contents
print(r)
# 可以通過正則對某個屬性進行匹配
# 比如返回href中以zh開頭的標籤
import re
reg = re.compile('^zh')
result = soup.find_all(href=reg)
print(result)
選擇器
bs4非常強大,還支援css選擇器。通過select來完成
<html>
<head><titel>測試Title</titel></head>
<body>
<div class="test">
<ul>
<li> <a href="zhaosi.html"><img src="123456789.jpg" /><p>尼古拉斯趙四</p></a> </li>
</ul>
</div>
<div class="nr_zt w1180">
<ul>
<li> <a id="star" href="zhengshuang.html"><img src="5940f2cd6b759.jpg" /><p>鄭爽</p></a> </li>
<li> <a id="star" href="zhuyilong.html"><img src="5b56e0fabf5bf.jpg" /><p>朱一龍</p></a> </li>
<li> <a id="star" href="zhoudongyu.html"><img src="5a28b93be8155.jpg" /><p>周冬雨</p></a> </li>
<li> <a id="star" href="huyitian_1.html"><img src="5aa36dfbe5f61.jpg" /><p>胡一天</p></a> </li>
<li> <a id="star" href="yiyangqianxi.html"><img src="5a28d243b0382.jpg" /><p>易烊千璽</p></a> </li>
<li> <a id="star" href="dilireba.html"><img src="5a28b69334087.jpg" /><p>迪麗熱巴</p></a> </li>
</ul>
</div>
</body>
</html>
from bs4 import BeautifulSoup
fp = open('baidu.html', 'r', encoding='utf-8')
soup = BeautifulSoup(fp, 'lxml')
# 返回一個所有a標籤的列表
result = soup.select('a')
# 返回第一個
result1 = soup.select('a')[0]
"""
class選擇器 : .className
"""
# 一層一層的進行選擇,用 > 連線 即 > : 表示一個層級
# 輸出 class = nr_zt 下ul下的li下的a標籤集合
a = soup.select('.nr_zt > ul > li > a')
# 多個層級關聯,使用 空格。
# 輸出 class= 'nr_zt' 下的a標籤集合
b = soup.select('.nr_zt a')
"""
id選擇器: # idName
"""
result = soup.select('#star')
# 通過href屬性查詢,返回列表
soup.select('a[href="zhengshuang.html"]')
# 獲取對應標籤中img標籤的src值
a = soup.select('a[href="zhengshuang.html"]')[0]
print(a.img['src']) # 5940f2cd6b759.jpg
以上就是bs4的常用操作程式碼,實際上在具體的爬蟲過程中,匹配的方式比較靈活,所以大家也不用可以的去背,只需要記住其原理即可。