Pergunta

Problema

Quando screen-scraping uma página web usando um python tem de saber a codificação de caracteres da página. Se você tem a codificação de caracteres errado do que sua saída será confuso.

As pessoas costumam utilizar alguma técnica rudimentar para detectar a codificação. Eles quer usar o conjunto de caracteres a partir do cabeçalho ou o conjunto de caracteres definido na meta tag ou que utilizam uma codificação detector (que não se preocupa com meta tags ou cabeçalhos). Ao usar apenas uma dessas técnicas, às vezes você não vai obter o mesmo resultado que você faria em um navegador.

Navegadores fazê-lo desta maneira:

  • Meta tags sempre tem precedência (ou definição xml)
  • codificação definida no cabeçalho é usado quando não há charset definido em uma meta tag
  • Se a codificação não é definido em tudo, que é tempo para a codificação de detecção.

(Bem ... pelo menos é assim que eu acredito que a maioria dos navegadores fazê-lo. A documentação é muito escassa.)

O que eu estou procurando é uma biblioteca que pode decidir o conjunto de caracteres de uma página a maneira como um navegador seria. eu tenho certeza que não sou o primeiro que precisa de uma solução adequada para este problema.

Solução (eu não tentei ainda ...)

De acordo com a documentação bonito da Sopa .

Beautiful Soup tenta as seguintes codificações, em ordem de prioridade, para transformar o documento em Unicode:

  • Uma codificação você passar em como o fromEncoding argumento para a sopa construtor.
  • Uma codificação descoberto no próprio documento: por exemplo, em uma declaração XML ou (para HTML documentos) uma meta http-equiv tag. Se Bonita Soup encontra este tipo de codificação dentro do documento, que analisa o documento novamente desde o início e dá a nova codificação de uma tentativa. A única exceção é se você especificou explicitamente uma codificação, e que a codificação efectivamente trabalhadas:., Em seguida, ele irá ignorar qualquer codificação que encontra no documento
  • Uma codificação cheirou, olhando para os primeiros bytes do arquivo. Se for detectada uma codificação nesta fase, será um dos UTF-* codificações, EBCDIC ou ASCII.
  • Uma codificando inalado pelo chardet biblioteca, se você tem instalado.
  • UTF-8
  • Windows-1252
Foi útil?

Solução

Gostaria de usar html5lib para isso.

Outras dicas

Quando você baixar um arquivo com urllib ou urllib2, você pode descobrir se um cabeçalho charset foi transmitida:

fp = urllib2.urlopen(request)
charset = fp.headers.getparam('charset')

Você pode usar BeautifulSoup para localizar um elemento meta no HTML:

soup = BeatifulSoup.BeautifulSoup(data)
meta = soup.findAll('meta', {'http-equiv':lambda v:v.lower()=='content-type'})

Se não está disponível, os navegadores normalmente cair de volta à configuração de usuário, combinada com auto-detecção. Como rajax propõe, você poderia usar o módulo chardet. Se você tem a configuração de usuário disponível informando que a página deve ser chinês (digamos), você pode ser capaz de fazer melhor.

Use a Universal Encoding Detector :

>>> import chardet
>>> chardet.detect(urlread("http://google.cn/"))
{'encoding': 'GB2312', 'confidence': 0.99}

A outra opção seria a de wget uso apenas:

  import os
  h = os.popen('wget -q -O foo1.txt http://foo.html')
  h.close()
  s = open('foo1.txt').read()

Parece que você precisa de um híbrido das respostas apresentadas:

  1. Obter a página usando urllib
  2. Encontre etiquetas <meta> usando bela sopa ou outro método
  3. Se não existem meta tags, verifique os cabeçalhos retornados por urllib
  4. Se isso ainda não lhe dar uma resposta, use o detector de codificação universal.

Eu honestamente não acredito que você vai encontrar nada melhor do que isso.

Na verdade, se você ler mais para o FAQ ligado a você nos comentários sobre a outra resposta, que é o que o autor defende biblioteca detector.

Se você acredita que o FAQ, isso é o que os navegadores fazer (tal como solicitado na sua pergunta original) como o detector é um port do código sniffing firefox.

Scrapy download de uma página e detecta uma codificação correto para ele, ao contrário requests.get (url) .text ou urlopen. Para isso ele tenta seguir navegador-como regras - este é o melhor que se pode fazer, porque os proprietários de sites têm incentivo para fazer seus sites trabalhar em um navegador. Scrapy precisa tomar cabeçalhos HTTP, etiquetas <meta>, marcas de lista técnica e as diferenças na codificação de nomes em conta.

adivinhando baseado em conteúdo (chardet, UnicodeDammit) por si só não é uma solução correta, pois pode falhar; ele deve ser usado apenas como um último recurso quando cabeçalhos ou <meta> ou marcas BOM não estão disponíveis ou não fornecem informações.

Você não tem que usar Scrapy para obter as suas funções de detecção de codificação; eles são liberados (entre com algumas outras coisas) em uma biblioteca chamada w3lib separado: https://github.com/scrapy / w3lib .

Para obter codificação de página e uso do corpo unicode w3lib.encoding .html_to_unicode função, com um adivinhando fallback baseado em conteúdo:

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

em vez de tentar obter uma página, em seguida, descobrir o charset do navegador usaria, porque não basta usar um navegador para buscar a página e verificar o que charset ele usa ..

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 dose este com UnicodeDammit: Unicode, Dammit

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top