前言
在爬虫、接口对接工作中,url编码与解码是绕不开的基础操作。相比于编码,解码更容易踩坑,尤其是双重url编码,很多人看到一串满是%25的字符串,直接一次unquote就结束,最后拿到的还是编码后的json字符串,接口解析直接报错。本文使用python内置urllib.parse,不需要任何第三方库,带你彻底搞懂url解码。
一、url解码基础概念
url编码是把特殊字符转成%加十六进制;url解码就是反向操作,把%xx还原为原始字符。
常见编码映射对照(解码时就是反向转换)
%22→"%7b→{%7d→}%3a→:%2c→,%25→%这是双重编码最关键的字符
python内置模块urllib.parse.unquote负责url解码。
配套还有unquote_plus,和unquote有区别:unquote_plus会把+还原成空格,适用于form表单的查询串;普通url路径、参数解析优先使用unquote。
单层解码基础示例:
from urllib.parse import unquote
# 单层编码后的字符串
encoded_str = "%7b%22articleid%22%3a%2289c46c77f90e61ff7df01e3cc18eae9349f619f697ca4366e94fad724d913ee6%22%2c%22columnid%22%3a%22268f86fdf61ac8614f09db38a2d0295253043b03e092c7ff48ab94290296125c%22%7d"
raw = unquote(encoded_str)
print(raw)
# 输出:{"articleid":"89c46c77f90e61ff7df01e3cc18eae9349f619f697ca4366e94fad724d913ee6","columnid":"268f86fdf61ac8614f09db38a2d0295253043b03e092c7ff48ab94290296125c"}
二、双重url解码(爬虫高频场景)
当字符串里面大量出现%25,说明是双重url编码。
原理回顾:
- 原始json:
{"articleid":"xxx"} - 第一次quote →
%7bxxx%7d - 第二次quote,把
%编码成%25→%257b%2522articleid%2522...
解码顺序必须反过来:先unquote一次,再unquote第二次。只解码一次,拿到的还是第一层编码后的字符串,无法直接json.loads。
实战案例
我们拿到接口参数:params=%257b%2522articleid%2522%3a%252289c46c77f90e61ff7df01e3cc18eae9349f619f697ca4366e94fad724d913ee6%2522%2c%2522columnid%2522%3a%2522268f86fdf61ac8614f09db38a2d0295253043b03e092c7ff48ab94290296125c%2522%257d
完整解码代码:
from urllib.parse import unquote
import json
full_param = "params=%257b%2522articleid%2522%3a%252289c46c77f90e61ff7df01e3cc18eae9349f619f697ca4366e94fad724d913ee6%2522%2c%2522columnid%2522%3a%2522268f86fdf61ac8614f09db38a2d0295253043b03e092c7ff48ab94290296125c%2522%257d"
# 截取 params= 后面的值
encode_value = full_param.split("params=")[1]
# 双重解码
decode_step1 = unquote(encode_value)
decode_step2 = unquote(decode_step1)
# 转为字典
data = json.loads(decode_step2)
print(data)
执行过程拆解:
- 第一次unquote:
%257b→%7b,得到单层编码串 - 第二次unquote:
%7b→{,得到原始json字符串 - json.loads 加载成python字典
三、直接解析完整url中的查询参数
日常开发,我们经常拿到完整url,需要直接解析query参数,parse_qs内部自带解码,不用手动unquote。
from urllib.parse import urlparse, parse_qs
url = '[https://www.chinaisa.org.cn/gxportal/xfgl/portal/content.html?articleid=89c46c77f90e61ff7df01e3cc18eae9349f619f697ca4366e94fad724d913ee6&columnid=268f86fdf61ac8614f09db38a2d0295253043b03e092c7ff48ab94290296125c](https://www.chinaisa.org.cn/gxportal/xfgl/portal/content.html?articleid=89c46c77f90e61ff7df01e3cc18eae9349f619f697ca4366e94fad724d913ee6&columnid=268f86fdf61ac8614f09db38a2d0295253043b03e092c7ff48ab94290296125c)'
parsed = urlparse(url)
query = parse_qs(parsed.query)
# parse_qs 返回value是列表
res = {k:v[0] for k, v in query.items()}
print(res)
注意:parse_qs 会自动做url解码,不要再次手动unquote,否则会重复解码引发bug。
四、unquote 和 unquote_plus 的区别(重点踩坑点)
unquote:标准url解码,空格还原成%20→ 空格。适合url路径、参数。unquote_plus:表单application/x-www-form-urlencoded专用,+会被转成空格。
示例对比:
from urllib.parse import unquote, unquote_plus s = "hello%20world+test" print(unquote(s)) # hello world+test print(unquote_plus(s)) # hello world test
错误混用会导致
+号被误转空格,参数直接错乱。
五、常见解码踩坑清单
坑1:双重编码只解码一次
现象:解码后的字符串还包含大量%,json.loads直接抛出jsondecodeerror。
判断依据:字符串包含%25,几乎就是双重编码,需要两次unquote。
坑2:对 parse_qs 的结果再次unquote
parse_qs内部已经自动完成解码,再次unquote会二次解码,遇到%25这类字符会产生脏数据。
坑3:中文解码编码不匹配
unquote默认encoding='utf-8',如果是gbk编码的老网站,会抛出unicodedecodeerror。
解决方案:指定编码 unquote(s, encoding="gbk")
# gbk编码解码示例 from urllib.parse import unquote s = "%d6%d0%ce%c4" print(unquote(s, encoding="gbk"))
坑4:不合法的%编码串
原始字符串截断,出现%3这种不完整的编码,默认会抛异常。可以设置errors='replace'忽略错误。
unquote(s, errors='replace')
六、封装通用函数:自动处理单层/双重解码
写一个简易工具函数,判断是否包含%25,自动选择解码次数,方便项目直接复用:
from urllib.parse import unquote
import json
def auto_double_decode(s: str):
"""自动判断单层/双重url解码,返回原始字符串"""
if "%25" in s:
s = unquote(unquote(s))
else:
s = unquote(s)
return s
# 测试
encoded = "%257b%2522articleid%2522%3a%252289c46c77f90e61ff7df01e3cc18eae9349f619f697ca4366e94fad724d913ee6%2522%2c%2522columnid%2522%3a%2522268f86fdf61ac8614f09db38a2d0295253043b03e092c7ff48ab94290296125c%2522%257d"
raw_json = auto_double_decode(encoded)
data = json.loads(raw_json)
print(data)
提示:这个简易函数仅适用于爬虫常见场景,极端多层编码(3层及以上)不适用。
七、什么时候会遇到双重编码需要解码
- 老java政务、国企网站,网关、nginx多层转发,每层自动解码
- 前端js编码后,浏览器发起请求再次自动编码
- 接口返回的参数是经过两层编码的json字符串,放在url query里面传递
八、小结
url解码核心是urllib.parse.unquote,单层解码是基础;%25是识别双重url编码最直观的标记,遇到它就要连续两次解码。
开发中还要区分unquote和unquote_plus,不要在parse_qs解析完成后重复解码。遇到中文乱码记得切换gbk编码。
编码和解码成对学习,在爬虫对接老旧门户、复杂网关转发接口时,能解决一大半参数解析失败的问题。
以上就是python的单层与双重url解码实战与踩坑指南的详细内容,更多关于python单层与双重url解码的资料请关注代码网其它相关文章!
发表评论