專項練習 · 8 分鐘閱讀

Python URL 解析練習:拼接、查詢與清理

很多重複連結並不是真的重複,而是同一個目的地的四種寫法。這些練習把 URL 字串拆成組成部分,基於頁面補全,再重建成規範值。

讀取每個組成部分

先給每個部分命名。scheme 表示協議,netloc 是主機和埠,path 是資源路徑,query 是參數,fragment 是頁內錨點。每個部分在抓取中承擔不同職責。

from urllib.parse import urlparse

url = urlparse("https://example.com:8080/docs?q=python#intro")
print(url.scheme)
print(url.netloc)
print(url.path)
print(url.query)
print(url.fragment)

給每個部分命名

基於頁面補全

連結相對於包含它的頁面。urljoin 能處理 ../、根相對路徑和只有查詢參數的引用。儲存前先補全,佇列才不會把一個目的地當成多個頁面。

from urllib.parse import urljoin

base = "https://example.com/docs/guide/page.html"
for href in ["../index.html", "/about", "?page=2"]:
    print(urljoin(base, href))

三種相對寫法

讀取重複的查詢鍵

parse_qs 回傳列表,即使鍵只出現一次。這是有意的:查詢字串可以重複鍵。只有 API 明確說明單值時,才取第一個值;數字在計算前要顯式轉換。

from urllib.parse import parse_qs

params = parse_qs("tag=python&tag=web&page=2")
print(params["tag"])
print(int(params["page"][0]) + 1)

先拿列表,再顯式轉換

編碼新的查詢字串

urlencode 會跳脫空格和保留字元。搜尋表單和分頁連結都應使用它。傳入鍵值對列表可以保留重複鍵和順序,普通字典無法保證這一點。

from urllib.parse import urlencode

query = urlencode([("q", "a b"), ("tag", "python"), ("tag", "web")])
print(query)

編碼鍵值對,保留重複

去重前去掉片段

# 後面的片段是給瀏覽器用的,不屬於伺服器請求。把頁面加入 visited 集合前先去掉它。如果需要記錄連結來源,可以另外保留原始 URL。

from urllib.parse import urlsplit, urlunsplit

parts = urlsplit("https://example.com/docs?q=1#section-2")
clean = urlunsplit((parts.scheme, parts.netloc, parts.path, parts.query, ""))
print(clean)

一個規範頁面位址

你的練習清單

常見問題

urljoin 會驗證目的地嗎?

不會。它只做語法上的補全。仍然需要檢查協議、主機和抓取規則。

為什麼 parse_qs 回傳列表?

查詢字串可能包含重複鍵,只保留一個值會丟失資訊。

應該把整個 URL 轉成小寫嗎?

不應該。主機名不區分大小寫,但路徑和查詢值可能區分。只規範化你了解規則的部分。

練習 URL 解析

12 道題,覆蓋 urlparse、urljoin、查詢字串、編碼和片段。

打開練習

繼續閱讀: