Ответ 1
Я использовал бы html5lib для этого.
При экранировании веб-страницы с использованием python нужно знать кодировку символов страницы. Если вы получите кодировку символов неправильно, чем ваш вывод будет испорчен.
Люди обычно используют некоторые рудиментарные методы для обнаружения кодирования. Они либо используют кодировку из заголовка, либо кодировку, определенную в метатеге, либо используют детектор кодирования (который не заботится о метатегах или заголовки). Используя только один из этих методов, иногда вы не получите тот же результат, что и в браузере.
Браузеры делают это следующим образом:
(Ну... по крайней мере, так я считаю, что большинство браузеров это делают. Документация действительно скудная.)
То, что я ищу, это библиотека, которая может решить набор символов на странице так, как это сделал бы браузер. Я уверен, что я не первый, кому нужно правильное решение для эта проблема.
Согласно Документация Beautiful Soup.
Beautiful Soup пытается в порядке очередности кодирования превратить ваш документ в Юникод:
Я использовал бы html5lib для этого.
Когда вы загружаете файл с urllib или urllib2, вы можете узнать, был ли передан заголовок charset:
fp = urllib2.urlopen(request)
charset = fp.headers.getparam('charset')
Вы можете использовать BeautifulSoup для поиска мета-элемента в HTML:
soup = BeatifulSoup.BeautifulSoup(data)
meta = soup.findAll('meta', {'http-equiv':lambda v:v.lower()=='content-type'})
Если ни один из них не доступен, браузеры обычно возвращаются к пользовательской конфигурации в сочетании с автоматическим обнаружением. Как предлагает rajax, вы можете использовать модуль chardet. Если у вас есть доступная конфигурация пользователя, говорящая вам, что страница должна быть китайской (скажем), вы можете сделать лучше.
Используйте Универсальный детектор кодирования:
>>> import chardet
>>> chardet.detect(urlread("http://google.cn/"))
{'encoding': 'GB2312', 'confidence': 0.99}
Другой вариант - просто использовать wget:
import os
h = os.popen('wget -q -O foo1.txt http://foo.html')
h.close()
s = open('foo1.txt').read()
Кажется, вам нужен гибрид представленных ответов:
<meta>
, используя красивый суп или другой метод.Я честно не верю, что ты найдешь что-нибудь лучшее.
Фактически, если вы читаете далее в FAQ, на который вы ссылаетесь в комментариях к другому ответу, это то, что защищает автор библиотеки детекторов.
Если вы верите в часто задаваемые вопросы, это то, что делают браузеры (по запросу в вашем исходном вопросе), поскольку детектор является портом кода обхода фейджока.
Scrapy загружает страницу и определяет для нее правильную кодировку, в отличие от request.get(url).text или urlopen. Для этого он пытается следовать правилам, подобным браузерам, - это лучшее, что можно сделать, потому что владельцы веб-сайтов имеют стимул заставить свои веб-сайты работать в браузере. Scrapy необходимо принимать заголовки HTTP, теги <meta>
, метки спецификации и различия в именах кодировок в учетной записи.
Удовлетворение контента (chardet, UnicodeDammit) само по себе не является правильным решением, поскольку оно может потерпеть неудачу; он должен использоваться только в качестве последнего средства, когда заголовки или метки <meta>
или BOM недоступны или не содержат никакой информации.
Вам не нужно использовать Scrapy для получения своих функций обнаружения кодирования; они выпускаются (в том числе с некоторыми другими вещами) в отдельной библиотеке под названием w3lib: https://github.com/scrapy/w3lib.
Чтобы получить кодировку страницы и тело юникода, используйте функцию w3lib.encoding.html_to_unicode с резервным предположением на основе контента:
import chardet
from w3lib.encoding import html_to_unicode
def _guess_encoding(data):
return chardet.detect(data).get('encoding')
detected_encoding, html_content_unicode = html_to_unicode(
content_type_header,
html_content_bytes,
default_encoding='utf8',
auto_detect_fun=_guess_encoding,
)
вместо того, чтобы пытаться получить страницу, затем выясняя кодировку, которую будет использовать браузер, почему бы просто не использовать браузер для извлечения страницы и проверить, какую кодировку он использует.
from win32com.client import DispatchWithEvents
import threading
stopEvent=threading.Event()
class EventHandler(object):
def OnDownloadBegin(self):
pass
def waitUntilReady(ie):
"""
copypasted from
http://mail.python.org/pipermail/python-win32/2004-June/002040.html
"""
if ie.ReadyState!=4:
while 1:
print "waiting"
pythoncom.PumpWaitingMessages()
stopEvent.wait(.2)
if stopEvent.isSet() or ie.ReadyState==4:
stopEvent.clear()
break;
ie = DispatchWithEvents("InternetExplorer.Application", EventHandler)
ie.Visible = 0
ie.Navigate('http://kskky.info')
waitUntilReady(ie)
d = ie.Document
print d.CharSet
BeautifulSoup дозирует это с помощью UnicodeDammit: Unicode, Dammit