Подтвердить что ты не робот

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

Проблема

При экранировании веб-страницы с использованием python нужно знать кодировку символов страницы. Если вы получите кодировку символов неправильно, чем ваш вывод будет испорчен.

Люди обычно используют некоторые рудиментарные методы для обнаружения кодирования. Они либо используют кодировку из заголовка, либо кодировку, определенную в метатеге, либо используют детектор кодирования (который не заботится о метатегах или заголовки). Используя только один из этих методов, иногда вы не получите тот же результат, что и в браузере.

Браузеры делают это следующим образом:

  • Метатеги всегда имеют приоритет (или определение xml)
  • Кодировка, определенная в заголовке, используется, когда в метатеге нет символа
  • Если кодировка не определена вообще, это время для обнаружения кодирования.

(Ну... по крайней мере, так я считаю, что большинство браузеров это делают. Документация действительно скудная.)

То, что я ищу, это библиотека, которая может решить набор символов на странице так, как это сделал бы браузер. Я уверен, что я не первый, кому нужно правильное решение для эта проблема.

Решение (я еще не пробовал...)

Согласно Документация Beautiful Soup.

Beautiful Soup пытается в порядке очередности кодирования превратить ваш документ в Юникод:

  • Кодировка, которую вы передаете в качестве fromEncoding аргумент супу конструктор.
  • Кодировка, обнаруженная в самом документе: например, в декларации XML или (для HTML-документов) тег META-http-equiv. Если Beautiful Soup находит этот вид кодировки внутри документа, он снова анализирует документ с самого начала и дает новую кодировку. Единственное исключение - если вы явно указали кодировку, и эта кодировка действительно сработала: тогда она будет игнорировать любую кодировку, найденную в документе.
  • Кодирование фыркнуло, просмотрев первые несколько байтов файла. Если обнаружено кодирование на этом этапе он будет одним из Кодировки UTF- *, EBCDIC или ASCII.
  • кодирование, обнюхиваемое чартой если вы его установили.
  • UTF-8
  • Windows-1252
4b9b3361

Ответ 1

Я использовал бы html5lib для этого.

Ответ 2

Когда вы загружаете файл с 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. Если у вас есть доступная конфигурация пользователя, говорящая вам, что страница должна быть китайской (скажем), вы можете сделать лучше.

Ответ 3

Используйте Универсальный детектор кодирования:

>>> 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()

Ответ 4

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

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

Я честно не верю, что ты найдешь что-нибудь лучшее.

Фактически, если вы читаете далее в FAQ, на который вы ссылаетесь в комментариях к другому ответу, это то, что защищает автор библиотеки детекторов.

Если вы верите в часто задаваемые вопросы, это то, что делают браузеры (по запросу в вашем исходном вопросе), поскольку детектор является портом кода обхода фейджока.

Ответ 5

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,
)

Ответ 6

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

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

Ответ 7

BeautifulSoup дозирует это с помощью UnicodeDammit: Unicode, Dammit