import re
import requests
import pandas as pd
from bs4 import BeautifulSoup
from urllib.parse import urljoin
### 設定網址
base_url = "https://www.books.com.tw"
url = (
"https://www.books.com.tw/web/sys_saletopb/books/"
"?loc=P_menu_th_1_002"
)
headers = {
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/151.0.0.0 Safari/537.36"
),
"Accept": (
"text/html,application/xhtml+xml,application/xml;"
"q=0.9,image/avif,image/webp,*/*;q=0.8"
),
"Accept-Language": "zh-TW,zh;q=0.9,en;q=0.8"
}
### 發送 HTTP 請求
response = requests.get(
url,
headers=headers,
timeout=15
)
response.raise_for_status()
print("狀態碼:", response.status_code)
print("實際網址:", response.url)
print("HTML 長度:", len(response.text))
### 建立 BeautifulSoup
soup = BeautifulSoup(
response.text,
"lxml"
)
### 顯示網頁標題
page_title = soup.select_one("title")
if page_title:
print(
"網頁標題:",
page_title.get_text(" ", strip=True)
)
### 找到所有商品
book_items = soup.select(
".item"
) # 每個 .item 代表一項商品
print("找到的商品區塊數量:", len(book_items))
### 建立書籍資料串列
book_list = []
### 逐筆抓取書籍
for item in book_items:
item_text = item.get_text(
" ",
strip=True
) # 取得整個商品區塊的文字
### 從商品區塊文字找出排名
rank_match = re.search(
r"TOP\s*(\d+)",
item_text
)
if not rank_match:
continue # 不是排行榜商品就跳過
rank = int(rank_match.group(1))
### 抓取書名與商品網址
title_element = item.select_one(
"h4 a"
)
if not title_element:
continue
title = title_element.get_text(
" ",
strip=True
)
relative_url = title_element.get(
"href",
""
)
book_url = urljoin(
base_url,
relative_url
)
### 抓取作者
author = ""
author_text_node = item.find(
string=re.compile(r"作者[::]")
) # 尋找包含「作者:」的文字節點
if author_text_node:
author_box = author_text_node.parent
author_links = author_box.select("a")
if author_links:
author_list = []
for author_link in author_links:
author_name = author_link.get_text(
" ",
strip=True
)
if author_name:
author_list.append(author_name)
author = "、".join(author_list)
### 抓取價格原文
price_text = ""
price_text_node = item.find(
string=re.compile(r"優惠價")
) # 找到包含「優惠價」的文字節點
if price_text_node:
price_box = price_text_node.parent
price_text = price_box.get_text(
" ",
strip=True
)
### 從價格文字取出金額
price_match = re.search(
r"(\d[\d,]*)\s*元",
price_text
)
if price_match:
price = price_match.group(1).replace(
",",
""
)
price = int(price)
else:
price = None
### 從價格文字取出折扣
discount_match = re.search(
r"(\d+)\s*折",
price_text
)
if discount_match:
discount = discount_match.group(1) + "折"
else:
discount = ""
### 抓取封面圖片
image_element = item.select_one("img")
if image_element:
image_url = (
image_element.get("data-src")
or image_element.get("src")
or ""
)
image_url = urljoin(
base_url,
image_url
)
else:
image_url = ""
### 加入書籍資料
book_list.append({
"排名": rank,
"書名": title,
"作者": author,
"折扣": discount,
"優惠價": price,
"價格原文": price_text,
"商品網址": book_url,
"封面網址": image_url
})
### 依照排名排序
book_list.sort(
key=lambda book: book["排名"]
)
### 顯示書籍資料
print("\n博客來中文書暢銷榜:")
for book in book_list:
print()
print("排名:", book["排名"])
print("書名:", book["書名"])
print("作者:", book["作者"])
print("折扣:", book["折扣"])
print("優惠價:", book["優惠價"])
print("商品網址:", book["商品網址"])
### 轉換成 DataFrame
book_df = pd.DataFrame(book_list)
print("\n暢銷榜資料表:")
print(book_df)
### 有資料才儲存 CSV
if not book_df.empty:
book_df.to_csv(
"博客來中文書暢銷榜.csv",
index=False,
encoding="utf-8-sig"
)
print("\n資料抓取完成")
print("共抓到:", len(book_list), "本書")
print("已產生:博客來中文書暢銷榜.csv")
else:
print("\n沒有抓到書籍資料")
with open(
"博客來_回應內容.html",
"w",
encoding="utf-8"
) as file:
file.write(response.text)
print("已儲存:博客來_回應內容.html")