2011-12-25 12 views
5

Estoy tratando de analizar la descarga de documentos arbitrarios desde la web salvaje, y sí, no tengo control de su contenido.Beautiful Soup plantea UnicodeEncodeError "ordinal not in range (128)"

Desde Beautiful Soup won't choke if you give it bad markup... me pregunto ¿por qué me está dando esos crujidos cuando a veces, parte del documento está mal formado, y si hay una manera de hacer que reanudar al siguiente parte legible del documento, independientemente de este error.

La línea en la que se produjo el error es la tercera uno:

from BeautifulSoup import BeautifulSoup as doc_parser 
reader = open(options.input_file, "rb") 
doc = doc_parser(reader) 

CLI salida completa es:

Traceback (most recent call last): 
    File "./grablinks", line 101, in <module> 
    sys.exit(main()) 
    File "./grablinks", line 88, in main 
    links = grab_links(options) 
    File "./grablinks", line 36, in grab_links 
    doc = doc_parser(reader) 
    File "/usr/local/lib/python2.7/dist-packages/BeautifulSoup.py", line 1519, in __init__ 
    BeautifulStoneSoup.__init__(self, *args, **kwargs) 
    File "/usr/local/lib/python2.7/dist-packages/BeautifulSoup.py", line 1144, in __init__ 
    self._feed(isHTML=isHTML) 
    File "/usr/local/lib/python2.7/dist-packages/BeautifulSoup.py", line 1186, in _feed 
    SGMLParser.feed(self, markup) 
    File "/usr/lib/python2.7/sgmllib.py", line 104, in feed 
    self.goahead(0) 
    File "/usr/lib/python2.7/sgmllib.py", line 143, in goahead 
     k = self.parse_endtag(i) 
    File "/usr/lib/python2.7/sgmllib.py", line 320, in parse_endtag 
    self.finish_endtag(tag) 
    File "/usr/lib/python2.7/sgmllib.py", line 358, in finish_endtag 
    method = getattr(self, 'end_' + tag) 
UnicodeEncodeError: 'ascii' codec can't encode characters in position 15-16: ordinal not in range(128) 
+0

¿Qué tipo de información alimentas a BeautifulSoup? De acuerdo con el mensaje de error, ¿tal vez está analizando algunos datos que no son ASCII (que contienen caracteres no latinos, por ejemplo)? –

+0

Estoy analizando los datos provienen de la web salvaje, y algunas partes definitivamente no son ascii. –

Respuesta

2

Sí, se ahogará si tiene elementos con nombres que no sean ASCII (<café>). Y eso no es ni siquiera 'bad markup', para XML ...

Es un error en sgmllib que BeautifulSoup está usando: trata de encontrar métodos personalizados con los mismos nombres que las etiquetas, pero en Python 2 los nombres son cadenas de bytes por lo que incluso buscando para un método con un carácter no ASCII en, que nunca estará presente, falla.

Puede hackear una reparación en sgmllib cambiando las líneas 259 y 371 de except AttributeError: a except AttributeError, UnicodeError:, pero eso no es realmente una buena solución. No es trivial anular el resto del método tampoco.

¿Qué es lo que estás tratando de analizar? BeautifulStoneSoup siempre fue de utilidad cuestionable en realidad: XML no tiene la riqueza de hacks de analizador fantasmales que HTML hace, por lo que en general XML roto no es XML. Por lo tanto, generalmente debe usar un analizador XML viejo y simple (por ejemplo, use un DOM estándar o un etree). Para analizar HTML general, html5lib es su mejor opción estos días.

+0

La solución que sugiere no funcionará en absoluto, porque el error realmente comienza antes, cuando el analizador intenta hacer coincidir una etiqueta _start_ utilizando una expresión regular que solo admite caracteres que no sean ASCII. Esto significa que se saltará una etiqueta de inicio válida incluso antes de que ocurra el 'UnicodeEncodeError'. – ekhumoro

+0

@bobince, seguí su sugerencia y agregué 'UnicodeError',' UnicodeEncodeError' y 'UnicodeDecodeError' (ver en https://gist.github.com/1520499#L331) para los métodos * _endtag y * _startag - y ahora tengo los resultados que esperaba, simplemente saltean las partes binarias y extraen solo los fragmentos relevantes. ¡Gracias! –

0

Esto ocurre si hay caracteres no ASCII en la entrada en las versiones pitón antes Python 3.0

Si está intentando usar str(...) en una cadena que contiene caracteres con un valor de char> 128 (ANSII & unicode), esta excepción es r aised.

Aquí, el error posiblemente se produce porque getattr intenta usar str en una cadena Unicode - "cree" que puede hacerlo de manera segura porque en las versiones de python anteriores a 3.0 los identificadores no deben contener unicode.

Compruebe su HTML para caracteres Unicode. Intenta reemplazar/codificar estos y si aún no funciona, cuéntanos.

Cuestiones relacionadas