這次的主題是「書籍爬蟲與價格分析系統」,希望透過 Python 自動取得網站上的書籍資料,將資料清理後存進資料庫,再進行統計分析和視覺化。
整個流程如下:
網站資料 → Requests 取得 HTML → BeautifulSoup 解析資料 → Pandas 清理與分析 → SQLite 儲存 → Matplotlib 製作圖表。
本次使用公開練習網站 Books to Scrape 作為爬蟲練習對象,並使用 Google Colab 執行程式。
一、安裝與匯入套件
先匯入這次會使用到的套件。
import requests
from bs4 import BeautifulSoup
import pandas as pd
import sqlite3
import matplotlib.pyplot as plt
import time
from urllib.parse import urljoin
各套件的用途如下:
requests:向網站發送 HTTP 請求。
BeautifulSoup:解析 HTML,取得書名、價格和評分。
pandas:整理資料並進行統計分析。
sqlite3:建立 SQLite 資料庫並儲存資料。
matplotlib:將分析結果轉換成圖表。
time:控制請求間隔,避免過度頻繁地存取網站。
urljoin:將相對網址轉換成完整網址。
二、使用 Requests 和 BeautifulSoup 爬取書籍
首先先取得網站的 HTML,再從每本書的區塊中擷取需要的資訊。
這次預計取得以下欄位:
書名:title
價格:price
評分:rating
庫存狀態:availability
網址:url
base_url = "https://books.toscrape.com/catalogue/"
current_url = "https://books.toscrape.com/catalogue/page-1.html"
headers = {
"User-Agent": "Mozilla/5.0"
}
all_books = []
rating_map = {
"One": 1,
"Two": 2,
"Three": 3,
"Four": 4,
"Five": 5
}
while current_url:
try:
response = requests.get(
current_url,
headers=headers,
timeout=10
)
response.raise_for_status()
except requests.RequestException as e:
print("網頁讀取失敗:", e)
break
soup = BeautifulSoup(response.text, "html.parser")
books = soup.select("article.product_pod")
for book in books:
title_tag = book.select_one("h3 a")
price_tag = book.select_one(".price_color")
rating_tag = book.select_one(".star-rating")
stock_tag = book.select_one(".availability")
link_tag = book.select_one("h3 a")
if not all([
title_tag,
price_tag,
rating_tag,
stock_tag,
link_tag
]):
continue
title = title_tag.get("title", "").strip()
# 清理價格符號
price_text = price_tag.get_text(strip=True)
price_text = price_text.replace("£", "").strip()
try:
price = float(price_text)
except ValueError:
continue
# 將英文評分轉換成數字
rating_text = rating_tag.get("class", [])
rating_word = next(
(word for word in rating_text if word in rating_map),
None
)
if rating_word is None:
continue
rating = rating_map[rating_word]
# 清理庫存文字
availability = stock_tag.get_text(
" ",
strip=True
)
# 取得書籍完整網址
book_url = urljoin(
current_url,
link_tag.get("href", "")
)
all_books.append({
"title": title,
"price": price,
"rating": rating,
"availability": availability,
"url": book_url
})
# 找下一頁
next_tag = soup.select_one("li.next a")
if next_tag:
current_url = urljoin(
current_url,
next_tag.get("href")
)
else:
current_url = None
print("目前累積書籍數量:", len(all_books))
# 控制請求頻率
if current_url:
time.sleep(1)
print("爬取完成,共取得", len(all_books), "筆書籍資料")
這段程式是整個專題的核心。
requests.get() 負責取得網頁,BeautifulSoup() 解析 HTML,而 select_one() 則利用 CSS Selector 找到需要的標籤。
例如,article.product_pod 代表每本書的商品區塊,.price_color 代表價格欄位。
評分原本是英文文字,例如 Four,程式會透過 rating_map 將它轉換成數字 4,方便之後使用 Pandas 計算平均值。
另外,程式使用 while 搭配 li.next a 自動尋找下一頁,不需要事先知道網站總共有多少頁。
三、使用 Pandas 整理資料
爬取完成後,先將 all_books 轉換成 DataFrame,再檢查資料是否完整。
df = pd.DataFrame(all_books)
print("原始資料筆數:", len(df))
print(df.head())
print("\n各欄位缺失值:")
print(df.isnull().sum())
接著清理資料,移除重複書籍,並確認價格和評分都是數字。
df["price"] = pd.to_numeric(
df["price"],
errors="coerce"
)
df["rating"] = pd.to_numeric(
df["rating"],
errors="coerce"
)
df = df.drop_duplicates(subset=["url"])
df = df.dropna(
subset=["title", "price", "rating"]
)
df = df[
(df["price"] >= 0) &
(df["rating"].between(1, 5))
].copy()
df = df.reset_index(drop=True)
print("清理後資料筆數:", len(df))
print(df.head())
這裡使用 drop_duplicates() 移除重複紀錄,再利用 dropna() 移除缺少必要資料的書籍。
由於價格和評分都需要進行數值計算,因此也使用 pd.to_numeric() 確保欄位的資料型態正確。
四、進行書籍資料分析
完成資料清理後,就可以分析書籍價格和評分。
print("書籍總數:", len(df))
print("平均價格:", round(df["price"].mean(), 2))
print("最高價格:", df["price"].max())
print("最低價格:", df["price"].min())
print("平均評分:", round(df["rating"].mean(), 2))
接著分析不同評分的書籍數量和平均價格。
rating_summary = df.groupby("rating").agg(
book_count=("title", "count"),
average_price=("price", "mean")
).reset_index()
rating_summary["average_price"] = (
rating_summary["average_price"].round(2)
)
print(rating_summary)
透過 groupby() 可以依照評分將書籍分組,再使用 agg() 同時計算每組的書籍數量與平均價格。
這些統計結果可以幫助我們了解目前爬取到的書籍資料分布,而不是只停留在取得原始資料的階段。
五、將書籍資料存進 SQLite
接著把清理後的資料存進 SQLite 資料庫,讓資料可以保留下來,並透過 SQL 查詢。
conn = sqlite3.connect("books_analysis.db")
df.to_sql(
"books",
conn,
if_exists="replace",
index=False
)
print("書籍資料已存入 SQLite。")
這裡使用 to_sql() 將 DataFrame 寫入資料庫。
books 是資料表名稱,而 if_exists="replace" 代表如果資料表已存在,就先取代原本的資料表,再寫入目前的資料。
接著可以使用 SQL 查詢平均價格和書籍數量。
sql_query = """
SELECT
COUNT(*) AS book_count,
ROUND(AVG(price), 2) AS average_price,
MAX(price) AS highest_price,
MIN(price) AS lowest_price
FROM books;
"""
result = pd.read_sql_query(sql_query, conn)
print(result)
也可以查詢各評分的書籍數量。
sql_query = """
SELECT
rating,
COUNT(*) AS book_count,
ROUND(AVG(price), 2) AS average_price
FROM books
GROUP BY rating
ORDER BY rating;
"""
sql_result = pd.read_sql_query(
sql_query,
conn
)
print(sql_result)
這樣就把 Python 資料分析與 SQL 查詢結合起來。Pandas 適合進行資料處理和分析,而 SQLite 則可以用來保存與查詢資料。
六、使用 Matplotlib 製作分析圖表
完成資料分析後,最後使用 Matplotlib 將結果視覺化。
先製作不同評分的書籍數量長條圖。
rating_counts = df["rating"].value_counts().sort_index()
plt.figure(figsize=(8, 5))
bars = plt.bar(
rating_counts.index,
rating_counts.values,
color="steelblue"
)
plt.bar_label(bars)
plt.title("Number of Books by Rating")
plt.xlabel("Rating")
plt.ylabel("Number of Books")
plt.xticks([1, 2, 3, 4, 5])
plt.tight_layout()
plt.savefig(
"rating_counts.png",
dpi=150,
bbox_inches="tight"
)
plt.show()
接著製作不同評分的平均價格圖。
avg_price = df.groupby("rating")["price"].mean()
plt.figure(figsize=(8, 5))
bars = plt.bar(
avg_price.index,
avg_price.values,
color="darkorange"
)
plt.bar_label(bars, fmt="%.2f")
plt.title("Average Book Price by Rating")
plt.xlabel("Rating")
plt.ylabel("Average Price")
plt.xticks([1, 2, 3, 4, 5])
plt.tight_layout()
plt.savefig(
"average_price.png",
dpi=150,
bbox_inches="tight"
)
plt.show()
透過這兩張圖,可以比較不同評分的書籍數量與平均價格,讓分析結果更容易理解。
要注意的是,這次只分析爬取到的書籍樣本,不能直接將結果推論到所有書籍市場,也不能只憑這些數據判定價格會影響評分。
七、匯出分析結果
最後將清理後的資料和統計結果儲存成 CSV,方便後續查看或製作報告。
df.to_csv(
"cleaned_books.csv",
index=False,
encoding="utf-8-sig"
)
rating_summary.to_csv(
"rating_summary.csv",
index=False,
encoding="utf-8-sig"
)
print("CSV 檔案已完成匯出。")
如果想將檔案下載到電腦,可以在 Google Colab 執行:
from google.colab import files
files.download("cleaned_books.csv")
其他檔案也可以用相同的方式下載,只要修改檔名即可。
如果想下載 SQLite 資料庫,可以先關閉連線,再執行下載:
conn.close()
files.download("books_analysis.db")
注意:Google Colab 的一般執行環境不是永久儲存空間,工作階段結束後,檔案可能會消失,因此重要的資料庫和圖表要記得下載保存。
八、今天的實作整理
今天完成了一個小型的書籍資料分析系統,將之前學過的技術整合起來。
使用 Requests 取得網頁內容。
使用 BeautifulSoup 解析書名、價格、評分和庫存。
自動切換頁面,累積多頁書籍資料。
使用 Pandas 清理資料並進行統計分析。
使用 SQLite 儲存資料,並透過 SQL 查詢統計結果。
使用 Matplotlib 製作資料視覺化圖表。
將清理後的資料、統計結果和資料庫匯出保存。
這次的重點是理解各個工具之間的分工。爬蟲負責取得資料,Pandas 負責整理和分析,SQLite 負責儲存資料,而 Matplotlib 則負責呈現分析結果。
今日心得
今天把前面學過的內容整合成一個完整的練習專題,從取得網站資料開始,到清理資料、存進資料庫,再製作統計圖表。實際串接時,我發現每個步驟都會影響後面的結果,例如價格如果沒有先轉換成數字,就無法正確計算平均值。
透過這次實作,我對爬蟲與資料分析的整體流程更熟悉了,也發現一個完整的資料分析專案不只是寫出爬蟲程式,還需要考慮資料品質、儲存方式和最後的呈現結果。
明天就是 30 天學習計畫的最後一天,我會整理這段時間學到的技術、完成的實作,以及這次專題的成果和未來可以改進的地方,為這次鐵人賽做一個完整的收尾。