2009-03-10 11 views
5

J'utilise BeautifulSoup pour gratter un site Web. La page du site Web s'affiche correctement dans mon navigateur:BeautifulSoup me donne des symboles unicode + html, plutôt que d'unicode. Est-ce un bug ou un malentendu?

Le rapport d'Oxfam International intitulé «Offside! http://www.coopamerica.org/programs/responsibleshopper/company.cfm?id=271

En particulier, les guillemets simples et doubles ont l'air bien. Ils regardent des symboles html plutôt qu'ascii, bien que bizarrement quand je regarde la source dans FF3 ils semblent être des ascii normaux.

Malheureusement, quand j'érafle je reçois quelque chose comme ça

u'Oxfam international \ rapport XE2 € ™ intitulé \ XE2 € œOffside!

oups, je veux dire ceci:

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

méta-données de la page indique le codage 'iso-88959-1. J'ai essayé différents encodages, joué avec unicode-> ascii et html-> ascii des fonctions tierces, et j'ai regardé la divergence MS/iso-8859-1, mais le fait est que ça n'a rien à voir avec un guillemets simples, et je n'arrive pas à transformer le combo unicode + htmlsymbol en un symbole ascii ou html - dans ma connaissance limitée, c'est pourquoi je cherche de l'aide.

Je serais heureux avec un ascii guillemet « ou »

Le problème ce qui suit est que je suis concerné, il y a d'autres symboles drôles décodées de manière incorrecte. Ci-dessous est un peu python pour reproduire ce que je vois, suivi par les choses que j'ai essayées.

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! 

EDIT:

J'ai essayé d'utiliser un analyseur différent BS:

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() 

qui me donne cette

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

le meilleur décodage de cas semble me donner les mêmes résultats:

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

EDIT 2:

Je cours Mac OS X 4 avec FF 3.0.7 et Firebug

Python 2.5 (wow, ne peut pas croire que je ne le préciser dès le début)

+0

Qu'est-ce que « oups je veux dire ce " signifier? Votre clé de retour arrière ne fonctionnait pas? –

+0

@ S.Lott: Y at-il une touche de retour arrière dans mac? – SilentGhost

+3

@SilentGhost: il y en a un sur chacun de mes macs. Le "oups je veux dire ça" est très, très irritant. Pourquoi ne pas reculer? Qu'est-ce qui est si important de répéter les mêmes caractères dans un balisage différent? C'est marrant"? –

Répondre

8

C'est un sérieux foiré la page, l'encodage sage :-)

Il n'y a vraiment rien mal avec votre approche du tout. Je serais probablement tendance à faire la conversion avant de le transmettre à BeautifulSoup, juste parce que je suis persnickity:

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) 

Dans ce cas, la balise meta de la page est Mentir sur l'encodage. La page est en fait en utf-8 ... L'information de page de Firefox révèle le vrai encodage, et vous pouvez voir ce charset dans les en-têtes de réponse renvoyés par le serveur:

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 vous faites le décodage en utilisant « utf -8' , cela fonctionnera pour vous (ou, au moins, est fait pour moi):

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 
+0

Merci beaucoup pour la réponse informative et douce. Cela fonctionne vraiment pour moi aussi. –

4

il est en fait UTF-8 misencoded comme CP1252:

>>> print u'Oxfam International\xe2€™s report entitled \xe2€œOffside!'.encode('cp1252').decode('utf8') 
Oxfam International’s report entitled “Offside!