Python에서 오류없이 유니 코드를 ASCII로 변환


178

내 코드는 웹 페이지를 긁은 다음 유니 코드로 변환합니다.

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에 어딘가에 유니 코드에서 잘못 구성된 시도가 포함되어 있다고 가정합니다. 오류를 발생시키는 대신 문제를 일으키는 코드 바이트를 삭제할 수 있습니까?


2
중요한 문자가 버려지면 오류라고 생각합니다! (또한 질문은 어디에 있습니까?)
— Arafangion

웹 페이지에 "휴식 공간 없음"이 발생한 것 같습니까? c2바이트 가 선행 되거나 디코드 오류가 발생합니다. hexutf8.com/?q=C2A0
— jar

답변:


105

2018 업데이트 :

2018 년 2 월 현재와 같은 압축 사용 gzip이 인기를 얻었습니다 (Google, YouTube, Yahoo, Wikipedia, Reddit, Stack Overflow 및 Stack Exchange Network 사이트와 같은 대규모 사이트를 포함한 모든 웹 사이트의 약 73 % 가 압축 사용).
응답이 gzipped 인 원래 답변과 같이 간단한 디코딩을 수행하면 다음과 유사한 오류가 발생합니다.

UnicodeDecodeError : 'utf8'코덱이 위치 1에서 바이트 0x8b를 디코딩 할 수 없습니다. 예기치 않은 코드 바이트

gzpipped 응답을 디코딩하려면 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기능. 그 후, zip으로 압축 된 파일을 다시 바이트 단위로 읽고 결국 읽을 수있는 텍스트로 디코딩 할 수 있습니다.

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"는 제가 예제 로 사용한 것 입니다. 나는 chardet 에서 이것을 얻었고 그것이 옳다 는 0.5 자신감을 가지고있었습니다! (자, 1- 문자 길이 문자열로 주어진 것처럼, 당신은 무엇을 기대합니까?) 당신이 .urlopen().read()검색 한 컨텐츠에 적용되는 것에서 리턴 된 바이트 문자열의 인코딩으로 변경해야 합니다.

내가 본 또 다른 문제는 .encode()문자열 메서드가 수정 된 문자열을 반환하고 소스를 수정하지 않는다는 것입니다. 따라서 self.response.out.write(html)html이 html.encode의 인코딩 된 문자열이 아니기 때문에 소용 이 없습니다 (원래 목표였던 경우).

Ignacio가 제안한 것처럼 소스 웹 페이지에서에서 반환 된 문자열의 실제 인코딩을 확인하십시오 read(). 메타 태그 중 하나 또는 응답의 ContentType 헤더에 있습니다. 그런 다음의 매개 변수로 사용하십시오 .decode().

그러나 다른 개발자가 헤더 및 / 또는 메타 문자 집합 선언이 실제 내용과 일치하는지 확인할 책임이 있다고 가정해서는 안됩니다. (피타 어느, 그래, 내가 알아야 할, 나는 이었다 전에 그 중 하나).


1
귀하의 예에서 나는 당신이 마지막 줄을 의미한다고 생각합니다 encoded_str = decoded_str.encode("utf8")
— Ajith Antony

1
Python 2.7.15에서 시도했지만이 메시지가 나타납니다 raise IOError, 'Not a gzipped file'. 내가 한 잘못은 무엇입니까?
— 김 현 - 근

222
>>> u'aあä'.encode('ascii', 'ignore')
'a'

meta응답 또는 Content-Type헤더 의 해당 태그에있는 문자 세트를 사용하여 돌아온 문자열을 디코딩 한 다음 인코딩하십시오.

이 메소드 encode(encoding, errors)는 오류에 대한 사용자 정의 핸들러를 승인합니다. 이외의 기본값 ignore은 다음과 같습니다.

>>> u'aあä'.encode('ascii', 'replace')
b'a??'
>>> u'aあä'.encode('ascii', 'xmlcharrefreplace')
b'a&#12354;&#228;'
>>> u'aあä'.encode('ascii', 'backslashreplace')
b'a\\u3042\\xe4'

https://docs.python.org/3/library/stdtypes.html#str.encode를 참조 하십시오.


119

Ignacio Vazquez-Abrams의 답변에 대한 확장으로

>>> u'aあä'.encode('ascii', 'ignore')
'a'

문자에서 악센트를 제거하고 기본 양식을 인쇄하는 것이 때때로 바람직합니다. 이것은 달성 할 수 있습니다

>>> import unicodedata
>>> unicodedata.normalize('NFKD', u'aあä').encode('ascii', 'ignore')
'aa'

다른 문자 (예 : 구두점)를 가장 가까운 문자로 변환 할 수도 있습니다. 예를 들어 인코딩 할 때 RIGHT SINGLE QUOTATION MARK 유니 코드 문자가 ASCII APOSTROPHE로 변환되지 않습니다.

>>> print u'\u2019'
’
>>> unicodedata.name(u'\u2019')
'RIGHT SINGLE QUOTATION MARK'
>>> u'\u2019'.encode('ascii', 'ignore')
''
# Note we get an empty string back
>>> u'\u2019'.replace(u'\u2019', u'\'').encode('ascii', 'ignore')
"'"

이것을 달성하는 더 효율적인 방법이 있지만. 자세한 내용은이 질문을 참조하십시오. Python의 "이 유니 코드에 가장 적합한 ASCII"데이터베이스는 어디에 있습니까?


4
둘 다 요청 된 질문을 해결하는 데 도움이되었으며, 질문과 관련된 문제를 해결하는 데 실용적입니다. 이것은 이런 종류의 질문에 대한 모델 답변입니다.
— shanusmagnus

96

unidecode를 사용하십시오 -이상한 문자를 즉시 ​​ASCII로 변환하고 중국어를 음성 ASCII로 변환합니다.

$ pip install unidecode

그때:

>>> from unidecode import unidecode
>>> unidecode(u'北京')
'Bei Jing'
>>> unidecode(u'Škoda')
'Skoda'

3
halle-freakin-lujah-시간이 지나면 저에게 도움이되는 답변을 찾았습니다
— Aurielle Perlmann

10
재미있는 가치를 추구했습니다. 이것은 강조된 모든 언어의 단어를 엉망으로 만듭니다. Škoda는 Skoda가 아닙니다. 스코다는 아마도 장어와 호버 크래프트로 심한 것을 의미합니다.
— Sylvain

1
나는 지금까지 며칠 동안 인터넷을 수색 해 왔습니다 .... 감사합니다, 정말 감사합니다
— Stephen

23

모든 프로젝트에서이 도우미 기능을 사용합니다. 유니 코드를 변환 할 수 없으면 무시합니다. 이것은 장고 라이브러리에 연결되어 있지만 약간의 연구만으로도 우회 할 수 있습니다.

from django.utils import encoding

def convert_unicode_to_string(x):
    """
    >>> convert_unicode_to_string(u'ni\xf1era')
    'niera'
    """
    return encoding.smart_str(x, encoding='ascii', errors='ignore')

이것을 사용한 후에 더 이상 유니 코드 오류가 발생하지 않습니다.


10
그것은 진단 및 수정이 아니라 문제를 억제하는 것입니다. "발을 자른 후에는 더 이상 옥수수와 아저씨에 문제가 없습니다"라고 말하는 것과 같습니다.
— John Machin

10
문제를 억제하고 있다는 데 동의합니다. 그래도 그 질문은 그런 것 같습니다. 그의 노트를 보자 : "오류가 아닌 문제를 일으키는 코드 바이트를 제거 할 수 있습니까?"
— Gattster

3
간단하게 ( '무시', '아스키') 함수 .encode "일부 문자열을"전화로이 정확히 동일합니다
— 여호수아 화상

17
나는 누군가 SO에 대해 질문하고이 모든 설교 응답을받는 것에 지쳐 피곤하다고 말할 수 없습니다. "내 차가 시작되지 않습니다." "왜 차를 시작하고 싶습니까? 대신 걸어야합니다." 멈춰!
— shanusmagnus

8
@JohnMachin 아무도 신경 쓰지 않습니다. 나는 사람들이 RSS 피드에 넣은 지연 쓰레기에 대해 신경 쓰지 않습니다. ASCII가 아닌 일부 문자는 잘릴 수 있습니다. 그들의 문제. 나는 파이썬이 실제로 그것을 질식시키고 처리하고, '무시'를 지정할 때마다 오류를주지 않기를 원합니다. 도대체 누가 그 똥을 내놓았습니까?!
— user1244215

10

cmd.exeHTML 콘솔과 같은 깨진 콘솔의 경우 항상 다음을 사용할 수 있습니다.

my_unicode_string.encode('ascii','xmlcharrefreplace')

이렇게하면 ASCII가 아닌 모든 문자를 그대로 유지하면서 순수한 ASCII 및 HTML로 인쇄 할 수 있습니다 .

경고 : 오류를 피하기 위해 프로덕션 코드에서이 코드를 사용하면 코드에 문제가있을 가능성이 높습니다 . 이를위한 유일한 유스 케이스는 비 유니 코드 콘솔로 인쇄하거나 HTML 컨텍스트에서 HTML 엔티티로 쉽게 변환하는 것입니다.

마지막으로 Windows에 있고 cmd.exe chcp 65001를 사용하는 경우 utf-8 출력을 사용하도록 입력 할 수 있습니다 (Lucida Console 글꼴과 함께 작동). 을 추가해야 할 수도 있습니다 myUnicodeString.encode('utf8').


6

"" "HTML에 유니 코드를 잘못 입력 한 것이 포함되어 있다고 가정합니다." ""

HTML은 어떤 형식의 "유니 코드 시도"를 포함하지 않아야합니다. 일부 인코딩으로 인코딩 된 유니 코드 문자를 포함해야합니다. 일반적으로 앞에 제공되는 "charset"을 찾으십시오.

문자셋이 UTF-8이라고 가정하고있는 것 같습니다 ... 어떤 근거에서? 오류 메시지에 표시된 "\ xA0"바이트는 단일 바이트 문자 세트 (예 : cp1252)가있을 수 있음을 나타냅니다.

HTML을 시작할 때 선언에 대해 이해가되지 않으면 chardet 을 사용 하여 가능한 인코딩이 무엇인지 찾아 보십시오 .

질문에 "regex"로 태그 한 이유는 무엇입니까?

전체 질문을 질문이 아닌 것으로 바꾼 후 업데이트 하십시오.

html = urllib.urlopen(link).read()
# html refers to a str object. To get unicode, you need to find out
# how it is encoded, and decode it.

html.encode("utf8","ignore")
# problem 1: will fail because html is a str object;
# encode works on unicode objects so Python tries to decode it using 
# 'ascii' and fails
# problem 2: even if it worked, the result will be ignored; it doesn't 
# update html in situ, it returns a function result.
# problem 3: "ignore" with UTF-n: any valid unicode object 
# should be encodable in UTF-n; error implies end of the world,
# don't try to ignore it. Don't just whack in "ignore" willy-nilly,
# put it in only with a comment explaining your very cogent reasons for doing so.
# "ignore" with most other encodings: error implies that you are mistaken
# in your choice of encoding -- same advice as for UTF-n :-)
# "ignore" with decode latin1 aka iso-8859-1: error implies end of the world.
# Irrespective of error or not, you are probably mistaken
# (needing e.g. cp1252 or even cp850 instead) ;-)

4

string이있는 경우 문자열 방법을 line사용하여 .encode([encoding], [errors='strict'])인코딩 유형을 변환 할 수 있습니다.

line = 'my big string'

line.encode('ascii', 'ignore')

Python에서 ASCII 및 유니 코드를 처리하는 방법에 대한 자세한 내용은 다음 사이트를 참조 하십시오. https://docs.python.org/2/howto/unicode.html


1
문자열에 ü와 같은 ASCII가 아닌 문자가 있으면 작동하지 않습니다.
— sajid

4

나는 대답이 있지만 비트와 조각에만 있다고 생각하여 다음과 같은 문제를 신속하게 해결하기가 어렵습니다.

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

예를 들어, 다음 형식의 데이터가있는 파일이 있다고 가정합니다 (ascii 및 non-ascii char 포함)

1/10/17, 21:36-Land : Welcome ��

ASCII 문자 만 무시하고 보존하려고합니다.

이 코드는 다음을 수행합니다.

import unicodedata
fp  = open(<FILENAME>)
for line in fp:
    rline = line.strip()
    rline = unicode(rline, "utf-8")
    rline = unicodedata.normalize('NFKD', rline).encode('ascii','ignore')
    if len(rline) != 0:
        print rline

type (rline)은 당신에게 줄 것입니다

>type(rline) 
<type 'str'>

이것은 또한 (표준화가) "확장 ASCII"경우에 작동
— 올리버 Zendel

1
unicodestring = '\xa0'

decoded_str = unicodestring.decode("windows-1252")
encoded_str = decoded_str.encode('ascii', 'ignore')

나를 위해 작동


-5

python 2.x를 사용하고있는 것 같습니다. Python 2.x의 기본값은 ascii이며 유니 코드에 대해서는 잘 모릅니다. 따라서 예외입니다.

shebang 후 아래 줄을 붙여 넣으면 작동합니다.

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

이 coding의견은 마법 치료법이 아닙니다. 오류가 발생하는 이유를 알아야합니다. 이는 Python 소스에 잘못된 문자가있을 때만 수정합니다. 이 질문에는 해당되지 않습니다.
— Mark Ransom
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.