用 Python 标准库追加 URL 查询参数:保留重复键和片段

举报
yd_210400787 发表于 2026/11/07 10:44:56 2026/11/07
【摘要】 用 Python 标准库 urllib.parse 为已有 URL 追加查询参数,保留重复键、空值与片段;示例演示 urlencode(doseq=True) 并说明签名 URL 等使用边界。

调用搜索接口时,一个参数有时会出现多次,比如 tag=python&tag=cloud。如果直接把 ?tag=... 拼到已有 URL 后面,原地址可能已经有查询参数,也可能带有 #section 片段;手工拼接容易把参数放错位置,或漏掉空值与编码。

下面用 Python 标准库 urllib.parse 做一个小函数:保留原查询参数的顺序、重复键和空值,再追加新参数,同时保留 URL 片段。

完整示例

保存为 url_query.py:

"""Append query parameters while keeping existing repeated keys and fragments."""

from __future__ import annotations

from urllib.parse import parse_qsl, urlencode, urlsplit, urlunsplit


def append_query(url: str, params: dict[str, str | list[str]]) -> str:
    parts = urlsplit(url)
    existing = parse_qsl(parts.query, keep_blank_values=True)
    query = "&".join(
        piece
        for piece in (urlencode(existing), urlencode(params, doseq=True))
        if piece
    )
    return urlunsplit(parts._replace(query=query))


if __name__ == "__main__":
    source = "https://example.com/search?tag=old&empty=#section"
    result = append_query(source, {"tag": ["python", "cloud"], "q": "a b"})
    print(result)
    print(parse_qsl(urlsplit(result).query, keep_blank_values=True))

运行结果:

https://example.com/search?tag=old&empty=&tag=python&tag=cloud&q=a+b#section
[('tag', 'old'), ('empty', ''), ('tag', 'python'), ('tag', 'cloud'), ('q', 'a b')]

输出中的 tag 出现三次:原地址的一次和新加入的两次。empty= 没丢,#section 仍在末尾。q 的空格编码为 +,这是 urlencode() 默认采用的表单式查询编码;再用 parse_qsl() 读取时会还原为空格。

关键步骤

先拆分 URL。 urlsplit() 把路径、查询串和片段分开,避免把新参数接到 #section 后面。片段只在浏览器等客户端内部使用,不属于发给服务器的查询参数。

保留原查询参数。 parse_qsl(..., keep_blank_values=True) 返回有序的键值对列表,所以重复键与空值都能留下。如果改用 parse_qs() 再随意转成普通字典,就需要额外处理多值列表和顺序。

展开新参数。 urlencode(params, doseq=True) 会把 {"tag": ["python", "cloud"]} 编成 tag=python&tag=cloud。省略 doseq=True 时,列表会被当成一个值编码,通常不是接口所需的重复键格式。普通字符串仍作为单个值处理。

最后把已有参数与新增参数的编码结果用 & 连接,并用 urlunsplit() 重组 URL。代码在任一部分为空时不会插入多余的 &。

使用边界

此函数追加参数;如果接口要求“替换同名参数”,应先从 existing 中删去该键,再编码新值。原查询串会经过解析和重新编码,因而 %20 可能变为 +,虽然一般查询解析结果相同,但不适合必须逐字保留原始查询串的签名 URL。对已签名的 URL 追加或重排参数也可能让签名失效,应按该接口的签名规则重新签名。

示例只处理字符串和字符串列表。若要传入数字、布尔值或 None,先明确接口要求的文本格式,再转换为字符串;不要让 None 意外变成字面量 None。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。