WeHelp
學習各式各樣的內建函式、類別、物件、模組等等工具,完成各種 Python 基礎應用。
  1. 字串的操作
  2. 列表的操作
  3. 字典的操作
  4. 數學、統計模組
  5. 文字檔案讀取、寫入
  6. CSV 檔案讀取、寫入
  7. JSON 檔案讀取、寫入
  8. ZIP 壓縮檔案和解壓縮
  9. HTTP 網路連線請求
  10. 網頁爬蟲程式
  11. 日期與時間
  12. 正規表達式
網頁爬蟲程式
## 一、網頁爬蟲的基本概念 網頁爬蟲(Web Crawler / Web Scraper)是一種自動化程式,通常依照以下流程取得網頁資料: 1. **發送 HTTP 請求**:向指定網址要求網頁內容。 2. **接收 HTML**:伺服器回傳網頁原始碼。 3. **解析 HTML**:找出需要的元素,例如標題、作者、日期或超連結。 4. **整理資料**:將資料顯示、儲存成文字、CSV 或資料庫。 5. **控制請求頻率**:避免過度頻繁存取網站,造成伺服器負擔。 本例中: - `urllib.request`:Python 內建模組,用來發送 HTTP 請求與取得網頁內容。 - `BeautifulSoup`:第三方 HTML 解析工具,用來從 HTML 中搜尋指定標籤與資料。 --- ## 二、安裝 BeautifulSoup `urllib.request` 已經包含在 Python 標準函式庫中,不需另外安裝;BeautifulSoup 則需安裝: ```bash pip install beautifulsoup4 ``` 程式中通常使用以下方式匯入: ```python from urllib.request import Request, urlopen from bs4 import BeautifulSoup ``` --- ## 三、PTT 棒球版網頁結構 PTT 棒球版網址為: ```text https://www.ptt.cc/bbs/baseball/index.html ``` 文章列表大致使用以下 HTML 結構: ```html <div class="r-ent"> <div class="title"> <a href="/bbs/baseball/M.1234567890.A.123.html"> 文章標題 </a> </div> </div> ``` 因此可以: - 先選取所有 `div.r-ent` - 再從每個項目中找出 `div.title a` - 取得超連結中的文字作為文章標題 --- ## 四、使用 `urllib.request` 與 BeautifulSoup 爬取標題 ```python from urllib.request import Request, urlopen from bs4 import BeautifulSoup url = "https://www.ptt.cc/bbs/baseball/index.html" # 建立 HTTP 請求 request = Request( url, headers={ "User-Agent": "Mozilla/5.0", # PTT 部分頁面需要此 Cookie 表示已同意瀏覽十八禁內容 "Cookie": "over18=1" } ) try: # 取得網頁內容 with urlopen(request, timeout=10) as response: html = response.read() # PTT 使用 UTF-8 編碼 soup = BeautifulSoup(html, "html.parser") # 找出所有文章項目 articles = soup.select("div.r-ent") for article in articles: title_tag = article.select_one("div.title a") # 被刪除的文章可能沒有 a 標籤,因此要先判斷 if title_tag: title = title_tag.get_text(strip=True) link = title_tag.get("href") print("標題:", title) print("網址:", "https://www.ptt.cc" + link) print("-" * 50) except Exception as error: print("讀取網頁時發生錯誤:", error) ``` ### 程式說明 #### 1. 建立請求 ```python request = Request( url, headers={ "User-Agent": "Mozilla/5.0", "Cookie": "over18=1" } ) ``` `User-Agent` 用來告訴伺服器目前的用戶端類型。有些網站若沒有設定 `User-Agent`,可能會拒絕請求。 PTT 某些版面會要求使用者確認十八歲以上,透過: ```text Cookie: over18=1 ``` 可以模擬已完成確認的瀏覽器。 #### 2. 取得 HTML ```python with urlopen(request, timeout=10) as response: html = response.read() ``` `urlopen()` 會向網址發送請求,`read()` 則讀取伺服器回傳的 HTML 原始資料。 #### 3. 建立 BeautifulSoup 物件 ```python soup = BeautifulSoup(html, "html.parser") ``` 這會將 HTML 轉換成可搜尋的結構,之後可以使用 CSS Selector 或其他方法尋找元素。 #### 4. 找出文章標題 ```python articles = soup.select("div.r-ent") ``` 表示找出所有類別為 `r-ent` 的 `div` 元素。 接著: ```python title_tag = article.select_one("div.title a") ``` 在每一篇文章中尋找標題超連結。 ```python title = title_tag.get_text(strip=True) ``` 取得標籤中的文字,並移除前後空白。 --- ## 五、只列印標題的簡化版本 如果只需要標題,可以寫得更簡潔: ```python from urllib.request import Request, urlopen from bs4 import BeautifulSoup url = "https://www.ptt.cc/bbs/baseball/index.html" request = Request( url, headers={ "User-Agent": "Mozilla/5.0", "Cookie": "over18=1" } ) with urlopen(request) as response: soup = BeautifulSoup(response.read(), "html.parser") for title_tag in soup.select("div.r-ent div.title a"): print(title_tag.get_text(strip=True)) ``` 這裡的: ```python soup.select("div.r-ent div.title a") ``` 表示尋找位於: ```text div.r-ent └── div.title └── a ``` 中的所有超連結。 --- ## 六、處理編碼問題 PTT 頁面通常使用 UTF-8。如果要明確指定編碼,可以使用: ```python html = response.read().decode("utf-8", errors="ignore") soup = BeautifulSoup(html, "html.parser") ``` 完整範例如下: ```python with urlopen(request, timeout=10) as response: html = response.read().decode("utf-8", errors="ignore") soup = BeautifulSoup(html, "html.parser") ``` `errors="ignore"` 可以避免少數無法解碼的字元使程式中斷,但也可能忽略部分異常字元。 --- ## 七、取得下一頁資料 PTT 頁面通常會有「‹ 上頁」連結,可以找出上一頁網址: ```python prev_link = soup.select_one("div.btn-group-paging a.btn.wide") if prev_link: previous_url = "https://www.ptt.cc" + prev_link["href"] print(previous_url) ``` 例如,將解析功能包裝成函式: ```python from urllib.request import Request, urlopen from bs4 import BeautifulSoup BASE_URL = "https://www.ptt.cc" def get_page(url): request = Request( url, headers={ "User-Agent": "Mozilla/5.0", "Cookie": "over18=1" } ) with urlopen(request, timeout=10) as response: html = response.read() return BeautifulSoup(html, "html.parser") url = "https://www.ptt.cc/bbs/baseball/index.html" soup = get_page(url) for article in soup.select("div.r-ent"): title_tag = article.select_one("div.title a") if title_tag: print(title_tag.get_text(strip=True)) # 取得上一頁連結 previous = soup.select_one("div.btn-group-paging a.btn.wide") if previous: print("上一頁:", BASE_URL + previous["href"]) ``` --- ## 八、使用爬蟲時的注意事項 1. **不要過於頻繁發送請求**,可以在請求之間加入延遲: ```python import time time.sleep(2) ``` 2. **遵守網站規範與服務條款**,不要大量下載或造成網站負擔。 3. **妥善處理錯誤**,例如網路中斷、網址不存在或伺服器拒絕請求。 4. **尊重個人資料與著作權**,爬取的資料不應任意散布或用於不當用途。 5. **網站 HTML 結構可能改變**,因此 CSS Selector 可能需要隨網站結構調整。 總結來說,`urllib.request` 負責「取得網頁」,而 BeautifulSoup 負責「解析網頁」。兩者搭配後,就能從 PTT 棒球版的 HTML 中找出文章標題及其連結。
相關學習地圖、教學課程
Python 資料工程
從 0 開始,成為資料工程師的學習路徑。
Python 後端工程、資料庫
從 0 開始,成為後端工程師的學習路徑。