Python 爬蟲練習:搭建禮貌的抓取流水線
爬蟲是一條流水線,不是一次請求。這些練習把抓取、解析、提取和儲存分開,讓每個階段都能在不存取真實網站的情況下測試。
從儲存的頁面開始
開發時下載一次,把 HTML 儲存下來,然後反覆解析這個樣本。這樣偵錯時不受網路波動影響,也方便測試缺失屬性、重複連結等邊界情況。
from html.parser import HTMLParser
class Links(HTMLParser):
def __init__(self):
super().__init__()
self.links = []
def handle_starttag(self, tag, attrs):
href = dict(attrs).get("href")
if tag == "a" and href:
self.links.append(href)
p = Links()
p.feed('<a href="/a">A</a><a href="/a">A</a><a href="/b">B</a>')
print(p.links)可以反覆執行的樣本
單獨構造請求
把請求構造放在一個函式裡。真正發送時設定描述清楚的 User-Agent 和超時。本站的瀏覽器執行器不會發送網路請求,所以這些範例只到 Request 物件為止。
from urllib.request import Request
request = Request(
"https://example.com/docs",
headers={"User-Agent": "LearningBot/1.0"},
)
print(request.full_url)
print(request.get_header("User-agent"))這個範例不聯網
按狀態碼分支
不要把 404 頁面當成目標頁面解析。用一個小函式把狀態判斷集中起來,重試策略也就有了唯一的位置。
def outcome(status):
if 200 <= status < 300:
return "parse"
if 300 <= status < 400:
return "follow redirect"
if status == 429:
return "back off"
return "stop"
print(outcome(200))
print(outcome(429))一個小的狀態策略
儲存緊湊的記錄
只提取任務需要的欄位,其餘內容留在原頁面。結構化結果可以用字典列表儲存,並按穩定鍵(例如絕對 URL)去重。寫入檔案或資料庫前,結果應當便於檢查。
rows = [
{"url": "/a", "title": "A"},
{"url": "/a", "title": "A"},
{"url": "/b", "title": "B"},
]
unique = list({row["url"]: row for row in rows}.values())
print(unique)每個 URL 一條記錄
抓取前先讀規則
robots.txt 只是起點,不是全部協議。閱讀站點條款,表明客戶端身份,限制請求頻率;沒有合法依據時不要收集個人資料。站點明確拒絕時就停止。
robots = "User-agent: *\nDisallow: /private\nCrawl-delay: 2"
rules = {}
for line in robots.splitlines():
if ":" in line:
key, value = line.split(":", 1)
rules[key.strip().lower()] = value.strip()
print(rules["disallow"])
print(rules["crawl-delay"])最小但必要的檢查
你的練習清單
- 儲存一份真實頁面,用樣本測試解析器。
- 構造請求時使用可識別的 User-Agent 和超時。
- 分別決定 2xx、3xx、4xx 和 5xx 回應的處理方式。
- 只儲存任務需要的欄位,並用穩定 URL 作為鍵。
- 擴大抓取前先閱讀 robots.txt 和站點條款。
常見問題
瀏覽器執行器能抓真實網站嗎?
不能。課程執行器用於本機 Python 範例,不會發送任意網路請求。真實抓取應在受控的 Python 環境執行。
應該用 requests 還是 urllib?
兩者都可以。urllib 屬於標準函式庫;requests 是常用的第三方封裝。解析和合規規則相同。
網站阻止我時怎麼辦?
停止。不要繞過登入、驗證碼、付費牆或存取控制。應尋找 API 或申請許可。
練習爬蟲流水線
12 道題,覆蓋請求、HTML 解析、去重和禮貌抓取限制。
繼續閱讀: