Pregunta

Quiero analizar RSS descargado con LXML, pero no sé cómo manejar con UnicodeDecodeError.

request = urllib2.Request('http://wiadomosci.onet.pl/kraj/rss.xml')
response = urllib2.urlopen(request)
response = response.read()
encd = chardet.detect(response)['encoding']
parser = etree.XMLParser(ns_clean=True,recover=True,encoding=encd)
tree = etree.parse(response, parser)

Pero recibo un error:

tree   = etree.parse(response, parser)
File "lxml.etree.pyx", line 2692, in lxml.etree.parse (src/lxml/lxml.etree.c:49594)
  File "parser.pxi", line 1500, in lxml.etree._parseDocument (src/lxml/lxml.etree.c:71364)
  File "parser.pxi", line 1529, in lxml.etree._parseDocumentFromURL (src/lxml/lxml.etree.c:71647)
  File "parser.pxi", line 1429, in lxml.etree._parseDocFromFile (src/lxml/lxml.etree.c:70742)
  File "parser.pxi", line 975, in lxml.etree._BaseParser._parseDocFromFile (src/lxml/lxml.etree.c:67
740)
  File "parser.pxi", line 539, in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etr
ee.c:63824)
  File "parser.pxi", line 625, in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:64745)
  File "parser.pxi", line 559, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:64027)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 97: ordinal not in range(128)
¿Fue útil?

Solución

Probablemente solo debería tratar de definir la codificación del personaje como último recurso, ya que está claro qué se basa la codificación en el Prólogo XML (si no es por los encabezados HTTP). De todos modos, es innecesario pasar la codificación etree.XMLParser A menos que desee anular la codificación; Así que deshazte del encoding parámetro y debería funcionar.

Editar: Bien, el problema en realidad parece estar con lxml. Lo siguiente funciona, por cualquier razón:

parser = etree.XMLParser(ns_clean=True, recover=True)
etree.parse('http://wiadomosci.onet.pl/kraj/rss.xml', parser)

Otros consejos

Me encontré con un problema similar, y resulta que esto no tiene nada que ver con las codificaciones. Lo que está sucediendo es esto: LXML le está lanzando un error totalmente no relacionado. En este caso, el error es que la función .Parse espera un nombre de archivo o URL, y no una cadena con el contenido en sí. Sin embargo, cuando intenta imprimir el error, se ahoga en caracteres no ASCII y muestra ese mensaje de error completamente confuso. Es muy desafortunado y otras personas han comentado sobre este tema aquí:

https://mailman-mail5.webfaction.com/pipermail/lxml/2009-february/004393.html

Afortunadamente, el tuyo es una solución muy fácil. Simplemente reemplace .Parse con. Desde el rango y debería estar totalmente bueno para ir:

request = urllib2.Request('http://wiadomosci.onet.pl/kraj/rss.xml')
response = urllib2.urlopen(request)
response = response.read()
encd = chardet.detect(response)['encoding']
parser = etree.XMLParser(ns_clean=True,recover=True,encoding=encd)

## lxml Y U NO MAKE SENSE!!!
tree = etree.fromstring(response, parser)

Acabo de probar esto en mi máquina y funcionó bien. ¡Espero eso ayude!

A menudo es más fácil cargar y solucionar la cadena para la biblioteca LXML primero, y luego llamar desde el rótido, en lugar de confiar en la función LXML.etree.Parse () y sus opciones de codificación difíciles de administrar.

Este archivo RSS en particular comienza con la declaración de codificación, por lo que todo debería funcionar:

<?xml version="1.0" encoding="utf-8"?>

El siguiente código muestra algunas de las diferentes variaciones que puede aplicar para hacer que Etree se analice para diferentes codificaciones. También puede solicitarlo para escribir diferentes codificaciones también, que aparecerán en los encabezados.

import lxml.etree
import urllib2

request = urllib2.Request('http://wiadomosci.onet.pl/kraj/rss.xml')
response = urllib2.urlopen(request).read()
print [response]
        # ['<?xml version="1.0" encoding="utf-8"?>\n<feed xmlns=... <title>Wiadomo\xc5\x9bci...']

uresponse = response.decode("utf8")
print [uresponse]    
        # [u'<?xml version="1.0" encoding="utf-8"?>\n<feed xmlns=... <title>Wiadomo\u015bci...']

tree = lxml.etree.fromstring(response)
res = lxml.etree.tostring(tree)
print [res]
        # ['<feed xmlns="http://www.w3.org/2005/Atom">\n<title>Wiadomo&#347;ci...']

lres = lxml.etree.tostring(tree, encoding="latin1")
print [lres]
        # ["<?xml version='1.0' encoding='latin1'?>\n<feed xmlns=...<title>Wiadomo&#347;ci...']


# works because the 38 character encoding declaration is sliced off
print lxml.etree.fromstring(uresponse[38:])   

# throws ValueError(u'Unicode strings with encoding declaration are not supported.',)
print lxml.etree.fromstring(uresponse)

El código se puede probar aquí: http://scraperwiki.com/scrapers/lxml_and_encoding_declarations/edit/#

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top