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.