2009-06-08 26 views
8

Sé que tengo un problema con una conversión de Unicode, pero no estoy seguro de dónde está sucediendo.Problema de Unicode con SQLAlchemy

Estoy extrayendo datos sobre un viaje reciente de Eruopean desde un directorio de archivos HTML. Algunos de los nombres de ubicación tienen caracteres que no son ASCII (como é, ô, ü). Obtengo los datos de una representación de cadena del archivo usando regex.

Si i imprimir los lugares como los encuentro, que imprimen con los personajes por lo que la codificación debe estar bien:

Le Pré-Saint-Gervais, France 
Hôtel-de-Ville, France 

Estoy almacenando los datos en una tabla usando SQLite SQLAlchemy:

Base = declarative_base() 
class Point(Base): 
    __tablename__ = 'points' 

    id = Column(Integer, primary_key=True) 
    pdate = Column(Date) 
    ptime = Column(Time) 
    location = Column(Unicode(32)) 
    weather = Column(String(16)) 
    high = Column(Float) 
    low = Column(Float) 
    lat = Column(String(16)) 
    lon = Column(String(16)) 
    image = Column(String(64)) 
    caption = Column(String(64)) 

    def __init__(self, filename, pdate, ptime, location, weather, high, low, lat, lon, image, caption): 
     self.filename = filename 
     self.pdate = pdate 
     self.ptime = ptime 
     self.location = location 
     self.weather = weather 
     self.high = high 
     self.low = low 
     self.lat = lat 
     self.lon = lon 
     self.image = image 
     self.caption = caption 

    def __repr__(self): 
     return "<Point('%s','%s','%s')>" % (self.filename, self.pdate, self.ptime) 

engine = create_engine('sqlite:///:memory:', echo=False) 
Base.metadata.create_all(engine) 
Session = sessionmaker(bind = engine) 
session = Session() 

I bucle a través de los archivos e insertar los datos de cada uno en la base de datos:

for filename in filelist: 

    # open the file and extract the information using regex such as: 
    location_re = re.compile("<h2>(.*)</h2>",re.M) 
    # extract other data 

    newpoint = Point(filename, pdate, ptime, location, weather, high, low, lat, lon, image, caption) 
    session.add(newpoint) 
    session.commit() 

I ver la siguiente advertencia en cada inserción:

/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/default.py:230: SAWarning: Unicode type received non-unicode bind param value 'Spitalfields, United Kingdom' 
    param.append(processors[key](compiled_params[key])) 

Y cuando trato de hacer cualquier cosa con la mesa, tales como:

session.query(Point).all() 

me sale:

Traceback (most recent call last): 
    File "./extract_trips.py", line 131, in <module> 
    session.query(Point).all() 
    File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/orm/query.py", line 1193, in all 
    return list(self) 
    File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/orm/query.py", line 1341, in instances 
    fetch = cursor.fetchall() 
    File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/base.py", line 1642, in fetchall 
    self.connection._handle_dbapi_exception(e, None, None, self.cursor, self.context) 
    File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/base.py", line 931, in _handle_dbapi_exception 
    raise exc.DBAPIError.instance(statement, parameters, e, connection_invalidated=is_disconnect) 
sqlalchemy.exc.OperationalError: (OperationalError) Could not decode to UTF-8 column 'points_location' with text 'Le Pré-Saint-Gervais, France' None None 

me gustaría para poder almacenar correctamente y luego devolver los nombres de ubicación con los caracteres originales intactos. Cualquier ayuda sería muy apreciada.

Respuesta

11

me encontré con este artículo que ayudó a explicar mis problemas tanto:

http://www.amk.ca/python/howto/unicode#reading-and-writing-unicode-data

yo era capaz de obtener los resultados deseados mediante el módulo de 'codecs' y luego cambiar mi programa como de la siguiente manera:

al abrir el archivo:

infile = codecs.open(filename, 'r', encoding='iso-8859-1') 

Al imprimir la ubicación:

print location.encode('ISO-8859-1') 

ahora puedo consultar y manipular los datos de la tabla sin el error de antes. Solo tengo que especificar la codificación cuando publico el texto.

(todavía no entienden completamente cómo esto está funcionando, así que supongo que es hora de aprender más acerca de la manipulación Unicode de Python ...)

+1

Intentaré "cp1252" primero antes de "iso-8859-1". Y no sé si lo siguiente ayuda en absoluto: http://stackoverflow.com/questions/368805/python-unicodedecodeerror-am-i-misunderstanding-encode/370199#370199 – tzot

7

Trate de usar un tipo de columna de Unicode en lugar de la cadena por las columnas Unicode:

Base = declarative_base() 
class Point(Base): 
    __tablename__ = 'points' 

    id = Column(Integer, primary_key=True) 
    pdate = Column(Date) 
    ptime = Column(Time) 
    location = Column(Unicode(32)) 
    weather = Column(String(16)) 
    high = Column(Float) 
    low = Column(Float) 
    lat = Column(String(16)) 
    lon = Column(String(16)) 
    image = Column(String(64)) 
    caption = Column(String(64)) 

Editar: respuesta al comentario:

Si está recibiendo advertencias sobre las codificaciones Unicode entonces hay dos cosas usted puede intentar:

  1. Convierta su ubicación a unicode. Esto significaría tener su punto creado de esta manera:

    Newpoint = Point (nombre de archivo, pdate, ptime, Unicode (ubicación), el tiempo, alto, bajo, lat, lon, imagen, una leyenda)

    La conversión Unicode producirá una cadena unicode cuando se pasa una cadena o una cadena unicode, por lo que no tiene que preocuparse acerca de lo que pasa en.

  2. Si eso no resuelve los problemas de codificación, intente llamar a codificar en su unicode objetos. Eso significaría usar código como:

    newpoint = Punto (nombre de archivo, pdate, ptime, unicode (ubicación) .encode ('utf-8'), clima, alto, bajo, lat, lon, imagen, título)

    Este paso probablemente no será necesario, pero lo que esencialmente hace es convertir un objeto Unicode de puntos de código Unicode en una representación de bytes específica (en este caso, utf-8). Esperaría que SQLAlchemy haga esto por ti cuando pases objetos Unicode, pero puede que no.

+0

Gracias por la sugerencia. Creo que esto me está llevando en la dirección correcta. Ahora recibo advertencias sobre la codificación de los datos que estoy insertando pero no estoy seguro de cómo solucionar esto. He actualizado mi pregunta para reflejar su sugerencia. –

7

De sqlalchemy.org

Véase la sección 0.4.2

añade nueva bandera de cadena y create_engine(), afirman _UNICODE = (True | False | 'avisar' | Ninguno) . El valor predeterminado es False o None en create _engine() y String, 'warn' en el tipo Unicode. Cuando True, da como resultado todas las operaciones de conversión Unicode que generan una excepción cuando se pasa una 0xbytesbyte no unicode como parámetro de vinculación. 'advertir' resultados en una advertencia. Se recomienda encarecidamente que todas las aplicaciones con reconocimiento de unicode hagan un uso adecuado de los objetos Unicode de Python (es decir, u'hello 'y no ' hola ') para que la ronda de datos se desplace de forma precisa.

Creo que está intentando ingresar una cadena de bytes no unicode. Quizás esto podría llevarte por el buen camino? Se necesita alguna forma de conversión, compare 'hola' y 'hola'.

Saludos

Cuestiones relacionadas