我使用Python 2.7.3和BeuatofulSoup从网站表中获取数据,然后使用codecs
将内容写入文件。我收集的变量之一,偶尔会出现乱码。例如,如果网站表看起来像这样
Year Name City State
2000 John D’Iberville MS
2001 Steve Arlington VA
因此,当我生成City
变量时,我始终将其编码为utf-8
:
Year = foo.text
Name = foo1.text
City = foo3.text.encode('utf-8').strip()
State = foo4.text
RowsData = ("{0},{1},{2},{3}").format(Year, Name, City, State)
这样我创建的逗号分隔字符串列表的内容名为RowData
和RowHeaders
,如下所示
RowHeaders = ['Year,Name,City,State']
RowsData = ['2000, John, D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville, MS',
'2001, Steve, Arlington, VA']
然后我尝试使用以下代码将其写入文件
file1 = codecs.open(Outfile.csv,"wb","utf8")
file1.write(RowHeaders + u'\n')
line = "\n".join(RowsData)
file1.write(line + u'\r\n')
file1.close()
我收到以下错误
Traceback (most recent call last):
File "HSRecruitsFBByPosition.py", line 141, in <module>
file1.write(line + u'\r\n')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 6879: ordinal not in range(128)
我可以在RowsData
上使用csv writer包,它可以正常工作。由于我不想进入的原因,我需要使用编解码器来输出csv文件。我无法弄清楚发生了什么。任何人都可以帮我解决这个问题吗?提前谢谢。
答案 0 :(得分:1)
codecs.open()
为您编码。不要将其编码数据,因为Python会再次尝试解码数据,这样它就可以将其编码为UTF-8。隐式解码使用ASCII编解码器,但由于编码字节字符串中包含非ASCII数据,因此失败:
>>> u'D’Iberville'.encode('utf8')
'D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville'
>>> u'D’Iberville'.encode('utf8').encode('utf8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 1: ordinal not in range(128)
解决方案是*不要手动编码:
Year = foo.text
Name = foo1.text
City = foo3.text.strip()
State = foo4.text
请注意,codecs.open()
不是文件流的最有效实现。在Python 2.7中,我使用io.open()
instead;它提供相同的功能,但实现更强大。 io
模块是Python 3的默认I / O实现,但在Python 2中也可用于向前兼容。
但是,您似乎正在重新发明CSV处理; Python有一个很好的csv
module,可以为你生成CSV文件。在Python 2中,它无法处理Unicode,因此您做需要手动编码:
import csv
# ...
year = foo.text
name = foo1.text
city = foo3.text.strip()
state = foo4.text
row = [year, name, city, state]
with open(Outfile.csv, "wb") as outf:
writer = csv.writer(outf)
writer.writerow(['Year', 'Name', 'City', 'State'])
writer.writerow([c.encode('utf8') for c in row])
最后但并非最不重要的是,如果您的HTML网页生成了文字D’Iberville
,那么您就会生成Mojibake;你把UTF-8误解为CP-1252的那个:
>>> u'D’Iberville'.encode('cp1252').decode('utf8')
u'D\u2019Iberville'
>>> print u'D’Iberville'.encode('cp1252').decode('utf8')
D’Iberville
这通常是绕过BeautifulSoup的编码检测(传入字节字符串,而不是Unicode)。
你可以尝试用以下方法“修复”这些:
try:
City = City.encode('cp1252').decode('utf8')
except UnicodeError:
# Not a value that could be de-mojibaked, so probably
# not a Mojibake in the first place.
pass
答案 1 :(得分:0)
这个'D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville'
是一个普通字符串,恰好有转义代表字符的位。
所以,要写出来,你需要先解码它。由于您没有进行解码,因此Python正在尝试使用ASCII并失败。
>>> s
'D\xc3\xa2\xe2\x82\xac\xe2\x84\xa2Iberville'
>>> type(s)
<type 'str'>
>>> type(s.decode('utf-8'))
<type 'unicode'>
>>> print(s.decode('utf-8'))
D’Iberville
以下是如何理解这一过程:
首先,要了解字符适用于人类,字节适用于计算机。计算机只是帮我们转换字符到字符,所以我们可以理解数据。
因此,只要您需要为计算机存储某些内容,您就需要将其从字符转换为字节,因为这是计算机所知道的。所有文件(甚至文本文件)都是字节。只要你打开它,就会将这个字节数据转换成字符,这样我们就可以理解它的内容了。在&#34;二进制&#34;的情况下文件(如图像或Word文档),这个过程有点不同。
如果我们正在撰写&#34;文字&#34;内容,我们需要获取字形(字符)并将它们转换为字节,以便可以写入文件。此过程称为解码。
当我们想要&#34;阅读&#34;一个文本文件,它将字节转换为我们需要编码位的字形(字符或字母) - 实际上,翻译它们。要知道什么字形对应于存储的位,我们使用查找表,这个表名(utf-8)就是你传入的内容。