2016-08-23 11 views
9

Potrzebuję wywołać procedurę przechowywaną MySQL z mojego skryptu python. Jako jeden z parametrów przekazuję ciąg znaków Unicode (język rosyjski), ale pojawia się błąd;Python z problemami z Unicode MySql

UnicodeEncodeError: 'latin-1' codec can't encode characters in position 0-1: ordinal not in range(256)

Mój skrypt:

self.db=MySQLdb.connect("localhost", "usr", "pass", "dbName") 
    self.cursor=self.db.cursor() 
    args=("какой-то текст") #this is string in russian 
    self.cursor.callproc('pr_MyProc', args) 
    self.cursor.execute('SELECT @_pr_MyProc_2') #getting result from sp 
    result=self.cursor.fetchone() 
    self.db.commit() 

Czytałem, że ustawienie charset='utf8' shuld rozwiązać ten problem, ale kiedy używam ciąg:

self.db=MySQLdb.connect("localhost", "usr", "pass", "dbName", charset='utf8') 

To daje mi kolejny błąd;

UnicodeEncodeError: 'utf-8' codec can't encode character '\udcd1' in position 20: surrogates not allowed

Również próbuję ustawić parametr use_unicode=True, który nie działa.

+0

Czy to działa, jeśli wysłać ciąg Unicode: 'args = (u "какой-то текст") '? –

+0

@ DanielRoseman nie, też tego wypróbowałem. – Gleb

+0

to jest python 2 lub 3? –

Odpowiedz

5

więcej rzeczy do sprawdzenia na: http://mysql.rjweb.org/doc.php/charcoll#python

Prawdopodobne pozycji:

  • Uruchom plik kodu z # -*- coding: utf-8 -*- - (dla literały w kodzie)
  • Literówki powinny być u '...'

Czy możesz wydobyć HEX? какой-то текст powinien to być w utf8: D0BA D0B0 D0BA D0BE D0B9 2D D182 D0BE D182 20 D0B5 D0BA D181 D182

+2

Jak rozumiem "# - * - coding: utf-8 - * -" ustawia kodowanie dla pliku, a nie dla ciągów. Więc to nie pomaga. – Gleb

+0

Czy to boli w Twojej sytuacji? –

2

Moduł MySQLdb nie jest kompatybilny z pythonem 3. Być może dlatego pojawiają się problemy. Radziłbym użyć innego złącza, takiego jak PyMySQL lub mysqlclient.

Powiązane: 23376103.

+1

Używam mysqlclinet – Gleb

3

Oto kilka myśli. Może nie odpowiedź. Grałem z python/mysql/utf-8/unicode w przeszłości i to jest to, co pamiętam:

Patrząc na komentarzu Saltstack modułu MySQL:

https://github.com/saltstack/salt/blob/develop/salt/modules/mysql.py#L314-L322

# MySQLdb states that this is required for charset usage 
# but in fact it's more than it's internally activated 
# when charset is used, activating use_unicode here would 
# retrieve utf8 strings as unicode() objects in salt 
# and we do not want that. 
#_connarg('connection_use_unicode', 'use_unicode') 
connargs['use_unicode'] = False 
_connarg('connection_charset', 'charset') 

Mamy zobacz, że aby uniknąć zmiany ciągu wynikowego, use_unicode jest ustawione na False, a zestaw znaków (który mógłby być utf-8) jest ustawiony jako parametr. use_unicode jest bardziej "żądaniem", aby uzyskać odpowiedzi jako ciągi Unicode.

Możesz sprawdzić rzeczywiste użycie w testach, tutaj: https://github.com/saltstack/salt/blob/develop/tests/integration/modules/test_mysql.py#L311-L361 z bazą danych o nazwie "標準 語".

Teraz o wiadomości UnicodeEncodeError: Kodek 'utf-8' nie może kodować znaku '\ udcd1' **. Używasz ** unicode, ale mówisz modułowi, że jest to utf-8. Nie jest to utf-8, dopóki nie zakodujesz swojego ciągu Unicode w utf-8.

Może powinieneś spróbować z:

args=(u"какой-то текст".encode('utf-8')) 

Przynajmniej w python3 jest to konieczne, ponieważ "какой-то текст" nie jest w UTF-8 domyślnie.

+0

Link jest teraz uszkodzony: Znalazłem nowy link: https://github.com/saltstack/salt/blob/develop/tests/integration/modules/test_mysql.py#L311-L361 (Note file_name zmień) – bdeo

+0

dzięki, link zaktualizowany – regilero

1

Jaki jest zestaw znaków Twojej bazy danych?
zastosowanie:

show variables like "characetr%"; 

lub zobaczyć charset bazy danych za

2

Może można przeładować sys w utf-8 i spróbować zdekodować ciąg na utf-8 w następujący sposób:

import sys 
reload(sys) 
sys.setdefaultencoding("utf-8") 

... 

stringUtf8 = u''.join(string_original).decode('utf-8') 
1

Widzę tu dwa problemy.

  1. Masz unikod, ale próbujesz zdefiniować go jako utf-8, ustawiając parametr "charset". Najpierw należy zakodować swój kod Unicode na UTF-8 lub inny system kodowania.

  2. Jeśli to jednak nie działa, spróbuj zrobić to przy pomocy parametru init_command = 'SET NAMES UTF8'.

Tak będzie wyglądać następująco:

conn = MySQLdb.connect(charset='utf8', init_command='SET NAMES UTF8') 

Można spróbować także tego:

cursor = db.cursor() 

cursor.execute("SET NAMES UTF8;") 
2

miałem podobny problem bardzo niedawno, ale z PostgreSQL. Po wypróbowaniu ton sugestii z SO/internet, zdałem sobie sprawę, że problem był z moją bazą danych. Musiałem usunąć moją bazę danych i ponownie zainstalować PostgreSQL, ponieważ z jakiegoś powodu nie pozwalała mi ona zmienić domyślnego sortowania bazy danych. Spieszyłem się, więc nie mogłem znaleźć lepszego rozwiązania, ale poleciłbym to samo, ponieważ dopiero uruchamiałem moją aplikację w środowisku wdrażania. Wszystkiego najlepszego.

0

Napotkałem podobny problem, który został spowodowany przez nieprawidłowe dane utf-8 w bazie danych; wydaje się, że MySQL nie dba o to, ale Python robi, bo to po spec UTF-8, który mówi that:

  • zastępcze pary nie są dozwolone w UTF-8
  • niesparowanych zastępcze nie są dozwolone w utf-8

Jeśli chcesz "sprawić, by działało", musisz przechwycić pakiet MySQL i użyć własnego konwertera, który wykona wymianę ad-hoc.

Oto jeden sposób, by „obsłużyć” nieprawidłowe dane zawierające zastępcze:

def borked_utf8_decode(data): 
    """ 
    Work around input with unpaired surrogates or surrogate pairs, 
    replacing by XML char refs: look for "&#\d+;" after. 
    """ 
    return data.decode("utf-8", "surrogatepass") \ 
    .encode("utf-8", "xmlcharrefreplace") \ 
    .decode("utf-8") 

Należy pamiętać, że właściwy sposób obsłużyć to jest zależne od kontekstu, ale istnieją pewne wspólne scenariusze zamienne, jak this one.

A oto jeden sposób podłączyć to pod pymysql (innym sposobem jest przetwarzanie pola małpa-łaty, patrz np https://github.com/PyMySQL/PyMySQL/issues/631.):

import pymysql.converters 

# use this in your connection 
pymysql_use_unicode = False 
conversions = pymysql.converters.conversions 
conversions[pymysql.converters.FIELD_TYPE.STRING] = borked_utf8_decode 
conversions[pymysql.converters.FIELD_TYPE.VAR_STRING] = borked_utf8_decode 
conversions[pymysql.converters.FIELD_TYPE.VARCHAR] = borked_utf8_decode