Frage

Problem

Wenn Screen-Scraping eine Webseite mit Python man die Zeichencodierung der Seite zu wissen hat. Wenn Sie die Zeichencodierung falsch als Ihr Ausgang wird erhalten vermasselt.

Die Menschen in der Regel einige rudimentäre Technik verwenden, um die Codierung zu erkennen. Sie entweder den charset aus dem Header oder den charset im Meta-Tag definiert, oder sie verwenden, um einen Codierung Detektor (die nicht über Meta-Tags oder Header Pflege). Durch die Verwendung von nur einer dieser Techniken, manchmal werden Sie nicht das gleiche Ergebnis, wie man es in einem Browser.

Browser tut es so aus:

  • Meta-Tags immer Vorrang (oder XML-Definition)
  • Codierung im Header definiert wird verwendet, wenn es keine charset in einem Meta-Tag
  • definiert ist
  • Wenn die Codierung nicht definiert ist, als es an der Zeit für die Codierung von Detektion ist.

(Na ja ... zumindest das ist die Art, wie ich die meisten Browser glauben tun es. Dokumentation wirklich knapp ist.)

Was ich suche ist eine Bibliothek, die den Zeichensatz einer Seite die Möglichkeit, einen Browser entscheiden würde. Ich bin sicher, ich bin nicht der erste, der eine richtige Lösung muss dieses Problem.

Lösung (ich habe es noch nicht probiert ...)

Nach Schöne Suppe in der Dokumentation .

Schöne Suppe versucht folgende Codierungen, in der Reihenfolge ihrer Priorität, Ihr Dokument in Unicode zu aktivieren:

  • Eine Codierung Sie passieren in der als fromEncoding Argument für die Suppe Konstruktor.
  • Eine Codierung im Dokument entdeckte selbst: zum Beispiel in einer XML-Deklaration oder (für HTML-Dokumente) einen http-equiv META-Tag. Wenn schöne Suppe findet diese Art der Codierung innerhalb des Dokuments, analysiert er das Dokument erneut von Anfang an und gibt die neuen einen Versuch kodiert. Die einzige Ausnahme ist, wenn Sie explizit eine Codierung angegeben ist, und dass die Kodierung tatsächlich gearbeitet. Dann wird es jede Codierung ignoriert es im Dokument findet
  • Eine Codierung durch einen Blick auf die ersten paar Bytes der Datei schnupperte. Wenn eine Codierung erfaßt wird zu diesem Zeitpunkt wird es eine der sein UTF- * Codierungen, EBCDIC oder ASCII.
  • Ein Codierung durch die chardet roch Bibliothek, wenn Sie es installiert haben.
  • UTF-8
  • Fenster-1252
War es hilfreich?

Lösung

Ich würde verwenden html5lib für diese.

Andere Tipps

Wenn Sie eine Datei mit urllib oder urllib2 herunterladen, können Sie festlegen, ob ein charset Header herausfinden, übertragen wurde:

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

Sie können BeautifulSoup verwenden, um ein Meta-Element im HTML zu finden:

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

Wenn keine vorhanden ist, Browser Regel fällt zurück in der Benutzerkonfiguration, kombiniert mit automatischer Erkennung. Wie rajax schlägt, können Sie das chardet Modul verwenden. Wenn Sie Benutzerkonfiguration zur Verfügung haben Sie sagen, dass die Seite Chinese sein sollte (sagen wir), können Sie in der Lage sein, besser zu machen.

Mit der Universal-Encoding-Detektor :

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

Die andere Option wäre nur wget zu verwenden:

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

Es scheint, wie Sie ein Hybrid aus den Antworten benötigen dargestellt:

  1. Fetch die Seite mit urllib
  2. Finden <meta> Tags mit schönen Suppe oder eine andere Methode
  3. Wenn keine Meta-Tags vorhanden sind, überprüfen Sie die Header von urllib zurückgegeben
  4. Wenn das immer noch nicht, dass Sie eine Antwort nicht geben, verwenden Sie den Universal-Codierung Detektor.

ich ehrlich gesagt nicht glaube, dass Sie etwas zu finden, besser als das gehen.

In der Tat, wenn Sie weiter in die FAQ lesen Sie in den Kommentaren auf der anderen Antwort verknüpft ist, das ist, was der Autor des Detektor Bibliothek befürwortet.

Wenn Sie die häufig gestellten Fragen glauben, das ist, was der Browser tun (wie in Ihrer ursprünglichen Frage angefordert) als der Detektor ein Port des Firefox-Sniffing-Code ist.

Scrapy lädt eine Seite und erkennt eine korrekte Codierung für sie, im Gegensatz zu requests.get (url) .text oder urlopen. Um dies zu tun versucht es Browser-ähnliche Regeln zu folgen - das ist das Beste, was man tun, weil Website-Besitzer Anreiz hat, ihre Webseiten in einem Browser zu arbeiten. Scrapy muss HTTP-Header übernehmen, <meta> Tags, BOM Marken und Unterschiede bei der Codierung Namen in Rechnung.

Content-basierte Erraten (chardet, UnicodeDammit) allein ist keine richtige Lösung, da sie versagen können; es sollte nur als letztes Mittel eingesetzt werden, wenn Kopf- oder <meta> oder BOM Marken nicht verfügbar sind oder keine Informationen zur Verfügung.

Sie müssen Scrapy nicht verwenden, um seine Codierung Erkennungsfunktionen zu erhalten; sie freigegeben werden (unter mit einigen anderen Sachen) in einer separaten Bibliothek namens w3lib: https://github.com/scrapy / w3lib .

Zur Seite Codierung und Unicode Körper Verwendung erhalten w3lib.encoding .html_to_unicode Funktion, mit einem inhaltsbasierten erraten Rückfall:

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

statt, eine Seite zu bekommen versuchen dann die charset herauszufinden, der Browser verwenden würde, warum nicht nur einen Browser verwenden, um die Seite zu holen und überprüfen, was charset verwendet es ..

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 Dosis dies mit UnicodeDammit: Unicode, Dammit

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top