【问题标题】:Python MySQLdb upload UnicodeEncodeErrorPython MySQLdb上传UnicodeEncodeError
【发布时间】:2015-08-29 19:08:04
【问题描述】:

我有一个问题,我可以将 CSV 文件上传到 MySQL,但随后发生了一些事情,我收到了编码错误。有人可以检查我的代码并告诉我有什么问题吗?我是新来的。

下面的 sn-p 是我如何编写将要上传的 CSV 文件,使用 MDN 工具(mdb-export)从 MDB 文件中提取数据:

    tableIndex  = 1
    for tName in tableNames:
        fileName = os.path.join(csvPath, os.path.basename(mdb).split('.')[0] + '_' + tName + '.csv')

        try:
            p = subprocess.Popen(["mdb-export", "-H", mdb, tName], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            tableContent, error = p.communicate()

            if(p.returncode != 0):
                _logger.error('[%3d] Export Subprocess %d %s' % (tID, p.returncode, tableContent))
                SendMdbError(tID, mdb, _logger, 'ALERT: Export Subprocess')
                return(['', False])
            if(error):
                _logger.error('[%3d] Export Communicate %d %s' % (tID, p.returncode, error.strip()))
                SendMdbError(tID, mdb, _logger, 'ALERT: Export Communicate')
                return(['', False])

        except Exception as ex:
            _logger.exception('[%3d] Export Error' % tID)
            SendMdbError(tID, mdb, _logger, 'ALERT: Export Exception')
            return(['', False])
        except:
            _logger.exception('[%3d] Export Unexpected' % tID)
            SendMdbError(tID, mdb, _logger, 'ALERT: Export Unexpected')
            return(['', False])

        # If no data, no need for corresponding SQL
        if(len(tableContent) == 0):
            emptyTables.append(tName)

        # If data exists, dump data
        else:
            # Add the 'DriveTest' to the data to upload
            tableContent = tableContent.split('\n')

            tableContent = [dt + ',' + line for line in tableContent if(line)]
            tableContent = '\n'.join(tableContent)

            try:
                with open(fileName, 'wb') as f:
                    f.write(tableContent)

                    if(_VERBOSITY):
                        _logger.debug('[%3d] %3d - Write CSV SIZE[%8d] FILE: %s' %(tID, tableIndex, len(tableContent.split('\n')), fileName))
                        tableIndex += 1

            except IOError as err:
                _logger.exception('[%3d] Write IOError: %s' % (tID, str(err)))
                SendMdbError(tID, mdb, _logger, 'ALERT: Write IOError')
                return(['', False])
            except Exception as ex:
                _logger.exception('[%3d] Write Exception' % tID)
                SendMdbError(tID, mdb, _logger, 'ALERT: Write Exception')
                return(['', False])
            except:
                _logger.exception('[%3d] Write Unexpected: %s' % tID)
                SendMdbError(tID, mdb, _logger, 'ALERT: Write Unexpected')
                return(['', False])

下面是我上传 CSV 文件的地方,这里是我得到错误的地方:

    # Upload the data
    tableIndex = 0
    for table in tableDDL:
        try:

            with warnings.catch_warnings(record=True) as war:

                _logger.info('[%3d] %3d Going up... %s' %(tID, tableIndex+1, os.path.basename(mdb).split('.')[0] + '_' + table))

                _sqlLock[tableIndex].acquire()
                #self.cursor.execute(tableDDL[table])
                self.cursor.execute(tableULD[table])
                self.conn.commit()
                _sqlLock[tableIndex].release()

                if(war):
                    #if(_VERBOSITY): print('[%3d] %3d WARNINGS[%3d] %s' % (tID, tableIndex+1, len(war), os.path.basename(mdb).split('.')[0] + '_' + table))
                    _logger.warning('[%3d] %3d WARNINGS[%3d] %s' % (tID, tableIndex+1, len(war), os.path.basename(mdb).split('.')[0] + '_' + table))
                    for w in war:
                        _logger.warning('[%3d] %s' % (tID, w.message))

                #if(_VERBOSITY): print('[%3d] %3d Uploaded %s' % (tID, tableIndex+1, os.path.basename(mdb).split('.')[0] + '_' + table))
                _logger.info('[%3d] %3d Uploaded %s' % (tID, tableIndex+1, os.path.basename(mdb).split('.')[0] + '_' + table))
                tableIndex += 1

                # Remove the uploaded CSV file
                try:
                    os.remove(csvFiles[table]+'.csv')
                    _logger.info('[%3d] Removed CVS file: %s' % (tID, csvFiles[table]+'.csv'))
                except OSError:
                    pass

        except (MySQLdb.InternalError, MySQLdb.NotSupportedError) as err:
            _logger.error('[%3d] %3d Internal: %s %s' % (tID, tableIndex+1, err, sys.exc_info()[0]))
            self.conn.rollback()
            self.Disconnect(tID, _logger, _VERBOSITY, _DEBUG)
            return(False)
        except MySQLdb.OperationalError as err:
            _logger.error('[%3d] %3d OperationalError: %s' % (tID, tableIndex+1, sys.exc_info()[0]))
            _logger.error(err)
            self.conn.rollback()
            self.Disconnect(tID, _logger, _VERBOSITY, _DEBUG)
            return(False)
        except MySQLdb.ProgrammingError as err:
            _logger.error('[%3d] %3d ProgrammingError: %s' % (tID, tableIndex+1, sys.exc_info()[0]))
            _logger.error(err)
            self.conn.rollback()
            self.Disconnect(tID, _logger, _VERBOSITY, _DEBUG)
            return(False)
        except MySQLdb.Error as err:
            _logger.error('[%3d] %3d QUERY: %s %s' % (tID, tableIndex+1, err, sys.exc_info()[0]))
            self.conn.rollback()
            self.Disconnect(tID, _logger, _VERBOSITY, _DEBUG)
            return(False)
        except Exception as err:
            _logger.error('[%3d] %3d Exception: %s %s' % (tID, tableIndex+1, err, sys.exc_info()[0]))
            #self.conn.rollback()
            #self.Disconnect(tID, _logger, _VERBOSITY, _DEBUG)
            #return(False)
            pass
        except:
            _logger.error('[%3d] %3d Other: %s' % (tID, tableIndex+1, sys.exc_info()[0]))
            self.conn.rollback()
            self.Disconnect(tID, _logger, _VERBOSITY, _DEBUG)
            return(False)

我得到的错误如下:

2015-06-13 19:42:21,743 __main__ -    ERROR - [  1]   1 Exception: 'ascii' codec can't encode character u'\xb4' in position 40: ordinal not in range(128) <type 'exceptions.UnicodeEncodeError'>
2015-06-13 19:42:30,962 __main__ -    ERROR - [  1]   1 Exception: 'ascii' codec can't encode character u'\xb4' in position 27: ordinal not in range(128) <type 'exceptions.UnicodeEncodeError'>

我注意到给定的数据已上传,但不确定是否所有行都已上传。

谢谢!

【问题讨论】:

  • 几个问题:(1)tableULD 变量中有什么,它来自哪里? (2) 你能从那个异常中得到堆栈跟踪吗?
  • 话虽如此,既然您似乎使用的是python 3,请尝试使用open(fileName, 'w', encoding="utf-8")而不是open(fileName, 'wb')打开文件。毕竟你是在写文本,而不是二进制数据。

标签: python mysql csv unicode utf-8


【解决方案1】:

在将 csv 放入 DB s.decode('UTF-8') 之前尝试并在将其从 DB s.encode('UTF-8') 中取出之后尝试

我是为 SQLite 做的,它工作正常。

【讨论】:

  • Ivan:按照你的建议做了:我从 MDB 'tableContent = tableContent.encode('UTF-8').split('\n')' 获取它后进行了编码。然后在上传之前解码'f.write(tableContent.decode('UTF-8'))'得到错误:'tableContent = tableContent.encode('UTF-8').split('\ n')UnicodeDecodeError:'ascii'编解码器无法解码位置 237 中的字节 0xaf:序数不在范围内(128)'
  • 好的。在放入数据库之前,我对 HTML 表单文本输入进行了解码。但是,如果您只有一个文件,请先尝试 s.encode("UTF-8") 。如果这不起作用,请尝试 s.encode("UTF-8").decode.("UTF-8")。和 s.encode('UTF-8') 之后。
  • 我添加了代码以查明数据导致问题的位置。事实证明,非 ascii 数据正在上传到 MySQL 中的 BLOB 字段,这引发了异常。处理需要存储的非 ascii 数据的最佳实践是什么?应该将 BLOB 更改为 BINARY 吗?
  • 嗯,这不是数据的错,而是 Python 是如何理解它的。如您所见,无论它是何种编码/解码方式,MySQL 都接受它,但 Python 以后无法消化它。我现在记得我没有在解码后立即尝试编码。解码后的数据操作起来不太方便。
  • 以下是一些有问题的非 ascii 数据示例:"^@^@^@^[ªmK»""±^C^P^@ÿ® ^F§^^Êì^R^A^P”和“^@^@T¯Qé{Ö”
【解决方案2】:

让它发挥作用应该不会太难,但你必须了解你在做什么。不要只尝试s.encode("UTF-8").decode("UTF-8") 之类的所有可能组合。

首先,了解stringbytes 之间的区别。见https://docs.python.org/3/howto/unicode.html。可以将字符串编码为字节:bytes = text.encode("UTF-8"),也可以将字节解码为字符串:text = bytes.decode("UTF-8")

其次,由于 CSV 文件是文本文件,您应该以文本模式打开 CSV 文件。 open(fileName, 'w', encoding="utf-8")。编写文件时无需对代码中的文本进行编码或解码。

第三,将 Unicode 文本写入 TEXT 字段是完全可以的。不需要 BINARY 或 BLOB。但请确保您的数据库具有可以处理它的排序规则设置,通常是 utf-8 排序规则之一。然后将 Unicode 放入数据库中,使用 python 字符串,不要将它们解码为字节。

【讨论】:

    【解决方案3】:

    错误信息暗示MySQL中的列定义为CHARACTER SET ascii;对吗?

    B4 听起来像 ´ 的 latin1(不是 utf8)编码,它可能来自诸如 it´s 这样的上下文中的 Microsoft Word 文档。

    因此,即使将列更改为 CHARACTER SET utf8 也无法解决问题。

    BINARYBLOB 本质上是相同类型的字段——允许任何字节。 VARCHARTEXTINSERT 期间验证字节以确保它们与 CHARACTER SET 匹配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-29
      • 1970-01-01
      • 1970-01-01
      • 2017-12-23
      • 2012-11-06
      • 1970-01-01
      相关资源
      最近更新 更多