成功用 requests 外交官跨越網際網路,拿到了網頁的原始碼包裹。
但把包裹打開時,看到的卻是一堆外星文。
<html lang="zh-Hant">
<div class="title">
這堆長得像亂成一團的毛線球,在程式界就叫做 HTML(網頁結構語法)。
如果我們要一字一字用肉眼去翻裡面我們要的新聞標題,那還不如直接用瀏覽器看就好。
今天,我們要請出爬蟲界的第二位重量級大師—— BeautifulSoup。
它是一把神奇的特製梳子,能幫你把網頁原始碼這團亂毛線給優雅地梳理開來,精準抓出隱藏在裡面的黃金資料!
🏛️ 一分鐘讀懂 HTML:網頁就像一棟大樓
在呼叫大師之前,我們必須先看懂網頁的結構。
請把網頁想像成一棟大樓,裡面的資料都住在不同的「房間(標籤 Tag)」裡:
• 新聞大標題 :這是一間名叫 h1 的房間,裡面專門住著最重要的特大號標題。
• 段落文字 :這是一間名叫 p 的房間,裡面住著普通的文章段落。
• 網頁超連結 :這是一間名叫 a 的房間,專門負責通往別的網站。
大樓管理員為了方便區分,還會幫房間貼上「門牌貼紙(屬性 Attribute)」,最常用的貼紙叫 class(類別)。例如:
這代表:這是一間 h1 房間,而且它有著名為 news-title 的專屬門牌!
🛠️ 步驟一:安裝尋寶探測器
跟 requests 一樣,BeautifulSoup 也是第三方套件,需要動手安裝。
請在 VS Code 終端機輸入這行指令:
pip install beautifulsoup4
當看到 Successfully installed 之後,代表探測器已經成功裝進你的工具箱囉!
🛠️ 步驟二:實戰模擬!從亂碼中精準拆解
我們今天先不從網路抓,我們直接在程式裡放一段模擬的網頁代碼,來看看 BeautifulSoup 是如何發揮「照妖鏡」功能的:
#1.引入剛剛下載的寶庫
from bs4 import BeautifulSoup
#2.模擬一段從網路上抓下來的亂七八糟網頁原始碼
html_doc = """
<html>
<head><title>好人科技新聞網</title></head>
<body>
<h1 class="main-title">今日焦點新聞</h1>
<p class="content">Python 成為全球最受歡迎的新手程式語言!</p>
<p class="content">網路爬蟲技術大公開,新手看完直呼太簡單!</p>
<a class="link" href="https://example.com">點我看更多資訊</a>
</body>
</html>
"""
#3.把這團毛線球(原始碼)丟給 BeautifulSoup 梳理,並指定用 html 解析器
soup = BeautifulSoup(html_doc, "html.parser")
這時候,這個變數 soup 就已經不是單純的文字了,它變成了一個立體的大樓立體地圖!
🕵️ 兩大終極尋寶指令:find() 與 find_all()
有了地圖,我們就可以用兩個絕招來精準抓資料:
如果你只想抓最上面的焦點大標題,可以使用 find(),並指定房間名字和門牌:
#尋找名字叫 h1,且 class 門牌是 "main-title" 的房間
title_room = soup.find("h1", class_="main-title")
#.text 代表只要房間裡的「純文字」,不要那些外星人括號
print("抓到的標題是:", title_room.text)
(⚠️ 超微妙注意:因為 class 在 Python 裡是拿來宣告類別的關鍵字,為了不讓電腦混淆,BeautifulSoup 規定這裡要打成 class_,尾巴要多一個底線唷!)
如果今天有很多個段落內容,我們想全部收集起來,就要用 find_all()。它會把找到的所有房間包裝成一個 List(列表) 回傳給你:
#尋找所有名字叫 p,且 class 門牌是 "content" 的房間
all_paragraphs = soup.find_all("p", class_="content")
print("抓到的所有段落:")
#既然拿到的是 List,就用 Day 5 學的 for 迴圈逐一印出來!
for p in all_paragraphs:
print("- " + p.text)
執行後,終端機會超級乾淨地印出:
抓到的標題是: 今日焦點新聞
抓到的所有段落:
Python 成為全球最受歡迎的新手程式語言!
網路爬蟲技術大公開,新手看完直呼太簡單!
那些醜陋的 HTML 括號通通消失了,只剩下我們想要的黃金資料!
今日結語:你拿到尋寶地圖了嗎?
今天我們搞懂了 HTML 大樓的基本結構,並學會用 soup.find() 與 soup.find_all() 搭配 class_ 去提取純文字(.text)。這代表你已經具備了「數據清洗」的初心修為了!