BeautifulSoup me da símbolos unicode + html, en lugar de unicode directo. ¿Es esto un error o un malentendido?

StackOverflow https://stackoverflow.com/questions/629999

Pregunta

Estoy usando BeautifulSoup para raspar un sitio web. La página del sitio web se ve bien en mi navegador:

  

Informe de Oxfam Internacional titulado & # 8220; ¡Fuera de juego!    http://www.coopamerica.org/programs/responsibleshopper/company.cfm ? id = 271

En particular, las comillas simples y dobles se ven bien. Se ven símbolos html en lugar de ascii, aunque extrañamente cuando veo la fuente en FF3 parecen ser ascii normales.

Desafortunadamente, cuando rasco me sale algo como esto

  

Informe de u'Oxfam International \ xe2 & # 8364; & # 8482;   titulado \ xe2 & # 8364; & # 339; ¡Fuera de juego!

Ups, quiero decir esto:

u'Oxfam International\xe2€™s report entitled \xe2€œOffside!

Los metadatos de la página indican la codificación 'iso-88959-1'. Probé diferentes codificaciones, jugué con funciones de terceros unicode- > ascii y html- > ascii, y examiné la discrepancia MS / iso-8859-1, pero el hecho es que & # 8482; no tiene nada que ver con una sola cita, y parece que no puedo convertir el combo unicode + htmlsymbol en el símbolo ascii o html correcto, en mi conocimiento limitado, por eso estoy buscando ayuda.

Estaría feliz con una comilla doble ASCII, " o "

El siguiente problema es que me preocupa que haya otros símbolos divertidos decodificados incorrectamente.

\xe2€™

A continuación se muestra algo de Python para reproducir lo que estoy viendo, seguido de las cosas que he probado.

import twill
from twill import get_browser
from twill.commands import go

from BeautifulSoup import BeautifulSoup as BSoup

url = 'http://www.coopamerica.org/programs/responsibleshopper/company.cfm?id=271'
twill.commands.go(url)
soup = BSoup(twill.commands.get_browser().get_html())
ps = soup.body("p")
p = ps[52]

>>> p         
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe2' in position 22: ordinal not in range(128)

>>> p.string
u'Oxfam International\xe2€™s report entitled \xe2€œOffside!<elided>\r\n'

http://groups.google.com/group/comp.lang.python/browse_frm/thread/9b7bb3f621b4b8e4/3b00a890cf3a5e46?q=htmlentitydefs&rnum=3&hl=en#3b00a890cf3a5e46

http://www.fourmilab.ch/webtools/demoroniser/

http://www.crummy.com/software/BeautifulSoup/documentation.html

http://www.cs.tut.fi/~ jkorpela / www / windows-chars.html

>>> AsciiDammit.asciiDammit(p.decode())
u'<p>Oxfam International\xe2€™s report entitled \xe2€œOffside!

>>> handle_html_entities(p.decode())
u'<p>Oxfam International\xe2\u20ac\u2122s report entitled \xe2\u20ac\u0153Offside! 

>>> unicodedata.normalize('NFKC', p.decode()).encode('ascii','ignore')
'<p>Oxfam International€™s report entitled €œOffside!

>>> htmlStripEscapes(p.string)
u'Oxfam International\xe2TMs report entitled \xe2Offside!

EDITAR:

He intentado usar un analizador BS diferente:

import html5lib
bsoup_parser = html5lib.HTMLParser(tree=html5lib.treebuilders.getTreeBuilder("beautifulsoup"))
soup = bsoup_parser.parse(twill.commands.get_browser().get_html())
ps = soup.body("p")
ps[55].decode()

que me da esto

u'<p>Oxfam International\xe2\u20ac\u2122s report entitled \xe2\u20ac\u0153Offside!

la mejor decodificación de casos parece darme los mismos resultados:

unicodedata.normalize('NFKC', p.decode()).encode('ascii','ignore')
'<p>Oxfam InternationalTMs report entitled Offside! 

EDITAR 2:

Estoy ejecutando Mac OS X 4 con FF 3.0.7 y Firebug

Python 2.5 (wow, no puedo creer que no dije esto desde el principio)

¿Fue útil?

Solución

Esa es una página muy desordenada, en cuanto a codificación :-)

No hay nada realmente malo con tu enfoque. Probablemente tendería a hacer la conversión antes de pasarla a BeautifulSoup, solo porque soy perspicaz:

import urllib
html = urllib.urlopen('http://www.coopamerica.org/programs/responsibleshopper/company.cfm?id=271').read()
h = html.decode('iso-8859-1')
soup = BeautifulSoup(h)

En este caso, la metaetiqueta de la página miente sobre la codificación. La página está en realidad en utf-8 ... La información de la página de Firefox revela la codificación real, y puedes ver este juego de caracteres en los encabezados de respuesta devueltos por el servidor:

curl -i http://www.coopamerica.org/programs/responsibleshopper/company.cfm?id=271
HTTP/1.1 200 OK
Connection: close
Date: Tue, 10 Mar 2009 13:14:29 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Set-Cookie: COMPANYID=271;path=/
Content-Language: en-US
Content-Type: text/html; charset=UTF-8

Si hace la decodificación usando 'utf-8', funcionará para usted (o, al menos, lo hizo para mí):

import urllib
html = urllib.urlopen('http://www.coopamerica.org/programs/responsibleshopper/company.cfm?id=271').read()
h = html.decode('utf-8')
soup = BeautifulSoup(h)
ps = soup.body("p")
p = ps[52]
print p

Otros consejos

En realidad es UTF-8 mal codificado como CP1252:

>>> print u'Oxfam International\xe2€™s report entitled \xe2€œOffside!'.encode('cp1252').decode('utf8')
Oxfam International’s report entitled “Offside!
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top