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)一个规范页面地址
你的练习清单
- 用 urlparse 拆分 URL,而不是手工切字符串。
- 去重前用 urljoin 补全相对链接。
- 把 parse_qs 的返回值当作列表处理。
- 用户输入和重复查询键用 urlencode 编码。
- 比较页面 URL 前去掉片段。
常见问题
urljoin 会验证目的地吗?
不会。它只做语法上的补全。仍然需要检查协议、主机和抓取规则。
为什么 parse_qs 返回列表?
查询字符串可能包含重复键,只保留一个值会丢失信息。
应该把整个 URL 转成小写吗?
不应该。主机名不区分大小写,但路径和查询值可能区分。只规范化你了解规则的部分。
练习 URL 解析
12 道题,覆盖 urlparse、urljoin、查询字符串、编码和片段。
继续阅读: