web-dev-qa-db-ja.com

BeautifulSoupでUTF-8エンコードされたHTMLをUnicode文字列に正しく解析する方法は?

PythonプログラムでUTF-8でエンコードされたWebページを取得するプログラムを実行しています。BeautifulSoupを使用してHTMLからテキストを抽出します。

ただし、このテキストをファイルに書き込む(またはコンソールに印刷する)と、予期しないエンコーディングで書き込まれます。

サンプルプログラム:

_import urllib2
from BeautifulSoup import BeautifulSoup

# Fetch URL
url = 'http://www.voxnow.de/'
request = urllib2.Request(url)
request.add_header('Accept-Encoding', 'utf-8')

# Response has UTF-8 charset header,
# and HTML body which is UTF-8 encoded
response = urllib2.urlopen(request)

# Parse with BeautifulSoup
soup = BeautifulSoup(response)

# Print title attribute of a <div> which uses umlauts (e.g. können)
print repr(soup.find('div', id='navbutton_account')['title'])
_

これを実行すると結果が得られます:

_# u'Hier k\u0102\u015bnnen Sie sich kostenlos registrieren und / oder einloggen!'
_

しかし、私はPython Unicode文字列が_ö_をWord _können_として _\xf6_ としてレンダリングすることを期待します:

_# u'Hier k\xf6bnnen Sie sich kostenlos registrieren und / oder einloggen!'
_

'fromEncoding'パラメータをBeautifulSoupに渡して、read()およびdecode()responseオブジェクトを試してみましたが、違いがないか、スローされますエラー。

_curl www.voxnow.de | hexdump -C_コマンドを使用すると、Webページが_0xc3 0xb6_文字に対して実際にUTF-8でエンコードされている(つまり、_ö_が含まれている)ことがわかります。

_      20 74 69 74 6c 65 3d 22  48 69 65 72 20 6b c3 b6  | title="Hier k..|
      6e 6e 65 6e 20 53 69 65  20 73 69 63 68 20 6b 6f  |nnen Sie sich ko|
      73 74 65 6e 6c 6f 73 20  72 65 67 69 73 74 72 69  |stenlos registri|
_

Python能力の制限を超えているので、これをさらにデバッグする方法について途方に暮れています。アドバイスはありますか?

26
Christopher Orr

上記で指摘したように、私の質問は基本的に この質問 の複製です。

HTMLコンテンツはそれ自体をUTF-8エンコードとして報告し、1つまたは2つの不正な無効なUTF-8文字を除いて、ほとんどの場合はエンコードされていました。

これは明らかに、どのエンコーディングが使用されているか、およびコンテンツをBeautifulSoupに渡すときに最初にUTF-8としてデコードしようとすると、BeautifulSoupを混乱させます:

soup = BeautifulSoup(response.read().decode('utf-8'))

エラーが発生します:

UnicodeDecodeError: 'utf8' codec can't decode bytes in position 186812-186813: 
                    invalid continuation byte

出力をさらに詳しく見てみると、正しい Ü ではなく、無効なバイトシーケンス0xe3 0x9cとして誤ってエンコードされた文字0xc3 0x9cのインスタンスがありました。 。

その質問の現在の 最高評価の回答 が示唆するように、無効なUTF-8文字は解析中に削除できるため、有効なデータのみがBeautifulSoupに渡されます。

soup = BeautifulSoup(response.read().decode('utf-8', 'ignore'))
28
Christopher Orr

結果をutf-8にエンコードするとうまくいくようです:

print (soup.find('div', id='navbutton_account')['title']).encode('utf-8')

それはもたらす:

Hier können Sie sich kostenlos registrieren und / oder einloggen!
3
Birei