今天的重點是:
理解 HTML 中的超連結與 href 屬性。
使用 BeautifulSoup 找出網頁的 Next 按鈕。
使用 while 迴圈自動切換頁面。
將相對網址轉換成完整網址。
加入錯誤處理,並整合所有頁面的資料。
將完整資料儲存成 CSV。
一、認識網站的下一頁連結
在 Books to Scrape 的書籍列表頁面底部,可以看到分頁功能。
當目前頁面不是最後一頁時,網頁會提供 Next 按鈕,讓使用者前往下一頁。
例如:
第一頁可以前往第二頁。
第二頁可以前往第三頁。
第三頁可以前往第四頁。
當到達最後一頁時,就不會再有 Next 按鈕。
這個特性可以用來設計自動翻頁的爬蟲。
我們不需要事先知道網站有多少頁,只要每次抓取目前頁面的資料,再檢查是否有下一頁即可。
二、實作一:理解 HTML 的超連結
在 HTML 中,超連結通常使用 a 標籤,而網址會放在 href 屬性裡。
例如:
next
這段 HTML 表示有一個連結,點擊後會前往 catalogue/page-2.html。
在爬蟲中,我們可以使用 BeautifulSoup 找到這個連結,再透過 href 取得網址。
先建立一個簡單的 HTML 範例:
from bs4 import BeautifulSoup
html = """
soup = BeautifulSoup(html, "html.parser")
next_link = soup.select_one("li.next a")
print(next_link)
print(next_link["href"])
這裡使用 select_one("li.next a") 找出具有 next class 的 li 標籤裡面的 a 標籤。
接著使用 next_link["href"] 取得超連結的網址。
這就是自動翻頁最重要的基礎:從 HTML 中取得下一頁的網址,而不是自己手動組合頁碼。
三、實作二:使用 urljoin() 處理相對網址
剛剛取得的 href 可能不是完整網址,而是相對網址。
例如:
page-2.html
這個網址本身並沒有包含網域名稱,因此不能直接當成完整網址使用。
Python 提供了 urljoin(),可以將目前頁面的網址和相對網址合併,轉換成完整網址。
from urllib.parse import urljoin
current_url = "https://books.toscrape.com/catalogue/page-1.html"
next_href = "page-2.html"
next_url = urljoin(current_url, next_href)
print(next_url)
輸出結果:
https://books.toscrape.com/catalogue/page-2.html
urljoin() 會根據目前頁面的網址,正確處理相對路徑。
這個方法非常適合用在自動翻頁的爬蟲,因為不同網站的下一頁連結可能使用不同的網址格式。
四、實作三:取得第一頁的下一頁網址
接下來,使用 Requests 取得 Books to Scrape 第一頁的 HTML,再使用 BeautifulSoup 找出 Next 按鈕。
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
current_url = "https://books.toscrape.com/"
response = requests.get(current_url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
next_link = soup.select_one("li.next a")
if next_link:
next_href = next_link["href"]
next_url = urljoin(current_url, next_href)
print("下一頁網址:", next_url)
else:
print("目前頁面沒有下一頁")
這段程式碼會先取得第一頁的 HTML,再尋找 li.next a。
如果找到 Next 按鈕,就透過 href 取得下一頁的連結,並使用 urljoin() 轉換成完整網址。
這裡使用 if next_link 判斷是否存在下一頁。
如果找不到 Next 按鈕,就代表目前頁面沒有下一頁,程式便會顯示相應的訊息。
五、實作四:使用 while 迴圈自動翻頁
前面已經學會如何取得下一頁的網址,現在就可以把這個功能放進 while 迴圈。
與 for 迴圈不同,while 迴圈可以根據條件決定是否繼續執行。
這次的邏輯是:
從第一頁開始。
抓取目前頁面的 HTML。
找出目前頁面中的書籍資料。
尋找 Next 按鈕。
如果有下一頁,就更新網址並繼續執行。
如果沒有下一頁,就結束迴圈。
先用簡單的程式碼觀察整個流程。
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
current_url = "https://books.toscrape.com/"
while current_url:
print("目前抓取:", current_url)
response = requests.get(current_url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
next_link = soup.select_one("li.next a")
if next_link:
next_href = next_link["href"]
current_url = urljoin(current_url, next_href)
else:
current_url = None
print("所有頁面處理完成")
這裡最重要的是 current_url。
只要 current_url 不是 None,while 迴圈就會繼續執行。
當程式找不到下一頁時,就將 current_url 設定為 None,讓迴圈結束。
這樣就能自動從第一頁一路前往最後一頁,不需要事先設定總頁數。
六、實作五:完整爬取所有頁面的書籍資料
接下來,將前面學過的資料擷取方法整合進 while 迴圈,建立完整的自動翻頁爬蟲。
這次會抓取每一頁的書名、價格、庫存狀態和評分,並將資料整合成一個 List。
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin
import time
current_url = "https://books.toscrape.com/"
books_data = []
rating_map = {
"One": 1,
"Two": 2,
"Three": 3,
"Four": 4,
"Five": 5
}
page_count = 0
visited_urls = set()
while current_url:
# 避免重複訪問同一個網址
if current_url in visited_urls:
print("發現重複網址,停止爬取")
break
visited_urls.add(current_url)
page_count += 1
print("正在抓取第", page_count, "頁")
try:
# 發送請求
response = requests.get(current_url, timeout=10)
response.raise_for_status()
# 解析 HTML
soup = BeautifulSoup(response.text, "html.parser")
# 找出目前頁面的所有書籍
books = soup.select("article.product_pod")
# 擷取每本書的資料
for book in books:
title = book.select_one("h3 a")["title"]
price_text = book.select_one(".price_color").text
price = float(price_text.replace("£", ""))
availability = book.select_one(
".availability"
).text.strip()
rating_text = book.select_one(
".star-rating"
)["class"][1]
rating = rating_map[rating_text]
book_info = {
"title": title,
"price": price,
"availability": availability,
"rating": rating,
"page": page_count
}
books_data.append(book_info)
print("本頁取得", len(books), "本書")
# 尋找下一頁
next_link = soup.select_one("li.next a")
if next_link:
next_href = next_link["href"]
current_url = urljoin(current_url, next_href)
else:
current_url = None
# 避免連續快速請求
time.sleep(1)
except requests.exceptions.RequestException as e:
print("請求失敗:", e)
break
print("爬取完成!")
print("總共抓取", page_count, "頁")
print("總資料筆數:", len(books_data))
程式碼重點說明
這段程式碼整合了今天學到的所有觀念。
只要還有下一頁的網址,就會繼續執行。
將已經抓取過的網址存進 Set,如果發現同一個網址再次出現,就停止爬取,避免無限迴圈。
不需要自己計算頁碼,只要讀取 Next 按鈕中的 href 就可以前往下一頁。
如果網路連線失敗或伺服器回傳錯誤狀態碼,程式會顯示錯誤訊息並停止爬取。
每次請求後暫停一秒,避免過於頻繁地向網站發送請求。實際爬取時仍應遵守網站的使用規範。
七、實作六:確認所有頁面的資料是否完整
完成自動翻頁後,接下來要確認資料是否成功抓取。
首先,查看總資料筆數。
print("總資料筆數:", len(books_data))
Books to Scrape 的書籍目錄有 1,000 本書,分布在 50 頁,每頁 20 本。
如果所有頁面都成功抓取,正常情況下應該會取得 1,000 筆書籍資料。
接著查看前 5 筆和最後 5 筆資料。
print("前 5 筆資料:")
for book in books_data[:5]:
print(book)
print("\n最後 5 筆資料:")
for book in books_data[-5:]:
print(book)
這樣可以檢查資料是否從第一頁一路累積到最後一頁。
統計每一頁的資料筆數
from collections import Counter
page_counts = Counter(
book["page"] for book in books_data
)
for page, count in sorted(page_counts.items()):
print(f"第 {page} 頁:{count} 本書")
這裡使用 Counter 統計每個頁碼出現的次數。
因為每本書都有記錄 page 欄位,所以可以直接統計每一頁取得多少筆資料。
這個方法也能幫助我們發現是否有頁面資料不足或抓取失敗的情況。
八、實作七:分析完整書籍資料
當所有頁面的資料都抓取完成後,就可以利用 Python 進行簡單的資料分析。
average_price = total_price / len(books_data)
print("平均價格:", round(average_price, 2))
這段程式碼會加總所有書籍的價格,再除以總筆數,得到平均價格。
print("價格最高的書籍:", most_expensive["title"])
print("價格:", most_expensive["price"])
透過 max() 找出價格最高的書籍,並顯示書名和價格。
print("五星書籍數量:", len(five_star_books))
這裡使用 List Comprehension 篩選出評分為五星的書籍。
average_rating = total_rating / len(books_data)
print("平均評分:", round(average_rating, 2))
這樣就能計算整個書籍資料集的平均評分。
透過完整的資料集,可以進行比單頁資料更全面的分析。
九、實作八:將所有資料儲存成 CSV
最後,將所有頁面的書籍資料寫入 CSV 檔案,方便後續使用 Pandas 進行資料分析。
import csv
with open(
"books_all_pages.csv",
"w",
newline="",
encoding="utf-8-sig"
) as file:
fieldnames = [
"title",
"price",
"availability",
"rating",
"page"
]
writer = csv.DictWriter(
file,
fieldnames=fieldnames
)
writer.writeheader()
writer.writerows(books_data)
print("CSV 檔案儲存完成")
這段程式碼會將 books_data 中的所有資料寫入 books_all_pages.csv。
接著在 Google Colab 中下載檔案:
from google.colab import files
files.download("books_all_pages.csv")
完成後,就能在電腦中取得完整的書籍資料集。
十、今天的爬蟲流程整理
設定初始網址,發送 HTTP 請求。
使用 BeautifulSoup 擷取書籍資料。
取得下一頁的 href,使用 urljoin() 組成完整網址。
有下一頁就繼續,沒有下一頁就停止。
將所有資料整合成 List,進行分析並輸出 CSV。