Как загрузить любую (!) веб-страницу с правильной кодировкой на python?

StackOverflow https://stackoverflow.com/questions/1495627

Вопрос

Проблема

При очистке экрана веб-страницы с помощью 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()

Похоже, вам нужен гибрид представленных ответов:

  1. Извлеките страницу с помощью urllib
  2. Найти <meta> теги с использованием красивого супа или другого метода
  3. Если метатегов не существует, проверьте заголовки, возвращаемые urllib
  4. Если это все еще не дает вам ответа, воспользуйтесь универсальным детектором кодирования.

Честно говоря, я не верю, что вы найдете что-то лучше этого.

На самом деле, если вы прочтете дальше часто задаваемые вопросы, на которые вы ссылались в комментариях к другому ответу, именно это отстаивает автор 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 : Юникод, черт возьми

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top