我有一个由外部程序填充的sqlite数据库。我试图用python读取数据。当我尝试读取数据时,出现以下错误:
操作错误:无法解码为UTF-8
如果我在sqlite管理器中打开数据库并使用内置的浏览和搜索查看有问题的记录中的数据,它看起来很好,但是如果我将表导出为csv,我会注意到该字符在违规中记录已成为£
如果我在python中读取csv,违规记录中的£仍然被读为£,但这不是问题,我可以手动解析它。但是我需要能够直接从数据库中读取数据,而无需转换为csv的中间步骤。
我已经在线查看了类似问题的一些答案,我到目前为止尝试设置“text_factory = str”,我也尝试使用sqlite manager将列的数据类型从TEXT更改为BLOB,但仍然得到错误。
下面的代码会导致OperationalError:无法解码为UTF-8
conn = sqlite3.connect('test.db')
conn.text_factory = str
curr = conn.cursor()
curr.execute('''SELECT xml_dump FROM hands_1 LIMIT 5000 , 5001''')
row = curr.fetchone()
数据库中5000以上的所有记录都存在此字符问题,因此会产生错误。
任何帮助表示感谢。
答案 0 :(得分:14)
Python试图通过将文本片段(在数据库中存储为字节)转换为python str
对象来提供帮助。为了进行这种转换,python必须猜测查询返回的每个字节(或字节组)所代表的字母。默认猜测是一个名为utf-8的编码。显然,这种猜测在你的情况下是错误的。
解决方法是给python一些关于如何从字节到字母(即unicode字符)进行映射的提示。你已经接近了这条线
conn.text_factory = str
但是(基于您在上面评论中的回答),由于您使用的是python 3,str
是默认文本工厂,因此该行不会为您做任何新的事情(见the docs)。
这一行幕后发生的事情是python尝试使用str
函数转换查询返回的字节,有点像:
your_string = str(the_bytes, 'utf-8') # actually uses `conn.text_factory`, not `str`
...但你需要一个不同的编码,其中&ut; -8'是。由于您无法更改str
函数的默认编码,因此您必须以其他方式模仿它。您可以使用名为 lambda 的一次性无名函数:
conn.text_factory = lambda x: str(x, 'latin1')
现在当数据库将字节传递给python时,python将尝试使用' latin1'将它们映射到字母。方案而不是'utf-8'方案。当然,我不知道latin1是否是您数据的正确编码。实际上,你必须尝试一些编码来找到合适的编码。我会首先尝试以下方法:
'iso-8859-1'
'utf-16'
'utf-32'
'latin1'
您可以找到更完整的列表here。
另一种选择是简单地让来自数据库的字节保持为字节。这对您来说是否好主意取决于您的应用。您可以通过设置:
来完成conn.text_factory = bytes
答案 1 :(得分:0)
如果数据库中的文本实际上大部分都是用UTF-8编码的,但是您仍然看到此错误(无法解码为UTF-8),则问题可能是一个或多个行的伪造数据无效的UTF-8。默认情况下,Python的decode()
函数在看到这样的文本时会引发异常。如果您处于这种情况下,并且只想忽略这些错误,则可以像这样设置text_factory
:
conn = sqlite3.connect('my-database.db')
conn.text_factory = lambda b: b.decode(errors = 'ignore')