爬蟲系列 | 6、詳解爬蟲中BeautifulSoup4的用法

初一丶發表於2021-01-19

bs4,全稱BeautifulSoup 4 , 它是Python獨有的一種解析方式。也就是說只有Python語言才可以通過這種方式去解析資料。

BeautifulSoup 3 只支援Python2,所以已經被淘汰了。

官網的介紹是這樣的

Beautiful Soup 提供一些簡單的、python 式的函式用來處理導航、搜尋、修改分析樹等功能。它是一個工具箱,通過解析文件為使用者提供需要抓取的資料,因為簡單,所以不需要多少程式碼就可以寫出一個完整的應用程式。 Beautiful Soup 自動將輸入文件轉換為 Unicode 編碼,輸出文件轉換為 utf-8 編碼。你不需要考慮編碼方式,除非文件沒有指定一個編碼方式,這時,Beautiful Soup 就不能自動識別編碼方式了。然後,你僅僅需要說明一下原始編碼方式就可以了。 Beautiful Soup 已成為和 lxml、html6lib 一樣出色的 python 直譯器,為使用者靈活地提供不同的解析策略或強勁的速度。

看起來很複雜,我用自己的理解,通俗的解釋一下

我們知道一個網頁的原始碼,是由多個標籤組成,比如、

、、等等組成的,而bs4就是用來幫我們精確定位標籤位置,從而獲取標籤或者標籤屬性中內容的工具。bs4預設自帶的解析器,但是官方推薦的是更強大 速度更快的 lxml解析器

其他解析器的優缺點

1561447662879877.png

一、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

image-20210103164834540

上圖是我從某網站擷取的部分畫面,翻譯成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的常用操作程式碼,實際上在具體的爬蟲過程中,匹配的方式比較靈活,所以大家也不用可以的去背,只需要記住其原理即可。

在這裡插入圖片描述

相關文章