Python中如何从带查询参数的复杂图片URL提取文件类型?
嘿,我懂你的问题啦——带?查询参数的URL确实会让你原来的方法失效!原因很简单:你的代码是直接检查整个URL字符串的结尾是否匹配图片扩展名,但这类URL里真正的扩展名在?符号之前就结束了,后面跟着的一堆参数会让URL的结尾变成参数内容(比如你例子里的URL结尾是q_80),自然匹配不上预设的扩展名列表。
问题出在哪?
你原来的splitext_函数会遍历扩展名列表,检查URL是否以某个扩展名结尾。但对带查询参数的URL来说,https://xxx.jpg?xxx的结尾是参数的最后一段,不是.jpg,所以所有endswith(ext)的条件都不满足,只能返回splitext(path)的结果。而splitext会把从最后一个.到URL结尾的所有内容(包括?和参数)都当成扩展名,这显然不是你想要的。
解决方案:先剥离查询参数,再提取扩展名
我们只需要先把URL中?及其后面的查询参数部分去掉,只保留真实的文件路径部分,再用你原来的逻辑处理就好。这里推荐两种方法:
方法1:用字符串分割快速处理
如果你的URL格式比较规整,直接按?分割取第一部分就行:
from os.path import splitext image_extensions = ['ai','bmp','gif','ico','jpeg','jpg','png','ps','psd','svg','tif','tiff','webp'] def splitext_(path, extensions): # 先转小写,兼容扩展名大写的情况 path_lower = path.lower() for ext in extensions: if path_lower.endswith(ext): return path[:-len(ext)], path[-len(ext):] return splitext(path) val = "https://dkstatics-public.digikala.com/digikala-products/9f4cb4e049e7a5d48c7bc22257b5031ee9a5eae8_1602179467.jpg?x-oss-process=image/resize,m_lfit,h_300,w_300/quality,q_80" # 第一步:剥离查询参数 if '?' in val: clean_path = val.split('?')[0] else: clean_path = val # 第二步:提取扩展名 ex_filename, ext = splitext_(clean_path, image_extensions) ex_extension = ext.lstrip('.').lower() # 用lstrip更稳妥,避免多个点的情况 print(ex_extension) # 输出:jpg
方法2:用标准库urllib.parse规范解析URL
如果需要处理更复杂的URL(比如带锚点#、或者没有查询参数的情况),用Python自带的urlsplit会更规范:
from os.path import splitext from urllib.parse import urlsplit image_extensions = ['ai','bmp','gif','ico','jpeg','jpg','png','ps','psd','svg','tif','tiff','webp'] def splitext_(path, extensions): path_lower = path.lower() for ext in extensions: if path_lower.endswith(ext): return path[:-len(ext)], path[-len(ext):] return splitext(path) val = "https://dkstatics-public.digikala.com/digikala-products/9f4cb4e049e7a5d48c7bc22257b5031ee9a5eae8_1602179467.jpg?x-oss-process=image/resize,m_lfit,h_300,w_300/quality,q_80" # 解析URL,提取不带查询参数的路径部分 parsed_url = urlsplit(val) clean_path = parsed_url.path # 提取扩展名 ex_filename, ext = splitext_(clean_path, image_extensions) ex_extension = ext.lstrip('.').lower() print(ex_extension) # 输出:jpg
额外优化点
我还给你的splitext_函数加了个小优化:先把路径转成小写再检查扩展名,这样不管URL里的扩展名是大写(比如.JPG)还是小写,都能正确匹配到。另外用lstrip('.')代替replace(".", "", 1),能更稳妥地处理扩展名前面有多个点的极端情况(比如file..jpg)。
测试一下你提供的另一个URL:
val = "https://www.needmode.com/wp-content/uploads/2023/04/%D9%84%D9%88%D8%A7%D8%B2%D9%85-%D8%AA%D8%AD%D8%B1%DB%8C%D8%B1.webp" parsed_url = urlsplit(val) clean_path = parsed_url.path ex_filename, ext = splitext_(clean_path, image_extensions) ex_extension = ext.lstrip('.').lower() print(ex_extension) # 输出:webp
完全可以正常工作啦!
备注:内容来源于stack exchange,提问作者Martin

