Contents ...
udn網路城邦
python爬蟲範例程式(一)
2025/10/17 12:02
瀏覽48
迴響0
推薦0
引用0
import requests                     # 用來發送 HTTP 請求,取得網頁內容

from bs4 import BeautifulSoup        # 用來解析 HTML 網頁

import csv                           # 用來寫入 CSV 檔案

import time                          # 用來控制爬蟲速度(例如 sleep)


def crawl_ptt_baseball(pages=3):

    """

    爬取 PTT 棒球版(Baseball 版)的文章列表資料


    參數:

        pages (int): 要爬取的頁數(預設為 3 頁)


    回傳:

        all_articles (list): 包含每篇文章標題、作者、日期、連結等資料的列表

    """


    base_url = "https://www.ptt.cc/bbs/Baseball/index.html"  # PTT 棒球版首頁

    all_articles = []  # 用來儲存所有爬取的文章資料


    headers = {

        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"  # 模擬瀏覽器,避免被擋

    }


    current_page_url = base_url  # 目前爬取的頁面 URL,初始為最新頁面


    # 開始逐頁爬取

    for page_num in range(pages):

        try:

            # 向當前頁面發送 HTTP GET 請求

            res = requests.get(current_page_url, headers=headers, timeout=10)

            res.raise_for_status()  # 若回應狀態非 200,則觸發例外

            soup = BeautifulSoup(res.text, "html.parser")  # 解析 HTML 內容


            # 抓取該頁所有文章的外層區塊

            articles = soup.select("div.r-ent")

            if not articles:

                print(f"第{page_num+1}頁沒找到文章")

                break


            # 逐篇處理每一篇文章

            for art in articles:

                try:

                    # 文章標題(若文章被刪除則顯示提示文字)

                    title_tag = art.select_one("div.title a")

                    title = title_tag.text.strip() if title_tag else "[本文已被刪除]"


                    # 文章連結(若存在才加入)

                    link = "https://www.ptt.cc" + title_tag['href'] if title_tag else ""


                    # 作者名稱

                    author = art.select_one("div.author").text.strip()


                    # 發文日期

                    date = art.select_one("div.date").text.strip()


                    # 將每篇文章資料整理成字典格式

                    all_articles.append({

                        "標題": title,

                        "作者": author,

                        "日期": date,

                        "連結": link,

                        "頁碼": page_num + 1

                    })

                except Exception as e:

                    print(f"文章抓取錯誤: {e}")  # 若單篇解析失敗,不影響整頁爬取


            print(f"第{page_num+1}頁爬取成功,共抓取 {len(articles)} 篇文章")


            # 找到「上頁」按鈕的連結,準備往前一頁繼續爬

            prev_link_tag = soup.select_one("a.wide:-soup-contains('上頁')")

            if prev_link_tag and "href" in prev_link_tag.attrs:

                current_page_url = "https://www.ptt.cc" + prev_link_tag['href']

            else:

                # 若找不到上一頁,代表已到最舊頁,停止爬取

                break


            time.sleep(1)  # 延遲 1 秒,避免爬太快被封鎖


        except Exception as e:

            print(f"第{page_num+1}頁錯誤: {e}")

            break  # 若整頁請求錯誤,則中止爬蟲


    # 將所有資料寫入 CSV 檔案

    with open("ptt_baseball_articles.csv", "w", newline="", encoding="utf-8-sig") as f:

        writer = csv.DictWriter(f, fieldnames=["標題", "作者", "日期", "連結", "頁碼"])

        writer.writeheader()        # 寫入標題列

        writer.writerows(all_articles)  # 寫入每一筆文章資料


    print(f"資料已儲存到 ptt_baseball_articles.csv,共 {len(all_articles)} 篇文章")


    return all_articles  # 回傳全部資料



# 主程式執行區

if __name__ == "__main__":

    crawl_ptt_baseball(pages=5)  # 例:爬取最新的 5 頁

限會員,要發表迴響,請先登入