Python2.7生成UTF-8 XML时遇UnicodeDecodeError问题求助
解决Python 2中UTF-8 XML生成的UnicodeDecodeError问题
嘿,我一看这个错误就知道你在Python 2里踩了Unicode和字节串混淆的坑——这在处理UTF-8编码的XML时太常见了!让我帮你理清楚问题出在哪,然后一步步修复它:
问题根源
你现在的代码里犯了一个典型的Python 2字符串处理错误:混合使用Unicode字符串(带u前缀的类型)和字节串(str类型)。
你对很多字符串做了.encode('UTF-8'),把Unicode转成了字节串,然后又用str()包装(在Python 2里str就是字节串)。但拼接时你又把这些字节串和u'<programme...'这类Unicode字符串混在一起,Python 2会自动尝试把字节串按ASCII编码解码成Unicode,而你的字节串里包含非ASCII字符(比如错误里的0xc2,对应输出里的Â),这就触发了UnicodeDecodeError。
修复方案
核心原则:在Python 2中,所有文本处理全程用Unicode字符串,直到最后写入文件时再编码为UTF-8字节串。
1. 先写一个通用的XML转义函数
你重复写了很多转义逻辑,不如封装成函数,既简洁又不容易出错:
def escape_xml(s): # 确保输入是Unicode字符串,如果是字节串先解码(假设原始编码是UTF-8) if not isinstance(s, unicode): s = s.decode('utf-8') # 转义XML特殊字符 return s.replace('&', '&')\ .replace("'", ''')\ .replace('"', '"')\ .replace('<', '<')\ .replace('>', '>')
2. 修正主代码逻辑
去掉所有不必要的.encode('UTF-8'),统一用Unicode处理文本:
# 处理时间:直接用字符串拼接,不需要encode starttime = datetime.strptime(' '.join([str(now.year), e[4], e[0]]), '%Y %a %d %b %I:%M%p').strftime('%Y%m%d%H%M%S') endtime = datetime.strptime(' '.join([str(now.year), e[4], e[1]]), '%Y %a %d %b %I:%M%p').strftime('%Y%m%d%H%M%S') global epg_data # 用转义函数清理所有需要插入XML的内容,确保都是Unicode clean_channel = escape_xml(channel) clean_e2 = escape_xml(e[2]) clean_e3 = escape_xml(e[3]) div_list3 = escape_xml(div_list2) e5 = escape_xml(e[5]) # 拼接全部为Unicode的字符串,避免类型混合 epg_data = u''.join([ u'<programme start="', starttime, u' +0100" stop="', endtime, u' +0100" channel="', clean_channel, u'">\n', u'<title lang="eng">', e5, u'</title>\n<desc lang="eng">', clean_e2, u' ', clean_e3, u'</desc>\n<icon src="', div_list3, u'" />\n', u'<country>UK</country>\n</programme>' ]) # 写入文件时,再把Unicode编码为UTF-8字节串 with open('your_epg_file.xml', 'wb') as f: f.write(epg_data.encode('UTF-8'))
3. 关键改动说明
- 去掉了所有
.encode('UTF-8')调用,转义函数会自动处理字节串到Unicode的转换(如果你的原始数据是字节串的话)。 - 时间处理部分直接用普通字符串拼接,
datetime的方法不需要处理编码。 - 拼接
epg_data时所有部分都是Unicode类型,彻底避免了混合类型导致的自动解码错误。 - 写入文件时用
wb模式(二进制写入),确保编码后的UTF-8字节串被正确写入。
额外注意事项
如果你的原始数据(比如channel、e列表里的元素)本身是字节串,最好在处理前先统一解码为Unicode,比如:
channel = channel.decode('utf-8') e = [item.decode('utf-8') for item in e]
这样转义函数里的类型判断可以简化,但保留判断会让代码更健壮。
内容的提问来源于stack exchange,提问作者gdogg371
相关产品推荐
相关产品推荐

