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ć?


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.


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.


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ć?


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.