再次出现:UnicodeEncodeError:ascii编解码器无法编码

3
我有一个XML文件夹需要解析。我需要从这些文件的元素中获取文本信息。它们将被收集并打印到CSV文件中,其中元素列出在列中。
实际上,我现在对一些文件可以做到这一点。也就是说,对于许多我的XML文件,该过程正常进行,并且我得到我想要的输出。执行此操作的代码如下:
import os, re, csv, string, operator
import xml.etree.cElementTree as ET
import codecs
def parseEO(doc):
    #getting the basic structure
    tree = ET.ElementTree(file=doc)
    root = tree.getroot()
    agencycodes = []
    rins = []
    titles =[]
    elements = [agencycodes, rins, titles]
    #pulling in the text from the fields
    for elem in tree.iter():
        if elem.tag == "AGENCY_CODE":
            agencycodes.append(int(elem.text))
        elif elem.tag == "RIN":
            rins.append(elem.text)
        elif elem.tag == "TITLE":
            titles.append(elem.text)
    with open('parsetest.csv', 'w') as f:
        writer = csv.writer(f)
        writer.writerows(zip(*elements))


parseEO('EO_file.xml')     

然而,在某些版本的输入文件中,我会遇到臭名昭著的错误:
'ascii' codec can't encode character u'\x97' in position 32: ordinal not in range(128)

完整的回溯信息如下:
    ---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-15-28d095d44f02> in <module>()
----> 1 execfile(r'/parsingtest.py') # PYTHON-MODE

/Users/ian/Desktop/parsingtest.py in <module>()
     91         writer.writerows(zip(*elements))
     92 
---> 93 parseEO('/EO_file.xml')
     94 
     95 

/parsingtest.py in parseEO(doc)
     89     with open('parsetest.csv', 'w') as f:
     90         writer = csv.writer(f)
---> 91         writer.writerows(zip(*elements))
     92 
     93 parseEO('/EO_file.xml')
UnicodeEncodeError: 'ascii' codec can't encode character u'\x97' in position 32: ordinal not in range(128)

通过阅读其他帖子,我相当有信心认为问题在于使用的编解码器(并且,你知道,错误信息已经非常明显了)。然而,我读到的解决方法对没有帮助(强调一下,因为我理解我是问题的源头,而不是人们以前回答的方式)。

一些回答(例如:这个这个这个)没有直接涉及ElementTree,我不确定如何将解决方案转换为我正在做的事情。

其他处理ElementTree的解决方案(例如:这个这个)要么使用短字符串(这里的第一个链接),要么使用ElementTree中的.tostring/.fromstring方法,而我没有使用。(当然,也许我应该使用。)

我尝试过但没有成功的方法:

  1. I have attempted to bring in the file via UTF-8 encoding:

    infile = codecs.open('/EO_file.xml', encoding="utf-8")
    parseEO(infile)
    

    but I think the ElementTree process already understands it to be UTF-8 (which is noted in the first line of all the XML files I have), and so this is not only not correct, but is actually redundantly bad all over again.

  2. I attempted to declare an encoding process within the loop, replacing:

    tree = ET.ElementTree(file=doc)
    

    with

    parser = ET.XMLParser(encoding="utf-8")
    tree = ET.parse(doc, parser=parser)
    

    in the loop above that does work. This didn't work for me either. The same files that worked before still worked, the same files that created the error still created the error.

有许多其他的随意尝试,但我不想再强调这一点。
所以,虽然我认为我写的代码既低效又得罪了良好的编程风格,但它确实能够处理几个文件。 我正在努力理解是否只是缺少我不知道的参数,是否应该对文件进行预处理(我还没有确定哪个字符有问题,但我知道u'\x97翻译成某种控制字符),或者其他选项。
2个回答

10

您正在解析XML; XML API将为您提供unicode值。 然后,您尝试将Unicode数据直接写入CSV文件中,而不进行编码。 Python然后尝试为您编码,但失败了。 您可以在回溯中看到这一点,即.writerows()调用失败,并且错误告诉您编码失败,而不是解码(解析XML)。

您需要选择一种编码方式,然后在写入之前对数据进行编码:

for elem in tree.iter():
    if elem.tag == "AGENCY_CODE":
        agencycodes.append(int(elem.text))
    elif elem.tag == "RIN":
        rins.append(elem.text.encode('utf8'))
    elif elem.tag == "TITLE":
        titles.append(elem.text.encode('utf8'))

我使用了 UTF8 编码,因为它可以处理任何 Unicode 码点,但你需要自己明确选择。


3

看起来你的xml文件中有unicode字符。Unicode与以utf8编码的字符串不同。

Python2.7的csv库不支持unicode字符,因此你需要在将数据导入csv文件之前通过一个函数对其进行编码。

def normalize(s):
    if type(s) == unicode: 
        return s.encode('utf8', 'ignore')
    else:
        return str(s)

所以你的代码应该像这样:

for elem in tree.iter():
    if elem.tag == "AGENCY_CODE":
        agencycodes.append(int(elem.text))
    elif elem.tag == "RIN":
        rins.append(normalize(elem.text))
    elif elem.tag == "TITLE":
        titles.append(normalize(elem.text))

非常感谢。Martijn的建议是我尝试的第一个,解决了我的直接问题。这似乎是我可以从中学习的东西,为下一轮做好准备。非常感谢您抽出时间发帖。 - Savage Henry
我不幸地花费了许多时间来调试Unicode错误。直到最近我才理解了其中的奥秘。很高兴能够帮忙! - eblahm
不要使用 type(s) == unicode;而应该使用 isinstance(s, unicode) - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接