Scrapy中如何让urljoin拼接URL时保留基础路径完整层级
问题根因
urllib.parse.urljoin 本身的设计逻辑是:base URL 末尾如果没有斜杠,最后一段路径会被识别为文件名,拼接时会直接替换该文件名;如果末尾带斜杠,最后一段会被识别为目录,扩展路径会拼接到目录下。你遇到的拼接不符合预期的问题就是这个逻辑导致的。
规范实现方案
不需要手动拆分拼接字符串,下面两种方案都是基于原生工具逻辑实现,比手动拼接的兼容性、稳定性更高,能覆盖绝对路径、相对跳转、带参数URL等各种边界场景:
方案1:统一补全base URL末尾斜杠
先对base URL做标准化处理,确保末尾带斜杠后再调用urljoin即可:
from urllib.parse import urljoin def custom_urljoin(base_url: str, extension: str) -> str: # 先移除末尾所有斜杠,再加一个,避免重复斜杠 processed_base = base_url.rstrip('/') + '/' return urljoin(processed_base, extension)
效果测试
# 单层路径场景 >>> custom_urljoin('https://url/part1', 'extension') 'https://url/part1/extension' # 多层路径场景 >>> custom_urljoin('https://url/part1/part2', 'extension') 'https://url/part1/part2/extension' # 扩展路径带相对跳转场景,手动拼接无法正确处理 >>> custom_urljoin('https://url/part1/part2', '../other') 'https://url/part1/other' # 扩展路径为绝对路径时,自动返回绝对路径符合通用URL规范 >>> custom_urljoin('https://url/part1', 'https://other-domain.com/path') 'https://other-domain.com/path'
方案2:给扩展路径加./前缀
如果不想封装函数,也可以直接在扩展路径前加./(表示当前目录),不需要修改base URL就能达到相同效果:
>>> urljoin('https://url/part1', './extension') 'https://url/part1/extension' >>> urljoin('https://url/part1/part2', './extension') 'https://url/part1/part2/extension'
Scrapy 场景适配
在Scrapy中使用response.urljoin时,直接套用上面两种方案即可:
# 方案1写法 processed_base = response.url.rstrip('/') + '/' full_url = urljoin(processed_base, extension) # 方案2更简洁的写法 full_url = response.urljoin(f'./{extension}')
内容的提问来源于stack exchange,提问作者watch-this
相关产品推荐
相关产品推荐

