web-dev-qa-db-ja.com

UnicodeEncodeError: 'ascii'コーデックは位置20の文字u '\ xa0'をエンコードできません:数が範囲外(128)

私は(異なるサイト上の)異なるWebページから取得したテキストのUnicode文字を扱うのに問題があります。 BeautifulSoupを使っています。

問題は、エラーが常に再現可能ではないことです。それは時々いくつかのページで動作します、そして時々、それはUnicodeEncodeErrorを投げることによって邪魔します。私は考えられるすべてのことを試してみましたが、Unicode関連のエラーを発生させずに一貫して動作するものは何も見つかりませんでした。

問題を引き起こしているコードのセクションの1つを以下に示します。

agent_telno = agent.find('div', 'agent_contact_number')
agent_telno = '' if agent_telno is None else agent_telno.contents[0]
p.agent_info = str(agent_contact + ' ' + agent_telno).strip()

これは上記のスニペットが実行されたときにSOME文字列で生成されたスタックトレースです。

Traceback (most recent call last):
  File "foobar.py", line 792, in <module>
    p.agent_info = str(agent_contact + ' ' + agent_telno).strip()
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 20: ordinal not in range(128)

これは、一部のページ(またはより具体的には、一部のサイトのページ)がエンコードされている可能性があるのに対し、他のページはエンコードされていない可能性があるためです。すべてのサイトはイギリスを拠点としており、イギリスでの消費を目的としたデータを提供しています。そのため、内部化や英語以外の文字で書かれたテキストの処理に関する問題はありません。

私がこの問題を確実に解決することができるようにこれを解決する方法について何か考えがありますか?

1129

Python Unicode HOWTO を読む必要があります。このエラーは 一番最初の例 です。

基本的に、strを使ってUnicodeからエンコードされたtext/bytesに変換するのをやめる。

代わりに、文字列をエンコードするために .encode() を正しく使用してください。

p.agent_info = u' '.join((agent_contact, agent_telno)).encode('utf-8').strip()

または完全にUnicodeで動作します。

1217
agf

これは古典的なPythonのユニコードの痛みのポイントです。次の点を考慮してください。

a = u'bats\u00E0'
print a
 => batsà

これですべて問題ありませんが、str(a)を呼び出した場合はどうなりますか。

str(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)

ああディップ、それは誰にも良いことをするつもりはない!エラーを修正するには、バイトを.encodeで明示的にエンコードし、pythonに使用するコーデックを指定します。

a.encode('utf-8')
 => 'bats\xc3\xa0'
print a.encode('utf-8')
 => batsà

失礼します。

問題は、あなたがstr()を呼ぶとき、あなたがそれに与えたバイトを試みそしてエンコードするためにpythonがデフォルトの文字エンコーディングを使うことです。あなたの場合には、それは時々ユニコード文字の表現です。この問題を解決するには、.encode( 'whatever_unicode')を使用して、与えた文字列をどのように処理するかをpythonに指示する必要があります。ほとんどの場合、あなたはutf-8を使って問題ないはずです。

このトピックに関する優れた解説については、Ned BatchelderのPyCon talkを参照してください。 http://nedbatchelder.com/text/unipain.html

406
Andbdrew

私はシンボルを削除し、次のように文字列として文字列を保持し続けるために私のための優雅な回避策を見つけました:

yourstring = yourstring.encode('ascii', 'ignore').decode('ascii')

無視するオプションの使用は dangerous であることに注意することが重要です。なぜなら、ここで見られるように(convert unicode)、それを使用するコードからUnicode(および国際化)サポートを黙って削除するからです。

>>> u'City: Malmö'.encode('ascii', 'ignore').decode('ascii')
'City: Malm'
194
Max Korolevsky

まあ私はすべてを試したが、周りをグーグルした後、それは助けにはならなかった、私は以下を考え出し、それは助けた。 python 2.7が使われています。

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
136
Ashwin

印刷でさえ失敗する微妙な問題はあなたの環境変数を間違って設定することです。ここでLC_ALLは "C"に設定されています。 Debianでは、彼らはそれを設定することを勧めません: ロケールに関するDebian Wiki

$ echo $LANG
en_US.utf8
$ echo $LC_ALL 
C
$ python -c "print (u'voil\u00e0')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe0' in position 4: ordinal not in range(128)
$ export LC_ALL='en_US.utf8'
$ python -c "print (u'voil\u00e0')"
voilà
$ unset LC_ALL
$ python -c "print (u'voil\u00e0')"
voilà
80
maxpolk

私は実際に私のほとんどの場合、それらの文字を削除するだけの方がはるかに簡単であることがわかりました。

s = mystring.decode('ascii', 'ignore')
25
Phil LaNasa

私にとって、うまくいったのは次のとおりです。

BeautifulSoup(html_text,from_encoding="utf-8")

これが誰かに役立つことを願っています。

25
Animesh

これを解決してみてください

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
19
Joseph Daudi

問題は、あなたがUnicode文字を印刷しようとしていることですが、あなたの端末はそれをサポートしていません。

language-pack-enパッケージをインストールしてみてください。

Sudo apt-get install language-pack-en

サポートされているすべてのパッケージ(Pythonを含む)の英語翻訳データの更新を提供します。必要に応じて別の言語パッケージをインストールします(印刷しようとしている文字によって異なります)。

Linuxディストリビューションによっては、デフォルトの英語ロケールが正しく設定されていることを確認するために必要です(したがって、Unicode文字はShell/terminalで処理できます)。手動で設定するよりも、インストールする方が簡単なことがあります。

それからコードを書くとき、あなたがあなたのコードで正しいエンコーディングを使うことを確認してください。

例えば:

open(foo, encoding='utf-8')

それでも問題が解決しない場合は、次のようにシステム設定をもう一度確認してください。

  • あなたのロケールファイル(/etc/default/locale)。

    LANG="en_US.UTF-8"
    LC_ALL="en_US.UTF-8"
    

    または

    LC_ALL=C.UTF-8
    LANG=C.UTF-8
    
  • シェルのLANG / LC_CTYPE の値。

  • 以下の方法で、シェルがサポートしているロケールを確認してください。

    locale -a | grep "UTF-8"
    

新しいVMで問題と解決策を実証する。

  1. VMを初期化して準備します(例: vagrant を使用)。

    vagrant init ubuntu/trusty64; vagrant up; vagrant ssh
    

    利用可能なUbuntuボックス を見てください。

  2. Unicode文字(のような商標記号など)を印刷する:

    $ python -c 'print(u"\u2122");'
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
    UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 0: ordinal not in range(128)
    
  3. language-pack-enをインストールします。

    $ Sudo apt-get -y install language-pack-en
    The following extra packages will be installed:
      language-pack-en-base
    Generating locales...
      en_GB.UTF-8... /usr/sbin/locale-gen: done
    Generation complete.
    
  4. 今問題は解決されるべきです:

    $ python -c 'print(u"\u2122");'
    ™
    
  5. それ以外の場合は、次のコマンドを試してください。

    $ LC_ALL=C.UTF-8 python -c 'print(u"\u2122");'
    ™
    
17
kenorb

スクリプトの先頭に(または2行目として)下に行を追加します。

# -*- coding: utf-8 -*-

それがpythonのソースコードエンコーディングの定義です。 PEP 263 の詳細情報。

16
Andriy Ivaneyko

これが、他のいわゆる「コップアウト」の答えのまとめです。抗議行動がここで表明されているにもかかわらず、単に面倒な文字や文字列を捨てるのが良い解決策である状況があります。

def safeStr(obj):
    try: return str(obj)
    except UnicodeEncodeError:
        return obj.encode('ascii', 'ignore').decode('ascii')
    except: return ""

それをテストする:

if __== '__main__': 
    print safeStr( 1 ) 
    print safeStr( "test" ) 
    print u'98\xb0'
    print safeStr( u'98\xb0' )

結果:

1
test
98°
98

提案:代わりにこの関数にtoAsciiという名前を付けたいと思うかもしれませんか?それは好みの問題です。

これはPython 2用に書かれました。 Python 3の場合、bytes(obj,"ascii")ではなくstr(obj)を使用することをお勧めします。まだテストしていませんが、ある時点で回答を修正します。

13
BuvinJ

シェルで:

  1. 次のコマンドでサポートされているUTF-8ロケールを見つけます。

    locale -a | grep "UTF-8"
    
  2. スクリプトを実行する前にエクスポートしてください。

    export LC_ALL=$(locale -a | grep UTF-8)
    

    手動で

    export LC_ALL=C.UTF-8
    
  3. 特殊文字を印刷してテストします。

    python -c 'print(u"\u2122");'
    

上記のUbuntuでテスト済み。

10
kenorb

私はいつも以下のコードをpythonファイルの最初の2行に入れます。

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
7
Pereira

単純なヘルパー関数が見つかりました ここ

def safe_unicode(obj, *args):
    """ return the unicode representation of obj """
    try:
        return unicode(obj, *args)
    except UnicodeDecodeError:
        # obj is byte string
        ascii_text = str(obj).encode('string_escape')
        return unicode(ascii_text)

def safe_str(obj):
    """ return the byte string representation of obj """
    try:
        return str(obj)
    except UnicodeEncodeError:
        # obj is unicode
        return unicode(obj).encode('unicode_escape')

単に変数encodeに追加する( 'utf-8')

agent_contact.encode('utf-8')
4

以下の解決策は私のために働いた、ちょうど追加

"文字列"

私の文字列の前に(Unicodeとして文字列を表します)。

result_html = result.to_html(col_space=1, index=False, justify={'right'})

text = u"""
<html>
<body>
<p>
Hello all, <br>
<br>
Here's weekly summary report.  Let me know if you have any questions. <br>
<br>
Data Summary <br>
<br>
<br>
{0}
</p>
<p>Thanks,</p>
<p>Data Team</p>
</body></html>
""".format(result_html)

私はちょうど以下を使いました:

import unicodedata
message = unicodedata.normalize("NFKD", message)

それについてドキュメントが何を言っているかチェックしてください。

unicodedata.normalize(form、unistr)Unicode文字列unistrのための正規形formを返します。 formの有効値は、「NFC」、「NFKC」、「NFD」、および「NFKD」です。

Unicode規格では、正規の等価性と互換性の等価性の定義に基づいて、Unicode文字列のさまざまな正規化形式が定義されています。 Unicodeでは、いくつかの文字をさまざまな方法で表現できます。たとえば、文字U + 00C7(ローマ字大文字CとCEDILLA)は、シーケンスU + 0043(ラテン大文字C)U + 0327(COMBINING CEDILLA)と表現することもできます。

各文字には、正規形Cと正規形Dの2つの正規形があります。正規形D(NFD)は、標準分解とも呼ばれ、各文字をその分解形に変換します。正規形C(NFC)は、最初に正規分解を適用してから、事前に結合された文字をもう一度構成します。

これら2つの形式に加えて、互換性の同等性に基づく2つの追加の標準形式があります。 Unicodeでは、通常他の文字と統合される特定の文字がサポートされています。たとえば、U + 2160(ROMAN NUMERAL ONE)は、実際にはU + 0049(ラテン大文字L)と同じものです。ただし、既存の文字セットとの互換性のためにUnicodeでサポートされています(例:gb2312)。

正規形KD(NFKD)は互換性分解を適用するでしょう、すなわちすべての互換性文字をそれらの同等物で置き換えます。正規形KC(NFKC)は最初に互換性分解を適用し、続いて標準的な構成を適用します。

2つのUnicode文字列が正規化されていて、読者には同じに見えても、一方に結合文字があり、もう一方にそうでない場合、それらは等しく比較されない場合があります。

私のためにそれを解決します。シンプルで簡単.

3
Drag0

ターミナルを開いて以下のコマンドを実行してください。

export LC_ALL="en_US.UTF-8"

ローカライズされたフィクスチャを使ってDjangoでmanage.py migrateを実行すると、このエラーが発生しました。

私達のソースは# -*- coding: utf-8 -*-宣言を含んでいました、MySQLはutf8のために正しく構成されました、そして、Ubuntuは適切な言語パックと/etc/default/localeの値を持っていました。

問題は、Djangoコンテナ(我々はdockerを使用しています)にLANG env varがないということです。

マイグレーションを再実行する前にLANGen_US.UTF-8に設定し、コンテナーを再始動することで問題を解決しました。

2
followben

私はちょうどこの問題を抱えていた、そしてグーグルはここに私を導いた、それでここに一般的な解決策を追加するために、これは私のために働いたものである:

# 'value' contains the problematic data
unic = u''
unic += value
value = unic

Nedの発表 を読んだ後、私はこの考えを持っていました。

しかし、なぜこれが機能するのかを完全に理解しているとは言いません。だから誰かがこの答えを編集したり説明のためにコメントを入れたりすることができれば私はそれをいただければ幸いです。

1
pepoluan

これは少なくともPython 3で動作します…

Python 3

時々エラーは環境変数にあり、そうエンコードすることにあります

import os
import locale
os.environ["PYTHONIOENCODING"] = "utf-8"
myLocale=locale.setlocale(category=locale.LC_ALL, locale="en_GB.UTF-8")
... 
print(myText.encode('utf-8', errors='ignore'))

エラーはエンコード時に無視されます。

0
hhh

ここでの多くの回答(@agfや@Andbdrewなど)は、OPの質問の最も直接的な側面に既に対処しています。

しかし、私はほとんど無視されている微妙で重要な側面があり、Pythonでエンコーディングの意味を理解しようとしている間に私のように終わったすべての人にとって非常に重要であると思います:Python 2 vs Python 3文字表現の管理は大きく異なります。バージョンを意識せずにPythonのエンコーディングについて読んでいる人々と関係があるので、大きな混乱が生じているように感じます。

OPの問題の根本原因を理解することに興味がある人は、まず Spolskyの 文字表現とUnicodeの概要を読んでから Batchelder Python 2およびPython 3.のUnicode.

変数をstr(variable)に変換しないようにしてください。時々、それは問題を引き起こすかもしれません。

避けるべき簡単なヒント:

try: 
    data=str(data)
except:
    data = str(data)

上記の例はEncode erroも解決します。

0
sam ruben

packet_data = "This is data"のようなものがある場合は、packet_dataを初期化した直後の次の行でこれを行います。

unic = u''
packet_data = unic
0
Nandan Kulkarni

Python 3.0以降にアップデートしてください。 Pythonエディタで次のことを試してください。

locale-gen en_US.UTF-8
export LANG=en_US.UTF-8 LANGUAGE=en_US.en
LC_ALL=en_US.UTF-8

これはシステムのデフォルトロケールエンコーディングをUTF-8フォーマットに設定します。

もっと読むことができます ここPEP 538 - レガシーCロケールをUTF-8ベースのロケールに強制変換する

0
ZF007

これはpython 2.7に役立ちます

import sys
reload(sys)   
sys.setdefaultencoding('utf-8')

これはsys.setdefaultencoding()を再び有効にするのを助けます

0
Edward Okech

私はUnicode文字をstdoutに出力しようとしていましたが、printではなくsys.stdout.writeを使っていました。

BeautifulSoup自身のドキュメンテーションから 、私はコーデックライブラリでこれを解決しました:

import sys
import codecs

def main(fIn, fOut):
    soup = BeautifulSoup(fIn)
    # Do processing, with data including non-ASCII characters
    fOut.write(unicode(soup))

if __== '__main__':
    with (sys.stdin) as fIn: # Don't think we need codecs.getreader here
        with codecs.getwriter('utf-8')(sys.stdout) as fOut:
            main(fIn, fOut)
0
palswim