Как загрузить любую (!) веб-страницу с правильной кодировкой на python?
-
18-09-2019 - |
Вопрос
Проблема
При очистке экрана веб-страницы с помощью python необходимо знать кодировку символов страницы. Если вы неправильно введете кодировку символов, то ваш вывод будет испорчен.
Люди обычно используют какую-то элементарную технику для обнаружения кодировки.Они либо используют кодировку из заголовка, либо кодировку, определенную в мета-теге, либо используют детектор кодирования (который не заботится о мета-тегах или заголовках).Используя только один из этих методов, иногда вы не получите того же результата, что в браузере.
Браузеры делают это следующим образом:
- Мета-теги всегда имеют приоритет (или определение xml)
- Кодировка, определенная в заголовке, используется, когда в мета-теге не задана кодировка
- Если кодировка вообще не определена, то настало время для обнаружения кодировки.
(Нучто ж...по крайней мере, я считаю, что именно так это делают большинство браузеров.Документации действительно мало.)
То, что я ищу, - это библиотека, которая может определять набор символов страницы так же, как это делал бы браузер. Я уверен, что я не первый, кому нужно правильное решение этой проблемы.
Решение (Я это еще не пробовал ...)
Согласно Документация по Прекрасному супу.
Beautiful Soup использует следующие кодировки в порядке приоритета, чтобы перевести ваш документ в Юникод:
- Кодировка, которую вы передаете в качестве аргумента fromEncoding конструктору soup .
- Кодировка, обнаруженная в самом документе:например, в объявлении XML или (для HTML-документов) в метатеге http-equiv.Если Beautiful Soup обнаруживает этот тип кодировки в документе, он снова анализирует документ с самого начала и пробует новую кодировку.Единственное исключение - это если вы явно указали кодировку, и эта кодировка действительно сработала:тогда он проигнорирует любую кодировку, которую найдет в документе.
- Кодировка, обнаруженная при просмотре первых нескольких байтов файла.Если кодировка обнаружена на этом этапе это будет одна из кодировок UTF-*, EBCDIC или ASCII.
- Кодировка, обнаруженная библиотекой chardet , если она у вас установлена.
- UTF-8
- Windows-1252
Решение
Я бы использовал html5lib для этого.
Другие советы
Когда вы загружаете файл с помощью urllib или urllib2, вы можете узнать, был ли передан заголовок кодировки:
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()
Похоже, вам нужен гибрид представленных ответов:
- Извлеките страницу с помощью urllib
- Найти
<meta>
теги с использованием красивого супа или другого метода - Если метатегов не существует, проверьте заголовки, возвращаемые urllib
- Если это все еще не дает вам ответа, воспользуйтесь универсальным детектором кодирования.
Честно говоря, я не верю, что вы найдете что-то лучше этого.
На самом деле, если вы прочтете дальше часто задаваемые вопросы, на которые вы ссылались в комментариях к другому ответу, именно это отстаивает автор detector library.
Если вы верите часто задаваемым вопросам, это то, что делают браузеры (как указано в вашем первоначальном вопросе), поскольку детектор является портом кода отслеживания firefox.
Scrapy загружает страницу и определяет для нее правильную кодировку, в отличие от requests.get(url).text или urlopen.Для этого он пытается следовать правилам, подобным браузерным, - это лучшее, что можно сделать, потому что у владельцев веб-сайтов есть стимул заставить свои веб-сайты работать в браузере.Scrapy должен принимать HTTP-заголовки, <meta>
теги, обозначения спецификаций и различия в кодировках имен при учете.
Угадывание на основе контента (chardet, UnicodeDammit) само по себе не является правильным решением, поскольку оно может привести к сбою;его следует использовать только в качестве последнего средства, когда заголовки или <meta>
или обозначения спецификации недоступны или не содержат никакой информации.
Вам не нужно использовать Scrapy, чтобы получить его функции определения кодировки;они выпущены (среди прочего) в отдельной библиотеке под названием w3lib: https://github.com/scrapy/w3lib.
Чтобы получить кодировку страницы и текст в юникоде, используйте w3lib.encoding.html_to_unicode (кодировка.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 : Юникод, черт возьми