解决多语言网站文件名乱码问题:以 DART 网站为例

解决老旧服务器端多语言网站文件名乱码问题:以 DART 网站为例

引言

在用 Python 爬取多语言网站(如韩文、日文等)的内容时,文件名乱码是一个常见问题。近日,我在爬取韩国 DART(Data Analysis, Retrieval and Transfer System)网站(https://dart.fss.or.kr)的文件(PDF 和 ZIP)时,遇到了文件名乱码问题。服务器返回的 Content-Disposition 头中的文件名显示为 [LIG³Ø½º¿ø]...,而预期为 [LIG넥스원]...。本文将分析乱码原因,分享解决思路,并总结通过代码获取网站内容时需要前期手动获取的关键信息,帮助开发者在处理多语言文件名时少走弯路。

问题描述

DART 网站提供公司披露文件的下载接口,包括 PDF(通过 pdf.do)和 ZIP(通过 zip.do)。我的目标是从 listzip_zip.txt 文件读取下载链接,将文件保存到本地 ./files 目录,文件名需添加 rcp_no_ 前缀,并正确显示韩文。

初始代码逻辑如下:

  1. 使用 requests.Session 发送 GET 请求,获取文件。
  2. Content-Disposition 头提取文件名。
  3. 保存文件,保留原始文件名。

代码片段(简化版):

import requests
import re

url = 'https://dart.fss.or.kr/pdf/download/zip.do?rcp_no=20250429800466&dcm_no=10620925'
response = requests.get(url)
content_disposition = response.headers.get('content-disposition')
if content_disposition:
    match = re.search(r'filename="([^"]+)"', content_disposition)
    if match:
        filename = match.group(1)
        print(f"Raw filename: {
     
     filename}")
else:
    filename = "default.zip"

运行结果

  • 日志显示文件名乱码:
    Raw filename: [LIG³Ø½º¿ø]±â¾÷¼³¸íȸ(IR)°³ÃÖ(¾È³»°ø½Ã)(2025.04.29).zip
    
  • 预期文件名:
    [LIG넥스원]기업설명회(IR)개최(안내공시)(2025.04.29).zip
    
  • 浏览器 InPrivate 模式下载的文件名显示正确,表明服务器返回的编码可能非标准。

问题分析

1. 服务器编码非标准

Content-Disposition 头的 filename 参数包含乱码,表明服务器未遵循 HTTP 标准(RFC 5987)。标准建议:

  • 使用 filename* 参数以 UTF-8 编码,例如:
    Content-Disposition: attachment; filename*=UTF-8''%5BLIG%EB%84%A5%EC%8A%A4%EC%9B%90%5D...
    
  • 或确保 filename 参数的编码与客户端期望一致(通常为 UTF-8)。

DART 服务器的行为

  • 使用 filename 参数,未使用 filename*
  • 韩文字符(如 )的 UTF-8 字节序列(EB 84 A5)被错误地作为 Latin-1(ISO-8859-1)发送,导致乱码(如 ³Ø)。
  • 例如:
    • (UTF-8: EB 84 A5)在 Latin-1 中被解析为 ³Ø½(对应字节 EB 84 A5)。
  • 这表明服务器未正确处理多语言字符,可能将 UTF-8 字符串直接作为 Latin-1 写入头。

2. 浏览器与代码的差异

  • 浏览器:Edge 等浏览器通过启发式解码(heuristic decoding)尝试多种编码(如 UTF-8、CP949),正确显示文件名。
  • 代码:Python 的 requests 库直接接收 Content-Disposition 的原始字节,需手动解码,否则显示乱码。

3. 编码模式推断

通过调试,我提取了 Raw filename 的字节序列:

raw_filename = "[LIG³Ø½º¿ø]..."
print(raw_filename.encode('latin1'))
# 输出: b'[LIG\xeb\x84\xa5\xec\x8a\xa4\xec\x9b\x90]...'
  • 字节序列 EB 84 A5 EC 8A A4 EC 9B 90 符合 UTF-8 编码,对应韩文 넥스원
  • 尝试解码:
    print(raw_filename.encode('latin1').decode('utf-8'))
    # 输出: [LIG넥스원]...
    
  • 确认服务器将 UTF-8 字节序列误作为 Latin-1 发送。

4. 非标准编码的普遍性

这种乱码问题在多语言网站中常见,尤其在:

  • 历史遗留系统,未针对国际化(i18n)优化。
  • 使用区域编码(如韩文的 CP949)而非 UTF-8。
  • 未遵循 RFC 5987,未使用 filename*

解决思路

1. 多编码解码逻辑

  • 方案:针对 filename 实现多编码解码,优先尝试 latin1 -> utf-8,后备 latin1 -> cp949 和 RFC 2047 解码。
  • 代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值