Ответ 1
Вы проверили это?
Как загрузить любую (!) веб-страницу с правильной кодировкой в python?
Я немного удивлен, что так сложно получить кодировку веб-страницы с Python. Я пропустил путь? HTTPMessage имеет множество функций, но не это.
>>> google = urllib2.urlopen('http://www.google.com/')
>>> google.headers.gettype()
'text/html'
>>> google.headers.getencoding()
'7bit'
>>> google.headers.getcharset()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: HTTPMessage instance has no attribute 'getcharset'
Итак, вы должны получить заголовок и разделить его. Дважды.
>>> google = urllib2.urlopen('http://www.google.com/')
>>> charset = 'ISO-8859-1'
>>> contenttype = google.headers.getheader('Content-Type', '')
>>> if ';' in contenttype:
... charset = contenttype.split(';')[1].split('=')[1]
>>> charset
'ISO-8859-1'
Это удивительное количество шагов для такой основной функции. Я что-то пропустил?
Вы проверили это?
Как загрузить любую (!) веб-страницу с правильной кодировкой в python?
Я провел некоторое исследование и придумал это решение:
response = urllib.request.urlopen(url)
encoding = response.headers.get_content_charset()
Вот как я это сделал бы в Python 3. Я не тестировал его в Python 2, но я предполагаю, что вам придется использовать urllib2.request
вместо urllib.request
.
Вот как это работает, поскольку официальная документация на Python не очень хорошо объясняет это: результат urlopen
- это < объект href= "https://docs.python.org/3/library/http.client.html#httpresponse-objects" rel= "nofollow" > http.client.HTTPResponse
. Свойством headers
этого объекта является объект http.client.HTTPMessage
, который, согласно документации, "реализуется с помощью email.message.Message
class ", который имеет метод get_content_charset
, который пытается определить и вернуть набор символов ответа.
По умолчанию этот метод возвращает None
, если он не может определить набор символов, но вы можете переопределить это поведение, передав параметр failobj
:
encoding = response.headers.get_content_charset(failobj="utf-8")
Вы ничего не пропустили. Он делает правильные вещи - кодирование ответа HTTP является подразделением Content-Type.
Обратите внимание, что некоторые страницы могут отправлять только Content-Type: text/html
, а затем установить кодировку с помощью <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- что уродливое взломать хотя (со стороны автора страницы) и не слишком распространено.
Я бы пошел с chardet Универсальный детектор кодирования.
>>> import urllib
>>> urlread = lambda url: urllib.urlopen(url).read()
>>> import chardet
>>> chardet.detect(urlread("http://google.cn/"))
{'encoding': 'GB2312', 'confidence': 0.99}
Вы правы, но ваш подход не удался для страниц, где charset объявлен в теге meta
или вообще не объявлен.
Если вы посмотрите ближе к источникам Chardet, у него есть модули charsetprober/charsetgroupprober
, которые прекрасно справляются с этой проблемой.