35

問題

Python を使用して Web ページのスクリーン スクレイピングを行う場合、ページの文字エンコーディングを知る必要があります。文字エンコーディングが間違っていると、出力がめちゃくちゃになります。

人々は通常、いくつかの基本的な技術を使用してエンコーディングを検出します。ヘッダーの文字セットまたはメタ タグで定義された文字セットを使用するか、エンコーディング検出器(メタ タグやヘッダーを気にしない) を使用します。これらの手法を 1 つだけ使用すると、ブラウザーで行った場合と同じ結果が得られない場合があります。

ブラウザは次のようにします。

  • メタ タグは常に優先されます (または xml 定義)。
  • メタタグに文字セットが定義されていない場合、ヘッダーに定義されたエンコーディングが使用されます
  • エンコーディングがまったく定義されていない場合は、エンコーディング検出の時間です。

(うーん...少なくとも、ほとんどのブラウザーがそうしていると私は信じています。ドキュメントは本当に不足しています。)

私が探しているのは、ブラウザが行う方法でページの文字セットを決定できるライブラリです。この問題に対する適切な解決策を必要とするのは、私が初めてではないと確信しています。

解決策(まだ試していません...)

Beautiful Soup のドキュメントによると.

Beautiful Soup は、ドキュメントを Unicode に変換するために、次のエンコーディングを優先順に試します。

  • スープ コンストラクターに fromEncoding 引数として渡すエンコーディング。
  • ドキュメント自体で検出されたエンコーディング: たとえば、XML 宣言または (HTML ドキュメントの場合) http-equiv META タグなど。Beautiful Soup がドキュメント内でこの種のエンコーディングを検出すると、ドキュメントを最初から再度解析し、新しいエンコーディングを試します。唯一の例外は、エンコーディングを明示的に指定し、そのエンコーディングが実際に機能した場合です。その場合、ドキュメント内で見つかったエンコーディングはすべて無視されます。
  • ファイルの最初の数バイトを調べることによってスニッフィングされたエンコーディング。この段階でエンコーディングが検出された場合、それは UTF-* エンコーディング、EBCDIC、または ASCII のいずれかになります。
  • インストールされている場合は、chardet ライブラリによってスニッフィングされたエンコーディング。
  • UTF-8
  • Windows-1252
4

7 に答える 7

37

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 モジュールを使用できます。ページが中国語である必要があることを示すユーザー構成が利用可能な場合 (たとえば)、より適切に実行できる可能性があります。

于 2009-09-30T01:04:36.460 に答える
15

Universal Encoding Detectorを使用します。

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

もう 1 つのオプションは、wget を使用することです。

  import os
  h = os.popen('wget -q -O foo1.txt http://foo.html')
  h.close()
  s = open('foo1.txt').read()
于 2009-09-30T00:44:15.887 に答える
4

提示された回答のハイブリッドが必要なようです:

  1. urllib を使用してページをフェッチする
  2. <meta>綺麗なスープなどでタグを探す
  3. メタ タグが存在しない場合は、urllib によって返されるヘッダーを確認します。
  4. それでも答えが得られない場合は、ユニバーサル エンコーディング検出器を使用してください。

正直なところ、それ以上のものが見つかるとは思えません。

実際、他の回答のコメントでリンクした FAQ をさらに読むと、それが検出器ライブラリの作成者が主張していることです。

FAQを信じるなら、検出器はfirefoxスニッフィングコードのポートであるため、これはブラウザが行うことです(元の質問で要求されたとおり)。

于 2009-10-09T16:34:22.850 に答える
3

これにはhtml5libを使用します。

于 2013-03-18T16:31:10.620 に答える
1

BeautifulSoup はこれを UnicodeDammit で処理します: Unicode, Dammit

于 2012-03-18T08:05:33.937 に答える
1

ページを取得しようとする代わりに、ブラウザが使用する文字セットを把握するのではなく、ブラウザを使用してページを取得し、使用する文字セットを確認してください..

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
于 2009-09-30T18:37:16.203 に答える