URL 与编码
约 1178 字大约 4 分钟
2026-05-10
URL(Uniform Resource Locator)用于定位网络资源。调用 API、访问网页、下载文件时,最常见的入口就是 URL。
- URL 的组成
- 使用 urllib.parse
- query string
- urlencode
- 1拆 URL:urllib.parse.urlparse 把 scheme/host/port/path/query/fragment 五段分开。
- 2拼 query:urlencode({'q': 'python 入门', 'page': 1}) 自动百分号编码中文和空格。
- 3永远不要手拼带中文/特殊字符的 URL —— 给 requests 传 params= 字典最安全。
- 4多值参数(如 tag=python&tag=web)用 urlencode(..., doseq=True);parse_qs 永远返回 list。
- 5记住空格的两套编码:路径里是 %20,query 里 quote_plus 会编为 + —— 用对函数。
URL(Uniform Resource Locator)用于定位网络资源。调用 API、访问网页、下载文件时,最常见的入口就是 URL。
URL 的组成
一个 URL 例子:
https://api.example.com:443/users?page=1&size=20#top它由几部分组成:
| 部分 | 示例 | 说明 |
|---|---|---|
| scheme | https | 协议 |
| host | api.example.com | 主机名 |
| port | 443 | 端口 |
| path | /users | 路径 |
| query | page=1&size=20 | 查询参数 |
| fragment | top | 页面片段 |
使用 urllib.parse
Python 标准库 urllib.parse 可以解析和构造 URL。
from urllib.parse import urlparse
url = 'https://api.example.com/users?page=1&size=20#top'
result = urlparse(url)
print(result.scheme)
print(result.netloc)
print(result.path)
print(result.query)
print(result.fragment)query string
query string 是 URL 中 ? 后面的参数。
from urllib.parse import parse_qs
query = 'page=1&tag=python&tag=web'
print(parse_qs(query))
# {'page': ['1'], 'tag': ['python', 'web']}注意:同一个参数名可以出现多次,所以 parse_qs() 的值是列表。
urlencode
不要手动拼接 query 参数,应该使用 urlencode()。
from urllib.parse import urlencode
params = {
'keyword': 'Python 网络编程',
'page': 1,
}
query = urlencode(params)
print(query)输出中中文会被自动编码。
quote 与 unquote
from urllib.parse import quote, unquote
text = 'Python 网络编程'
encoded = quote(text)
print(encoded)
print(unquote(encoded))URL 中不能直接安全地放入所有字符,中文、空格、特殊符号通常需要 percent encoding。
常见坑
- 手动拼接 URL 时忘记编码中文和特殊字符。
- query 参数中有列表,却按普通字符串处理。
- 把 fragment 当成会发送给服务端的内容。实际上
#后面的 fragment 通常不会发送给服务端。 - 路径和 query 混淆。
- 空格可能编码成
+或%20,取决于场景。
requests 中的 params
使用 requests 时,推荐把 query 参数交给 params:
import requests
response = requests.get(
'https://api.example.com/search',
params={'keyword': 'Python 网络编程', 'page': 1},
)
print(response.url)这样可以避免手动拼接 URL 出错。
为什么不要手动拼 URL
初学者很容易这样写:
keyword = 'python 入门'
url = 'https://example.com/search?q=' + keyword
print(url)看起来没问题,但空格、中文、&、?、# 这些字符在 URL 里都有特殊含义。如果不编码,服务器可能理解错。
更好的做法是交给工具:
from urllib.parse import urlencode
params = {
'q': 'python 入门',
'page': 1,
}
query = urlencode(params)
url = 'https://example.com/search?' + query
print(url)输出里的中文和空格会被编码成适合 URL 的形式。
在 requests 里更简单:
import requests
response = requests.get(
'https://example.com/search',
params={'q': 'python 入门', 'page': 1},
)
print(response.url)URL 里的特殊字符
URL 不是普通字符串。下面这些字符经常需要特别注意:
| 字符 | 在 URL 中常见含义 |
|---|---|
? | query string 开始 |
& | 多个 query 参数之间的分隔符 |
= | 参数名和值之间的分隔符 |
# | fragment,通常不会发送给服务端 |
/ | 路径分隔符 |
| 空格 | 需要编码,常见为 %20 或 + |
例如搜索关键词是 a&b,如果不编码,服务端可能把它当成两个参数。
quote 和 urlencode 怎么选
- 只有一个字符串片段需要编码,用
quote。 - 要把字典变成 query string,用
urlencode。
from urllib.parse import quote, urlencode
print(quote('python 入门'))
print(urlencode({'q': 'python 入门', 'page': 1}))如果参数里有多个同名值,可以这样写:
from urllib.parse import urlencode
params = {
'tag': ['python', 'web'],
'page': 1,
}
print(urlencode(params, doseq=True))doseq=True 会把列表展开成多个同名参数。
parse_qs 的返回值为什么是列表
from urllib.parse import parse_qs
query = 'tag=python&tag=web&page=1'
print(parse_qs(query))结果类似:
{'tag': ['python', 'web'], 'page': ['1']}因为 URL 允许同一个参数名出现多次。即使 page 只有一个值,parse_qs 也会把它放进列表里。
这点在处理筛选条件、多选标签时很常见。
总结
URL 是网络资源的地址。写 Python 网络代码时,应使用 urllib.parse 或 HTTP 客户端提供的 params 参数处理 URL 和 query,不要手动拼接复杂 URL。
- URL 不是普通字符串,中文、空格、&、? 等字符都可能影响解析。
- query 参数优先用 requests 的 params 或 urllib.parse.urlencode,不要手动拼复杂字符串。
- 同名 query 参数可以出现多次,所以 parse_qs 的值通常是列表。
版权所有
版权归属:Shuo Liu
