Python解析西里尔字母编码URL遇LocationParseError求助
问题解决:IDN域名解析LocationParseError错误
问题原因
你遇到的LocationParseError是因为目标网站返回的重定向Location头是URL编码后的西里尔域名(如%d0%ba%d1%83%d0%bf...),而requests内置的URL解析器无法直接将这种编码字符串解析为合法域名——它既不是标准的punycode格式,也不符合域名标签长度限制(每个标签最多63字符)。首次运行正常可能是因为网站返回的重定向路径不同(比如缓存机制),后续请求触发了异常路径。
修复后的代码
通过禁用自动重定向、手动处理重定向流程,先解码URL编码的域名再转换为punycode,可以解决该问题:
import requests from urllib.parse import urlparse, unquote, urljoin import idna def fix_location_parse_error(url): max_redirects = 5 current_url = url redirect_count = 0 while redirect_count < max_redirects: try: # 禁用自动重定向,手动处理每一步 response = requests.get(current_url, timeout=120, allow_redirects=False) status_code = response.status_code if status_code in (301, 302, 303, 307, 308): location = response.headers.get('Location') if not location: print(f"URL: {current_url}\n无重定向Location头\n状态码: {status_code}") return # 解码URL编码的Location值 decoded_location = unquote(location) parsed_loc = urlparse(decoded_location) if parsed_loc.hostname: # 将西里尔域名转换为punycode格式 try: puny_hostname = idna.encode(parsed_loc.hostname).decode('utf-8') new_loc = parsed_loc._replace(netloc=puny_hostname).geturl() except idna.IDNAError: new_loc = decoded_location else: # 处理相对路径重定向 new_loc = urljoin(current_url, decoded_location) redirect_count += 1 current_url = new_loc print(f"重定向至: {current_url}") elif status_code == 200: final_url = current_url print(f"原始URL: {url}\n最终URL: {final_url}\n状态码: {status_code}") return else: print(f"URL状态码异常 {status_code}: {url}") return except requests.exceptions.RequestException as e: print(f"URL: {current_url}\n错误信息: {e}\n状态: 异常") return print(f"URL: {url}\n重定向次数超限(>{max_redirects})\n状态: 异常") url = 'http://xn-----7kctapfjvlndvhiafp8oxc.xn--p1ai' fix_location_parse_error(url)
关键修复点
- 禁用
requests自动重定向,避免内置解析器处理异常Location头 - 使用
unquote解码URL编码的域名,还原为原始西里尔字符串 - 用
idna库将西里尔域名转换为符合标准的punycode格式,确保解析合法 - 限制重定向次数,防止死循环
推荐替代库
- idna:专门处理国际化域名(IDN)的转换,是解决此类问题的核心依赖
- yarl:现代URL解析库,对IDN、特殊字符的支持更健壮,示例:
from yarl import URL url = URL('http://xn-----7kctapfjvlndvhiafp8oxc.xn--p1ai') print(url.host) # 自动转换为西里尔域名或保留punycode - httpx:
requests的替代HTTP库,内置更完善的URL解析和重定向处理逻辑,可直接替换requests使用
内容的提问来源于stack exchange,提问作者Jawaher
相关产品推荐
相关产品推荐

