2015-06-14 6 views
2

У меня проблема с загрузкой CSV-файлов в MySQL, но потом что-то происходит, и я получаю ошибку кодирования. Может кто-нибудь, пожалуйста, просмотрите мой код и скажите, что не так? Я новичок в обращении.Python MySQLdb upload UnicodeEncodeError

Следующий фрагмент кода, как я пишу файлы CSV, которые будут загружены, данные извлекаются из файла MDB с помощью инструментов MDN (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'> 

Я заметил, что данные загружаются, но не уверены, что все строки загружены.

Спасибо!

+0

Несколько вопросов: (1) Что входит в переменную 'tableULD', откуда она исходит? (2) Можете ли вы получить трассировку стека из этого исключения? – roeland

+0

С учетом того, что вы используете * python 3 *, попробуйте открыть файл с помощью 'open (fileName, 'w', encoding =" utf-8 ")', а не 'open (имя_файла, 'wb'). '. Вы все написали текст, а не двоичные данные. – roeland

ответ

0

Попробуйте, прежде чем положить CSV в БД s.decode('UTF-8') и после получения его из БД s.encode('UTF-8')

Я сделал это для SQLite и она работала нормально.

+0

Ivan: Сделано так, как вы порекомендовали: Я закодировал его после получения из MDB 'tableContent = tableContent.encode (' UTF-8 '). Split (' \ n ')'. Затем декодируется перед загрузкой'f.write (tableContent.decode ('UTF-8')) 'Got error:' tableContent = tableContent.encode ('UTF-8'). Split ('\ n') UnicodeDecodeError: 'ascii 'кодек не может декодировать байт 0xaf в позиции 237: порядковый номер не в диапазоне (128)' – Francisco

+0

OK. Я делал декодирование ввода текста HTML-форм перед вставкой в ​​БД. Но если у вас есть только файл, попробуйте s.encode («UTF-8») раньше. Если это не работает, попробуйте s.encode («UTF-8»). Decode. («UTF-8»). И s.encode ('UTF-8') после. –

+0

Я добавил код в точку, где данные приводят к проблеме. Оказывается, что данные non-ascii загружаются в BLOB-поле в MySQL, это повышает исключение. Какова наилучшая практика для обработки данных, не относящихся к ascii, которые необходимо сохранить? Должен ли BLOB быть изменен BINARY? – Francisco

0

Получение этого для работы не должно быть слишком сложным, но вы должны понимать, что делаете. Не просто попробуйте все возможные комбинации s.encode("UTF-8").decode("UTF-8") и тому подобное.

Во-первых, понять разницу между string и bytes. См. 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"). Нет необходимости кодировать или декодировать текст в коде при записи файла.

В-третьих, вполне нормально писать текст Юникода в поле ТЕКСТ. Нет необходимости в BINARY или BLOB. Но убедитесь, что в вашей базе данных есть параметр сортировки, который может справиться с ним, обычно это будет одно из совпадений utf-8. Затем, чтобы поместить Unicode в вашу базу данных, используйте строки python и не расшифровывайте их в байтах.

0

Сообщение об ошибке означает, что определение столбца в MySQL равно CHARACTER SET ascii; это верно?

B4 звучит как latin1 (не utf8) кодирования для ´, который может быть наступающими из документа Microsoft Word в контексте таких как it´s.

Таким образом, даже изменение колонки, которая будет CHARACTER SET utf8, не решит проблему.

BINARY и BLOB - это, по сути, один и тот же тип поля - разрешен любой байт. VARCHAR и TEXT подтвердите байты в течение INSERT, чтобы убедиться, что они соответствуют CHARACTER SET.