1. ホーム
  2. python

[解決済み] PythonでUnicodeからASCIIにエラーなく変換する

2022-04-13 06:22:40

質問

私のコードは、ウェブページをスクレイピングして、それをユニコードに変換しているだけです。

html = urllib.urlopen(link).read()
html.encode("utf8","ignore")
self.response.out.write(html)

しかし、私は UnicodeDecodeError :


Traceback (most recent call last):
  File "/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine/google/appengine/ext/webapp/__init__.py", line 507, in __call__
    handler.get(*groups)
  File "/Users/greg/clounce/main.py", line 55, in get
    html.encode("utf8","ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 2818: ordinal not in range(128)

これは、HTMLのどこかに間違った形式のUnicodeの試みが含まれていることを意味していると思います。 エラーになる代わりに、問題を引き起こしているコードバイトをすべて削除することはできますか?

解決方法は?

2018年最新情報です。

2018年2月現在、以下のような圧縮を使用すると gzip になりました。 かなりポピュラー (Google、YouTube、Yahoo、Wikipedia、Reddit、Stack Overflow、Stack Exchange Networkサイトなどの大規模サイトを含む、全ウェブサイトの約73%が使用しています)。

gzip化されたレスポンスで元の回答のような単純なデコードを行うと、以下のような、またはそれに似たエラーが発生します。

<ブロッククオート

UnicodeDecodeError: 'utf8' コーデックはポジション1のバイト0x8bをデコードできません: 予期しないコードバイトです。

gzpipされた応答をデコードするためには、以下のモジュールを追加する必要があります(Python 3の場合)。

import gzip
import io

Python 2では StringIO の代わりに io

すると、このようにコンテンツをパースして取り出すことができます。

response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resource

このコードはレスポンスを読み、そのバイトをバッファに格納します。その際 gzip モジュールは、バッファを読み取るために GZipFile 関数を使用します。その後、gzipされたファイルを再びバイト単位で読み込んで、最終的に普通に読めるテキストにデコードすることができます。

2010年のオリジナル回答です。

に使用されている実際の値を取得することはできますか? link ?

さらに、通常、ここでこの問題に遭遇するのは、次のような場合です。 .encode() すでにエンコードされているバイト列を そこで、次のようにまずデコードしてみるのもよいでしょう。

html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")

例として

html = '\xa0'
encoded_str = html.encode("utf8")

で失敗します。

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)

ながら。

html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")

エラーなしで成功します。なお、"windows-1252" は、私が . 私はこれを シャルデ で、それが正しいという信頼度は0.5だった! (まあ、1文字長の文字列で与えられたので、何を期待してもいいのですが)あなたはこれを .urlopen().read() を、取得したコンテンツに適用されるものに変更します。

そこに見えるもう一つの問題は .encode() 文字列メソッドは変更された文字列を返し、その場でソースを変更することはありません。だから、ある意味無駄な self.response.out.write(html) htmlはhtml.encodeでエンコードされた文字列ではないので(それが本来の目的であるならば)。

Ignacio が提案したように、ソースのウェブページで read() . MetaタグかレスポンスのContentTypeヘッダーの中にあります。のパラメータとして使用します。 .decode() .

しかし、他の開発者がヘッダやメタ文字セットの宣言が実際のコンテンツと一致しているかどうかを確認する責任を負っているとは考えない方がよいことに注意してください。(これは面倒なことですが、ええ、私は知っているはずです。 でした 以前はその一人でした)。