Problem mit Encoding - PayPal CSV to SQLite

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
martinjo
User
Beiträge: 186
Registriert: Dienstag 14. Juni 2011, 20:03

Hallo,

ich komme bei meinem Programm nicht weiter. Ich versuche eine PayPal CSV Datei in eine SQLite Datenbank zu kopieren. Hänge aber an einem KeyError den ich auf ein Problem mit dem Encoding zurückführe. Ich dachte eigentlich das habe ich schon soweit im Griff, kann jedoch die CSV File nicht mal codecs.open öffnen. Das strip() wird verwendet da bei der PayPal CSV ein Leerzeichen vor dem Titel der Spalte steht.

Die CSV Datei stelle ich hier zum herunterladen bereit. Encoding sollte eigentlich iso-8859-15 bzw latin-1 sein.

CSV File: http://www.file-upload.net/download-860 ... n.csv.html

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf8 -*-

import csv
import codecs
import time

from sqlite3 import dbapi2 as sqlite

#.decode('latin')
#.encode('utf8')

def readPayPalCSV():
    with codecs.open('./Data/Herunterladen.csv', 'rb') as csvfile:
        csvReader = csv.DictReader(csvfile, delimiter=",")
        header = [c for c in csvReader.fieldnames if c.strip()]
        print "\n header", header
        csvcontent = []
        for c in csvReader:
            newdict = {}
            for h in header:
                newdict[h.strip()] = c[h]
            csvcontent.append(newdict)
        print "\n PayPal Liste\n%s Einträge" % len(csvcontent)
        return csvcontent
paypal_dict_list = readPayPalCSV()

#connect to db
con = sqlite.connect("Data/database_test")
cur = con.cursor()

#del db and create new db 
def create_db():
        #paypal
        cur.execute('''drop table if exists paypal_complete''')
        cur.execute('''create table if not exists paypal_complete (Datum date, Zeit time,  Zeitzone text, Name text, Art text, Status text, Währung text, Brutto text, Gebühr text, Netto text, [Von E-Mail-Adresse] text, [An E-Mail-Adresse] text, Transaktionscode text PRIMARY KEY, [Status der Gegenpartei] text, Adressstatus text, Verwendungszweck text, Artikelnummer text, [Betrag für Versandkosten] text, Versicherungsbetrag text, Umsatzsteuer text, [Option 1 - Name] text, [Option 1 - Wert] text, [Option 2 - Name] text, [Option 2 - Wert] text, [Auktions-Site] text, [Käufer-ID] text, [Artikel-URL] text, Angebotsende date, [Vorgangs-Nr.] text, [Rechnungs-Nr.] text, [Txn-Referenzkennung] text, Rechnungsnummer text, [Individuelle Nummer] text, Bestätigungsnummer text, Guthaben text, Adresse text, [Zusätzliche Angaben] text, Ort [text], [Staat/Provinz/Region/Landkreis/Territorium/Präfektur/Republik] text, PLZ text, Land text, [Telefonnummer der Kontaktperson] text)''')
create_db()

def print_header(tabelle):
    print "\n header for", tabelle
    cur.execute("PRAGMA table_info("+tabelle+")")
    print cur.fetchall()
print_header("paypal_complete")

def insertDict(curs, tablename, data_list):
    for data in data_list:
        fields = ['[' + k + ']' for k in data.keys()]
        values = ['[' + v + ']' for v in data.values()]
        placeholder = "?"
        fieldlist = ",".join(fields)
        placeholderlist = ",".join([placeholder] * len(fields))
        query = "insert into %s(%s) values (%s)" % (tablename, fieldlist, placeholderlist)
        print "query"
        print query
        curs.execute(query, values)
insertDict(cur, "paypal_complete", paypal_dict_list) 

#show first db entries
def print_lines(db, count=5):
    print "\n", db
    cur.execute('select * from '+db)
    for n, a in enumerate(cur):
        if n == count:
            break
        else:
            print a
print_lines("paypal_complete")

#close connection
con.commit()
Würde mich sehr über Hilfe freuen. Danke
Benutzeravatar
martinjo
User
Beiträge: 186
Registriert: Dienstag 14. Juni 2011, 20:03

Die CSV-Datei lässt sich nun herunterladen. Hatte nicht bemerkt, was speedyshare com für ein Müll ist.

Nutze ich

Code: Alles auswählen

codecs.open('./Data/Herunterladen.csv', 'rb', 'latin')
bekomme ich
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 43: ordinal not in range(128)
Nutze ich

Code: Alles auswählen

codecs.open('./Data/Herunterladen.csv', 'rb', 'utf8')
bekomme ich
UnicodeDecodeError: 'utf8' codec can't decode byte 0xe4 in position 43: invalid continuation byte
Lasse ich das Encoding weg bekomme ich
sqlite3.OperationalError: table paypal_complete has no column named K�ufer-ID
Bei weiteren Experimenten direkt einzelne Elemente mit decode('latin') in Unicode zu transferieren bekomme ich die Meldung:
sqlite3.ProgrammingError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.
Evtl. hilft diese Ergänzung ja noch.
Die Typen sollten übrigens alle vorerst text sein. Das dort noch 2x date als Typ vorkommt war nicht beabsichtigt. Das sollte auch vorerst text sein.

Hier habe ich dies korrigiert und auch die Datei als UTF-8 gespeichert. Code + Result: http://pastebin.com/GtPh8YeY


edit:
Dieser Code umgeht das Problem. Ich würde jedoch lieber in Unicode speichern. Bzw. habe das eigentlich so verstanden, dass nur die Ausgabe umgewandelt wird. Ich will doch eigentlich speichern und nicht ausgeben!? (http://docs.python.org/2/library/sqlite ... xt_factory)

Code: Alles auswählen

#connect to db
con = sqlite.connect("Data/database_test")
con.text_factory = str
cur = con.cursor()
Benutzeravatar
martinjo
User
Beiträge: 186
Registriert: Dienstag 14. Juni 2011, 20:03

Ich hatte vergessen, dass der csv.DictReader nicht mit Uniode umgehen kann. Suche ich jedoch nach den Spalten in meiner Datenbank muss ich die Strings zuvor in Unicode umwandeln:

Code: Alles auswählen

def insertDict(curs, tablename, data_list):
    for data in data_list:
        fields = [u'[' + k.decode('utf8') + u']' for k in data.keys()]
        values = [u'[' + v.decode('utf8') + u']' for v in data.values()]
        placeholder = "?"
        fieldlist = ",".join(fields)
        placeholderlist = ",".join([placeholder] * len(fields))
        query = "insert or ignore into %s(%s) values (%s)" % (tablename, fieldlist, placeholderlist)
        curs.execute(query, values)
Damit hat sich das Problem für mich erledigt.
Antworten