[FAQ] 크롤링 데이터의 한글이 깨져요
[FAQ] - 크롤링 데이터의 한글이 깨져요¶
- Q: 데이터를 크롤링하는데 한글이 외계어로 표시 됩니다
- A: 대부분의 경우 한글 인코딩의 문제 입니다. decode('euc-kr') 시도해 보세요.
데이터를 크롤링할 때 한글 데이터가 깨지는 경우가 있다. 다양한 경우가 있지만, 가장 많은 경우가 euc-kr 인코딩된 한글 바이트 문자열 데이터를 그대로 사용하려는 경우이다. 이 경우로 euc-kr 인코딩을 utf-8 인코딩으로 바꾸어 주면 해결 된다.
예를 들어, 데이터를 수집했는데 아래와 같이 데이터가 표시 되는 경우이다.
b'\xc4\xda\xbd\xba\xc7\xc7\xc1\xf6\xbc\xf6'
b로 시작되는 것으로 바이트 나열(byte sequence)라는 의미이며, \x00 모양의 데이터는 1바이트의 16진수 값을 표시한다. 이 데이터가 euc-kr 로 인코딩된 한글이라면 다음과 같이 decode('euc-kr') 함수를 사용해서 유니코드 문자열로 바꿀 수 있다.
s = b'\xc4\xda\xbd\xba\xc7\xc7\xc1\xf6\xbc\xf6'
type(s), s
u = s.decode('euc-kr')
type(u), u
다량의 데이터라면 아래와 같이 변환한다.
arr = [
b'K200\xc0\xce\xb5\xa6\xbd\xba',
b'\xc0\xcf\xb9\xdd\xc1\xd6\xbd\xc4',
b'\xb9\xe8\xb4\xe7\xc1\xd6\xbd\xc4',
b'\xc1\xdf\xbc\xd2\xc7\xfc\xc1\xd6\xbd\xc4',
]
for i in arr:
print(i.decode('euc-kr'))
Python2 와 Python3 에서 유니코드¶
Python 2.x 에서 str과 unicode는 서로 다르다. 이 때문에 str의 인코딩 처리와 unicode 변환이 상당히 번거롭다.
>>> s = "한글ABC"
>>> u = u"한글ABC"
>>> type(s), len(s)
(<type 'str'>, 9)
>>> type(u), len(u)
(<type 'unicode'>, 5)
>>> s == u
False
Python3는 모든 문자열을 유니코드(unicode)로 처리하기 때문에 str과 unicode가 완전히 동일하다. 위와 동일한 코드를 Python3에서 실행한 결과이다.
>>> s = "한글ABC"
>>> u = u"한글ABC"
>>> type(s), len(s)
(<class 'str'>, 5)
>>> type(u), len(u)
(<class 'str'>, 5)
>>> s == u
True
반드시 Python2를 써야만 하는 상황이 아니라면 가급적 Python3를 쓰는 것이 좋다.
EUC-KR 그리고 UTF-8¶
한글 인코딩과 관련해서 알아 둘만한 인코딩은 크게 4가지 정도(EUC-KR, CP949, UTF-8, UTF-16) 이다.
인코딩 | 주요핵심 | 상세설명(위키피디어) |
---|---|---|
EUC-KR | 한글 완성형 | https://ko.wikipedia.org/wiki/EUC-KR |
CP949 | 한글 완성형 (마이크로소프트사) | https://ko.wikipedia.org/wiki/CP949 |
UTF-8 | 유니코드 8비트 (한글 1글자에 3바이트) | https://ko.wikipedia.org/wiki/UTF-8 |
UTF-16 | 유니코드 16비트 (한글 1글자에 2바이트) | https://ko.wikipedia.org/wiki/UTF-16 |
동일한 문자열도 다른 값으로 인코딩에 따라 다른 값을 갖는다.
>>> '아름다운'.encode('euc-kr')
b'\xbe\xc6\xb8\xa7\xb4\xd9\xbf\xee'
>>> '아름다운'.encode('cp949')
b'\xbe\xc6\xb8\xa7\xb4\xd9\xbf\xee'
>>> '아름다운'.encode('utf-8')
b'\xec\x95\x84\xeb\xa6\x84\xeb\x8b\xa4\xec\x9a\xb4'
>>> '아름다운'.encode('utf-16')
b'\xff\xfeD\xc5\x84\xb9\xe4\xb2\xb4\xc6'
# 참고: utf-16의 시작 2바이트(0xFF 0xFE)는 BOM (Byte Order Mark) https://ko.wikipedia.org/wiki/바이트_순서_표식
각 인코딩의 주요한 핵심을 간단히 설명하면 아래와 같다.
- EUC-KR은 한글 완성형 인코딩으로 국내 사이트의 상당수가 EUC-KR 인코딩을 사용하고 있다.
- CP949는 EUC-KR와 동일한 한글 완성형 인코딩이지만, EUC-KR 보다 확장된 문자 집합을 가지고 있다. 마이크로소프트가 제정하였으며, 주로 윈도우에서 사용한다.
- UTF-8과 UTF-16은 둘 다 유니코드 인코딩이다. 각각 UTF-8는 8비트 단위로 인코딩하며 한글 1자는 3바이트, 영문자 1자는 1바이트로 표현한다. 자리수는 많이 차지하지만 영문자와 섞어 쓸 때 혹은 특수 문자 사용이 제한적인 인터넷 환경(예: URL)에서 가장 문제가 적다.
가급적 UTF-8 인코딩을 사용하도록 권한다. (데이터 파일, 데이터 송수신, 파이썬 소스 프로그램 등 모두)¶
인코딩 알아내기¶
여러 데이터 소스로 부터 데이터를 가져오는 경우 (혹은 텍스트 인코딩이 한가지로 지정되지 않는 데이터인 경우) 인코딩을 추정하는 방법이 있다.
chardet.detect (data) 를 함수를 사용하면 data의 인코딩을 추정해 준다.
import chardet
euc_data = '아름다운 한글'.encode('euc-kr')
print( euc_data )
# 인코딩 알아내기
print (chardet.detect (euc_data))
euc_data = '아름다운 한글'.encode('utf-8')
print( euc_data )
# 인코딩 알아내기
print (chardet.detect (euc_data))
{'encoding': 'EUC-KR', 'confidence': 0.99}
결과에서 인코딩('encoding')은 EUC-KR로 추정하였으며 신뢰도(confidence)는 0.99 (99%)라는 의미이다.
결론¶
- 파이썬2 보다 Python3 추천 (Python3는 자체가 유니코드 시스템)
- urllib2 보다 requests 추천 (더 적절하게 동작하며 사용도 편리)
- 데이터의 인코딩이 EUC-KR 이면, decode('euc-kr') 하여 유니코드로 디코딩
- 데이터 저장, 송수신, 프로그램 소스 파일 모두 가능한 UTF-8로 통일
댓글
Comments powered by Disqus