BeautifulSoup дает мне символы Юникод + HTML, а не прямой Юникод. Это ошибка или недоразумение? - PullRequest
5 голосов
/ 10 марта 2009

Я использую BeautifulSoup для чистки сайта. Страница веб-сайта хорошо отображается в моем браузере:

Отчет Oxfam International под названием «Офсайд! http://www.coopamerica.org/programs/responsibleshopper/company.cfm?id=271

В частности, одинарные и двойные кавычки выглядят хорошо. Они выглядят как символы html, а не как ascii, хотя странно, когда я смотрю на источник в FF3, они кажутся нормальными ascii.

К сожалению, когда я чищу, я получаю что-то вроде этого

Отчет u'Oxfam International \ xe2 € озаглавленный \ xe2 € -Offside!

Упс, я имею в виду это:

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

Метаданные страницы обозначают кодировку iso-88959-1. Я пробовал разные кодировки, играл с функциями сторонних производителей unicode-> ascii и html-> ascii и смотрел на несоответствие MS / iso-8859-1, но факт в том, что ™ не имеет ничего общего с одиночная кавычка, и я не могу превратить комбо unicode + htmlsymbol в правильный символ ascii или html - насколько мне известно, поэтому я и обращаюсь за помощью.

Я был бы счастлив с двойными кавычками ascii, "или"

Проблема в том, что я обеспокоен тем, что есть другие забавные символы, декодированные неправильно.

\xe2€™

Ниже приведен какой-то питон, воспроизводящий то, что я вижу, и то, что я пробовал.

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:

Я пытался использовать другой парсер 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()

, что дает мне это

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

лучший вариант декодирования, похоже, дает мне те же результаты:

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

РЕДАКТИРОВАТЬ 2:

Я использую Mac OS X 4 с FF 3.0.7 и Firebug

Python 2.5 (вау, не могу поверить, я не утверждал это с самого начала)

Ответы [ 2 ]

8 голосов
/ 10 марта 2009

Это одна серьезно испорченная страница в кодировке: -)

Нет ничего плохого в вашем подходе. Я, вероятно, предпочел бы сделать преобразование перед передачей его BeautifulSoup, просто потому что я привередлив:

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)

В этом случае метатег страницы лжет о кодировке. На самом деле страница находится в utf-8 ... Информация страницы Firefox показывает реальную кодировку, и вы действительно можете увидеть эту кодировку в заголовках ответов, возвращаемых сервером:

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

Если вы выполняете декодирование с использованием 'utf-8', оно будет работать для вас (или, по крайней мере, для меня):

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
4 голосов
/ 10 марта 2009

Это на самом деле UTF-8, неправильно закодированный как CP1252:

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