Python 2 UnicodeEncodeError: ‘ascii’ codec can’t encode character — str() 대신 encode()
1. 문제 정의
웹 페이지(여러 사이트)에서 가져온 유니코드 텍스트를 처리하다가 다음과 같은 에러가 발생하는 상황입니다.
| |
문제가 되는 코드는 다음과 같습니다.
| |
핵심 증상은 다음과 같습니다.
| 증상 | 설명 |
|---|---|
| 에러 유형 | UnicodeEncodeError |
| 실패 코드 | str(...) 호출 과정에서 발생 |
| 실패 문자 | \xa0 (줄 바꿈 없는 공백, non-breaking space) |
| 재현성 | 사이트에 따라 간헐적으로 발생 — 어떤 페이지는 되고 어떤 페이지는 실패 |
에러가 항상 재현되지 않는다는 것이 이 문제의 까다로운 점입니다. 어떤 페이지는 정상 동작하고, 다른 페이지에서는 에러를 던집니다.
2. 원인 탐구
에러 메시지를 분해해 보면 원인을 추적할 수 있습니다.
'ascii' codec can't encode— ASCII 코덱이 이 문자를 인코딩할 수 없다는 뜻입니다.character u'\xa0'—\xa0는 유니코드의 줄 바꿈 없는 공백(non-breaking space)으로, 웹 페이지 HTML에 자주 등장하는 문자입니다. ASCII에는 존재하지 않습니다.position 20— 20번째 위치에 해당 문자가 있다는 뜻입니다.
즉, agent_contact 또는 agent_telno에 포함된 유니코드 문자열(예: \xa0)을 str()로 변환하는 순간, Python 2의 str()이 기본 인코딩인 ASCII를 사용하려다 실패한 것입니다.
왜 간헐적으로 발생할까요?
- 일부 페이지의 텍스트는 순수 ASCII 문자만 포함 →
str()이 성공 - 다른 페이지의 텍스트는
\xa0처럼 ASCII 밖의 유니코드 문자를 포함 →str()이 실패
입력 데이터에 따라 성공/실패가 갈리기 때문에, 코드 자체는 똑같은데 에러가 항상 나지 않는 것입니다.
3. 근본 원인 분석
근본 원인은 Python 2에서 str()로 유니코드를 변환하는 방식에 있습니다.
Python 2에는 두 가지 문자열 타입이 있습니다.
| 타입 | 설명 | 기본 인코딩 |
|---|---|---|
str | 바이트 문자열 | ASCII |
unicode | 유니코드 문자열 | — |
str()은 unicode → str 변환 과정에서 시스템 기본 인코딩(ASCII) 을 사용합니다. 따라서 변환 대상에 ASCII 범위 밖의 문자가 하나라도 있으면 UnicodeEncodeError가 발생합니다.
Python 공식 문서(Python Unicode HOWTO)는 이 상황을 바로 이 예외 케이스로 소개합니다. ASCII 기본 인코딩으로는 \xa0와 같은 유니코드 문자를 바이트로 표현할 수 없기 때문에 에러가 나는 것이며, 이는 코드가 아니라 str() 사용 방식의 문제입니다.
즉 근본 원인은 다음 두 가지가 결합된 것입니다.
- 웹에서 가져온 텍스트에
\xa0등 ASCII 밖 유니코드 문자가 존재함 str()이 기본 코드(ASCII)로 유니코드를 인코딩하려 함
4. 코드 해결책
해결 방법은 두 가지입니다. 핵심 원칙은 유니코드 → 바이트 변환에 str()을 쓰지 말고 .encode()를 쓰는 것입니다.
방법 1: .encode('utf-8')로 명시적 인코딩
| |
u' '.join(...)로 유니코드 문자열을 만듭니다..encode('utf-8')로 명시적으로 UTF-8 인코딩합니다..strip()으로 앞뒤 공백을 제거합니다.
\xa0도 UTF-8에서는 정상적으로 인코딩되므로 에러가 발생하지 않습니다.
방법 2: 전체를 유니코드로 처리
가능하다면 프로그램 전체에서 유니코드 문자열로만 작업하고, 입출력 경계(파일 쓰기, 네트워크 전송 등)에서만 인코딩하는 방식이 더 깔끔합니다.
| |
이렇게 하면 중간 단계에서 ASCII 강제 변환이 일어나지 않아 에러가 원천적으로 사라집니다.
5. 향후 예방 조치
같은 에러를 반복하지 않으려면 다음을 지키세요.
| 조치 | 설명 |
|---|---|
str() 대신 .encode() 사용 | 유니코드 → 바이트 변환은 반드시 .encode('utf-8')로 명시 |
| 전체를 유니코드로 유지 | 입출력 경계에서만 인코딩/디코딩 |
| 파이썬 3 사용 | Python 3에서는 str이 유니코드가 되어 이 계열 에러가 크게 줄어듦 |
| 문자 규범화 | \xa0 같은 특수 문자가 필요하면 \xa0 → 일반 공백 등으로 정규화 |
특히 \xa0(줄 바꿈 없는 공백)는 웹 파싱에서 매우 흔하게 등장하므로, HTML에서 추출한 텍스트를 처리할 때는 항상 유니코드 인코딩을 염두에 두어야 합니다.
출처
- StackOverflow 질문 9942594: UnicodeEncodeError: ‘ascii’ codec can’t encode character u’\xa0’ in position 20: ordinal not in range(128)
- Python 공식 문서: Unicode HOWTO