Problem z kodowaniem w języku Python

2

Mam skrypt w języku Python, który eksportuje dane z tabeli mysql utf-8 do pliku tekstowego. Oto kod, który wykonuje zadanie

csvDatei = codecs.open( csvDateiName, "w", "utf-8" )
...
cursor = db.cursor();
sql = "select * from %s.%s;" % (dbAusgang, tabelle)
cursor.execute(sql);
...
daten = cursor.fetchall();
for i in xrange(len(daten)):
    line = '';
    for j in xrange(len(daten[i])):
        line += '"%s";' % unicode(daten[i][j]);
    line = line[:-1];
    line += '\n';
    csvDatei.write(line);
csvDatei.close();

Próbowałem również tego

line += '"%s";' % str(daten[i][j]);

i

line += '"%s";' % daten[i][j];

A teraz część, której nie rozumiem:

Zwykle ten skrypt powinien być wywoływany przez zadanie cron. Ale kiedy czytam varchara ze tabeli zawierającej umlaut, taki jak ä, ö lub ü, skrypt po prostu się kończy. Sprawdziłem to, przesyłając dane wyjściowe skryptu do pliku.

Dlatego przetestowałem skrypt, wywołując go ręcznie w powłoce, wpisując po prostu „python myscript.py” i działa on doskonale bez żadnych problemów.

Domyślam się, że problem tak naprawdę nie leży w samym skrypcie, ale raczej w środowisku cron.

Mam nadzieję, że ktokolwiek z was udzieli mi porady. Jestem całkowicie zdezorientowany.

Każda pomoc jest mile widziana.

---------------- Odpowiedź na komentarz 1:

Dzięki za podpowiedź do ustawień regionalnych.

Najpierw napisałem „locale” na standardowej powłoce. Dało mi to następujące dane wyjściowe:

dhl@srv1093:~$ locale
LANG=de_DE.UTF-8
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=de_DE.UTF-8

Następnie edytowałem plik cron za pomocą „crontab -e” i dodałem następującą linię

*/1 * * * * locale > /home/user/locale.ouput

Dane wyjściowe tego cronjob jest:

dhl@srv1093:~$ cat locale.ouput 
LANG=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

To może być problem? Jak mogę to naprawić?

TessellatingHeckler
źródło
1
1.Upewnij się, że cron może wysłać ci pocztę i ją przeczytać, prawdopodobnie zawiera ślad. 2. Sprawdź, czy dane wyjściowe localesą takie same wewnątrz crona.
Tobu,

Odpowiedzi:

1

Dekodujesz linie do Unicode unicode(daten[i][j]). Gdy nie podajesz żadnego kodowania, Python używa domyślnego systemu, który prawdopodobnie jest ascii po uruchomieniu skryptu przez cron.

W obu przypadkach należy podać rzeczywiste kodowanie używane przez bazę danych. Możesz użyć unicode(daten[i][j], dbencoding)zamiast tego lub uzyskać adapter bazy danych, który da ci kod Unicode bezpośrednio.

Btw: Prawdopodobnie istnieje milion narzędzi, które generują pliki CVS z zapytań do baz danych, MySQL ma to nawet wbudowane. Z drugiej strony twój kod jest raczej delikatny, ponieważ nie uciekasz w ogóle.

Jochen Ritzel
źródło
Dziękuję za odpowiedź. Mój skrypt działa dobrze, jestem z niego bardzo zadowolony i nie zamierzam go zmieniać. Problem wydaje się wynikać z kodowania. Również zmiana na „Unicode (daten [i] [j],„ utf-8 ”);” powoduje awarię skryptu już przy pierwszym fragmencie danych. Więc usunę to jeszcze raz
@toom: Więc co to znaczy? Jeśli linia się nie powiedzie, twoje dane nie są zakodowane w UTF-8.
Jochen Ritzel,
Okej, więc jak ustalić kodowanie bazy danych? Afaik, to jest utf-8, jak mówi mi „show create table tablename”. I dlaczego mój skrypt działa w normalnej powłoce. To też nie powinno być możliwe.
0

Jestem pewien, że to jest problem. MySQL przyjrzy się twoim ustawieniom regionalnym, aby określić kodowanie znaków do zwrócenia wartości. Wiem również, że znaki łacińskie z umlautami, gdy są zakodowane w ISO-8859-1, nie są poprawnymi znakami UTF-8, a każdy dekoder zawiedzie, jeśli spróbuje dekodować (bez zestawu ustawień narodowych moduł klienta db może być domyślny). Nie próbowałem tego i nie wiem, jakiej wersji Pythona używasz, ale Google python localezwrócił ten link: http://docs.python.org/library/locale.html So. spróbowałbym

import locale
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')

na samym początku skryptu przed zaimportowaniem modułu łączności db i sprawdź, czy to działa.

Hoons
źródło
Tak, podejrzewam też coś takiego. Moduł łączności db prawdopodobnie ma również opcję ustawienia kodowania dla połączenia, więc nie potrzebujesz ustawień regionalnych.
Jochen Ritzel,
Dziękuję za odpowiedź. Ustawienie lokalnego z kodu nie dało niczego, co nadal powoduje awarię, gdy zbliża się do umlaut. Jeśli MySQL używa kodowania odpowiadającego lokalnemu, byłby to POSIX, a podczas działania w normalnej powłoce byłby to UTF-8. W każdym razie zawsze otwieram połączenie z bazą danych przez mysql.connect (db = '', charset = "utf8", use_unicode = True, ** v.MySQLServer [serwer])
0

Okej, teraz dowiedziałem się na czym polega problem. Nie ma to nic wspólnego z kodem, dobrze, to już wcześniej było jasne, ale problemem są zmienne języka lokalnego.

W zadaniu cron kodowania są ustawione na POSIX, aw normalnym trybie SHELL kodowania są ustawione na UTF-8. Zmieniłem więc kodowanie z UTF-8 na POSIX i uruchomiłem skrypt. I niespodzianka, ten sam błąd występuje w środowisku cron. Więc teraz zmieniam kodowanie krok po kroku, mam na myśli zmienne po zmiennej i sprawdzam, czy mój skrypt działa, czy nie.

Najpierw się zmieniłem

eksport LANG = de_DE.UTF-8

i po uruchomieniu skryptu pozostał ten sam błąd. Potem się zmieniłem

eksport LC_CTYPE = "de_DE.UTF-8"

a potem skrypt działał absolutnie dobrze. Bez problemów.

To jest problem. Jak teraz zmienić tę zmienną w moim środowisku cron? Próbowałem już w kodzie

locale.setlocale(locale.LC_CTYPE, 'de_DE.UTF-8')

Ale to nie zadziałało.

Jak to zmienić?


źródło
W pliku crontab umieść zmienne środowiskowe na górze. LANG=de_DE.UTF-8a LC_CTYPE="de_DE.UTF-8".
Keith
Mmmh teraz wszystkie zmienne językowe są ustawione na utf-8, ale nadal zawiesza się, jeśli chodzi o umlaut. Co jeszcze może być problemem?
Czy jesteś pewien, że ciąg znaków w bazie danych to UTF-8?
Keith
Sprawdziłem bazę danych i odkryłem, że kodowanie znaków w rzeczywistości nie jest utf8, ale latin1. Myślę, że najpierw muszę to sprawdzić z kolegą odpowiedzialnym za bazę danych. Właściwie kodowanie powinno być utf8. Nadal nie rozumiem, dlaczego skrypt działa w normalnej powłoce i ulega awarii w środowisku cron? Nie powinno tak się zdarzyć, jeśli kodowanie jest nieprawidłowe, powinno również zawieść w normalnej powłoce
Można eksportować zmienne w samej crontab, wystarczy wpis byćexport LC_CTYPE="de_DE.UTF-8"; myscript.py