2009-03-10 15 views
5

Używam BeautifulSoup do zeskanowania strony internetowej. Strona internetowa w przeglądarce wygląda dobrze:BeautifulSoup daje mi symbole Unicode + html, zamiast prostego unicode. Czy to błąd, czy nieporozumienie?

Raport Oxfam International pod tytułem "Offside! http://www.coopamerica.org/programs/responsibleshopper/company.cfm?id=271

W szczególności, pojedyncze i podwójne cudzysłowy wyglądać dobrze. Wyglądają raczej na html niż na ascii, choć dziwnie, gdy oglądam źródło w FF3, wydają się być normalne ascii.

Niestety, kiedy złom mam coś takiego

u'Oxfam Międzynarodówki \ xe2 € ™ s raportu zatytułowany \ xe2 € œOffside!

oops, mam na myśli to:

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

strony za meta dane wskazują kodowania ISO-88959-1 ''. Próbowałem różnych kodowań, grałem z funkcjami stron trzecich unicode-> ascii i html-> ascii i patrzyłem na rozbieżność MS/iso-8859-1, ale faktem jest, że ™ nie ma nic wspólnego z pojedynczy cytat i nie mogę zmienić kombinacji Unicode + Htmlsymbol w prawy symbol ascii lub html - w mojej ograniczonej wiedzy, dlatego szukam pomocy.

byłbym szczęśliwy z ascii podwójny cudzysłów „lub”

Problem jest następujący, że jestem zaniepokojony istnieją inne symbole śmieszne dekodowane nieprawidłowo.

\xe2€™ 

Poniżej znajduje się kilka python do odtworzenia tego, co widzę, a następnie rzeczy, które próbowałem.

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! 

Edycja:

Próbowałem użyć innego BS parser:

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

który daje mi ten

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

najlepszy przypadek dekodowania wydaje mi dać takie same wyniki:

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

EDIT 2:

Używam Mac OS X 4 z FF 3.0.7 i Firebug

Python 2.5 (wow, nie mogę uwierzyć, że nie stwierdzają tego od początku)

+0

Co oznacza „oops znaczy to " oznaczać? Czy twój klawisz Backspace nie działał? –

+0

@ S.Lott: czy istnieje klucz Backspace w mac? – SilentGhost

+3

@SilentGhost: jest jeden na każdym z moich mac. "Oops mam na myśli" jest bardzo, bardzo irytujące. Czemu nie wrócić? Co jest tak ważnego w powtarzaniu tych samych znaków w różnych znacznikach? Czy to jest "zabawne"? –

Odpowiedz

8

To jedna poważnie zawiedli strony, kodowanie mądry :-)

Nic naprawdę źle z twoim podejściem w ogóle. Prawdopodobnie mają tendencję do zrobić konwersję przed przekazaniem go do BeautifulSoup, tylko dlatego, że jestem 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) 

W tym przypadku tag strony jest leżącego na temat kodowania. Strona jest faktycznie w UTF-8 ... info strona Firefoksa odsłania prawdziwe kodowanie, i rzeczywiście można zobaczyć ten charset w nagłówki odpowiedzi zwracane przez serwer:

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 

Jeśli do dekodowania przy użyciu UTF -8' , to będzie pracować dla Ciebie (lub, co najmniej, to nie dla mnie):

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

Dziękuję bardzo za informacyjną i łagodną odpowiedź. To też działa dla mnie. –

4

to faktycznie UTF-8 misencoded jak CP1252:

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