iT邦幫忙

2026 iThome 鐵人賽

DAY 3
0
自我挑戰組

Python 爬蟲與資料分析實戰:從網路資料到資訊視覺化系列 第 12 篇

Day 12|Python 爬蟲實戰:自動偵測下一頁,完整抓取網站資料

  • 分享至 

  • xImage
  •  

今天的重點是:

理解 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))
程式碼重點說明

這段程式碼整合了今天學到的所有觀念。

  1. 使用 while current_url 控制翻頁

只要還有下一頁的網址,就會繼續執行。

  1. 使用 visited_urls 避免重複訪問

將已經抓取過的網址存進 Set,如果發現同一個網址再次出現,就停止爬取,避免無限迴圈。

  1. 使用 urljoin() 取得下一頁的完整網址

不需要自己計算頁碼,只要讀取 Next 按鈕中的 href 就可以前往下一頁。

  1. 使用 try...except 處理請求錯誤

如果網路連線失敗或伺服器回傳錯誤狀態碼,程式會顯示錯誤訊息並停止爬取。

  1. 使用 time.sleep(1) 控制請求間隔

每次請求後暫停一秒,避免過於頻繁地向網站發送請求。實際爬取時仍應遵守網站的使用規範。

七、實作六:確認所有頁面的資料是否完整

完成自動翻頁後,接下來要確認資料是否成功抓取。

首先,查看總資料筆數。

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 進行簡單的資料分析。

  1. 計算所有書籍的平均價格
    total_price = sum(
    book["price"] for book in books_data
    )

average_price = total_price / len(books_data)

print("平均價格:", round(average_price, 2))

這段程式碼會加總所有書籍的價格,再除以總筆數,得到平均價格。

  1. 找出價格最高的書籍
    most_expensive = max(
    books_data,
    key=lambda book: book["price"]
    )

print("價格最高的書籍:", most_expensive["title"])
print("價格:", most_expensive["price"])

透過 max() 找出價格最高的書籍,並顯示書名和價格。

  1. 篩選五星評分的書籍
    five_star_books = [
    book for book in books_data
    if book["rating"] == 5
    ]

print("五星書籍數量:", len(five_star_books))

這裡使用 List Comprehension 篩選出評分為五星的書籍。

  1. 計算平均評分
    total_rating = sum(
    book["rating"] for book in books_data
    )

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")

完成後,就能在電腦中取得完整的書籍資料集。

十、今天的爬蟲流程整理

  1. 從第一頁開始

設定初始網址,發送 HTTP 請求。

  1. 解析目前頁面

使用 BeautifulSoup 擷取書籍資料。

  1. 尋找 Next 按鈕

取得下一頁的 href,使用 urljoin() 組成完整網址。

  1. 判斷是否還有下一頁

有下一頁就繼續,沒有下一頁就停止。

  1. 整理與儲存

將所有資料整合成 List,進行分析並輸出 CSV。


上一篇
Day 11|Python 爬蟲實戰:突破單頁限制,使用 Requests 與 BeautifulSoup 爬取多頁資料
下一篇
Day 13|Python 爬蟲實戰:爬蟲錯誤處理與資料驗證,讓爬取結果更可靠
系列文
Python 爬蟲與資料分析實戰:從網路資料到資訊視覺化 共 13 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言