Domanda

Problema

Quando screen-scraping una pagina web utilizzando python deve sapere la codifica dei caratteri della pagina. Se si ottiene la codifica dei caratteri sbagliato che l'output sarà incasinato.

La gente di solito usano una tecnica rudimentale per rilevare la codifica. Essi o usa il charset nell'intestazione o il set di caratteri definito nel metatag o usano un (che non si preoccupa di meta tag o intestazioni). Utilizzando solo una di queste tecniche, a volte non sarà possibile ottenere lo stesso risultato come si farebbe in un browser.

Browser fare in questo modo:

  • Meta tag ha sempre la precedenza (o definizione XML)
  • Codifica definita nell'intestazione viene utilizzata quando non c'è charset definito un meta tag
  • Se la codifica non è definita affatto, che è tempo per la codifica di rilevamento.

(Beh ... almeno questo è il modo in cui io credo maggior parte dei browser lo fanno. La documentazione è davvero scarsa.)

Quello che sto cercando è una libreria che può decidere il set di caratteri di una pagina nel modo un browser sarebbe. Sono sicuro che io non sono il primo che ha bisogno di una soluzione adeguata per questo problema.

Soluzione (I non hanno ancora provato ...)

Bella documentazione del Soup .

Beautiful Soup cerca le seguenti codifiche, in ordine di priorità, di trasformare il documento in Unicode:

  • Un codifica si passa come il fromEncoding argomento della minestra costruttore.
  • Una codifica scoperto nel documento stesso: per esempio, in una dichiarazione XML o (per i documenti HTML) un http-equiv META tag. Se Beautiful Soup trova questo tipo di codifica all'interno del documento, che analizza il documento di nuovo dall'inizio e conferisce alla nuova codifica una prova. L'unica eccezione è se è stato specificato in modo esplicito una codifica, e che la codifica effettivamente lavorato:. Allora ignorerà qualsiasi codifica che trova nel documento
  • Un codifica annusato, cercando nei primi byte del file. Se viene rilevata una codifica in questa fase, sarà uno dei UTF * codifiche, EBCDIC o ASCII.
  • Un encoding annusò dal chardet biblioteca, se lo avete installato.
  • UTF-8
  • di Windows-1252
È stato utile?

Soluzione

html5lib per questo.

Altri suggerimenti

Quando si scarica un file con urllib o urllib2, è possibile scoprire se un colpo di testa charset è stato trasmesso:

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

È possibile utilizzare BeautifulSoup per individuare un elemento meta nel codice HTML:

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

Se non è disponibile, i browser di solito ripiegare a configurazione utente, in combinazione con auto-rilevazione. Come rajax propone, è possibile utilizzare il modulo chardet. Se si dispone di configurazione utente disponibili che ti dice che la pagina dovrebbe essere cinese (diciamo), si può essere in grado di fare meglio.

Utilizza il universale di codifica Detector :

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

L'altra opzione sarebbe quella di utilizzare solo wget:

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

Sembra che tu abbia bisogno di un ibrido delle risposte presentate:

  1. Scarica la pagina utilizzando urllib
  2. Trova tag <meta> utilizzando bella zuppa o altro metodo
  3. Se non esistono meta tag, controllare le intestazioni restituite da urllib
  4. Se questo ancora non ti dà una risposta, utilizzare il rilevatore di codifica universale.

Onestamente non credo che stai andando a trovare qualcosa di meglio di questo.

In realtà se leggete ulteriormente nella FAQ si è collegato al nei commenti sul altra risposta, questo è ciò che l'autore del rivelatore sostenitori della biblioteca.

Se si ritiene che il FAQ, questo è ciò che i browser fanno (come richiesto nella tua domanda iniziale) come il rivelatore è un porting del codice di sniffing firefox.

Scrapy scarica una pagina e rileva una codifica corretta per esso, a differenza requests.get (url) .text o urlopen. Per fare ciò si cerca di seguire le regole simili a browser - questo è il meglio che si può fare, perché proprietari di siti web hanno incentivo a fare i loro siti web lavorano in un browser. Scrapy ha bisogno di prendere le intestazioni HTTP, tag <meta>, marchi di BOM e le differenze nella codifica nomi in conto.

Content-based indovinare (chardet, UnicodeDammit) di per sé non è una soluzione corretta, come può fallire; esso dovrebbe essere utilizzato solo come ultima risorsa, quando le intestazioni o marchi <meta> o BOM non sono disponibili o non forniscono informazioni.

Non è necessario usare Scrapy per ottenere le sue funzioni di rilevamento di codifica; che vengono rilasciati (tra le altre cose con un po ') in una libreria chiamata w3lib separata: https://github.com/scrapy / w3lib .

Per ottenere pagina la codifica e l'uso del corpo unicode w3lib.encoding .html_to_unicode funzione, con un contenuto a base di indovinare fallback:

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

invece di cercare di ottenere una pagina poi cercare di capire il charset il browser avrebbe usato, perché non basta utilizzare un browser per andare a prendere la pagina e controllare quali charset utilizza ..

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 di questo con UnicodeDammit: Unicode, Dammit

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top