Open-uri 인코딩 문제 처리


가끔 예제대로만 크롤링 작업을 하다보면 인코딩 문제가 발생할 수 있습니다.

예를 들면, Ruby의 Open-uri의 경우 Default 설정이 UTF-8 방식이므로, 자동으로 UTF-8 방식으로 변환해서 가져옵니다.

만약에 깔끔하게 UTF-8 변환을 지원하지 않는 데이터를 Open-uri로 열 경우, Nokogiri로 파싱작업을 끝낸 놈에서 "쀍퀡찌!$#%#$" 이런 식으로 표시가 되서 DB에 들어가 있는 결과를 만나보게 되고, 아무리 디버깅하면서 irb에서 삽질을 한다고 해도, 본인은 알고리즘 상에서 잘못한게 없다는 결론에 도달하게 됩니다. (물론, 보통은 Open-uri를 지원합니다.)

"보통 이런 형태의 문제가 있는 데이터는 일부는 잘 나오고, 일부는 깨져서 개발자를 당황시킵니다." (예를 들면, 블락 비 - Bl&#$%, Bl&#$% 부분이 Block B입니다.)

여러 삽질을 하다가 Open-uri 문제라는 걸 깨닫고, Open-uri를 대체할 놈을 찾기 시작했습니다. Open-uri 를 대체할 놈으로 Mechanize Gem 을 찾았습니다. Mechanize gem 을 설치하거나 Rails 에서 Gemfile 에 넣는 방법은 알고 있다고 가정하고 글을 씁니다.

해결 방법

data_url = "URL 내용을 넣어줍니다."

@agent= Mechanize.new    #Mechanize 객체 하나를 생성
@page = @agent.get data_url    #get 메소드를 사용하여 get 요청을 보낸 값을 가져옵니다.
@data_by_nokogiri = Nokogiri::HTML(@page.content)    #가져온 데이터를 다시한번 Nokogiri 로 변환합니다.

위처럼 open-uri를 대체할 것을 찾아서 get 요청 후 Nokogiri로 다시 파싱해서 사용하시면 됩니다.


그런데 위처럼 해도 해결이 안되는 경우가 있습니다. 아래 에러 메시지를 한 번 살펴보죠.

"nokogiri::xml::syntaxerror: input is not proper utf-8, indicate encoding"

Nokogiri 나 Mechanize를 통해서 웹 페이지의 데이터를 파싱하려고 할 때, 글자가 깨져서 나오는 경우가 있습니다. 인코딩 에러 또는 깨짐 현상이라고 말하죠.

특히 한글이 말이죠. 흔히 "쀍꿹빨떫꿝짫" 이런걸 생각하실 수도 있는데 " ´ß°¡½¿»ìÀ¯¸°±âÁ¤½Ä" 이런게 나올 때도 있습니다. 아주 멘붕이 오는거죠. 에러 메시지는 "0xED 0x6E 0x2C 0x20" 이런 걸 만나보실 수도 있고 다른 걸 수도 있습니다. 글씨에 따라 다른 에러 메시지가 나오니까요. 요즘 페이지들은 대부분 알아서 UTF-8로 인코딩해서 웹 페이지를 구현합니다. 하지만 일부 짜증나는 것들이 대충 만들어서 크롤링하기 귀찮게 만들어 놓았더라구요. "페이지 자체를 인코딩해주세요." 라고 부탁하는 방법도 있지만 페이지 자체를 저희가 인코딩해서 수정할 수 없다면, 받아올 때 인코딩해서 잠시 소스를 가져오는 방법은 있습니다.

이 현상은 부분적으로 일어날 수도 있고 특정 언어 전반에 걸쳐서 일어날 수도 있습니다. 페이지가 어떻게 구현 되었는지에 따라 다릅니다. 여기서는 Nokogiri와 Open-uri 잼을 이용하여 페이지를 열어서 가져올 때 일어난 것에 대해서 살펴보겠습니다. 예시로 사용할 페이지는 '광운대학교 푸드코트 메뉴 페이지' 입니다.

$irb
> require 'nokogiri'
> require 'open-uri'
> url = "http://foodcourt.kw.ac.kr/menu/menu_chinesefood.html"
> data = Nokogiri::HTML(open(url))

#보통 이렇게 하면, 정상적으로 데이터를 받아서 HTML 구조대로 Nokogiri가 나누어줍니다. 하지만 여기서는 문제가 발생합니다.

> data = Nokogiri::HTML(open(url)).errors
#이렇게 에러를 살펴보면 다음과 같은 에러 메시지가 나타납니다.

=> [#<Nokogiri::XML::SyntaxError: Input is not proper UTF-8, indicate encoding !>, 
#<Nokogiri::XML::SyntaxError: Input is not proper UTF-8, indicate encoding !
Bytes: 0xEA 0xB8 0xDE 0xB4>, #<Nokogiri::XML::SyntaxError: Input is not proper UTF-8, indicate encoding

#즉 페이지 자체에 문제가 있다는 의미죠. 여러 방법이 있을 수 있지만, Nokogiri 자체에서 인코딩을 처리하는 방법이 있습니다.

해결 방법

> Nokogiri::HTML(open(url),nil,'euc-kr')
#이게 그 방법인데요, 왜 'euc-kr'을 사용했는지 궁금할겁니다.

사실 현재 이 상황에서는 노코기리 기본 인코드인 UTF-8을 사용하는데, EUC-KR이 필요한 상황이기 때문에 발생했습니다. 뭐가 문제인지 알려주는 사이트가 있어서 공유합니다. 아래 사이트에 URL을 입력하고 옵션을 조정하면 여기서 문제가 발생했을 때 왜 인지를 알려줍니다. 위와 같은 상황에서는 다음과 같은 메시지를 남깁니다. (http://validator.w3.org)

Character Encoding Override in effect!
The detected character encoding "euc-kr" has been suppressed and "utf-8" used instead.

즉, EUC-KR이 필요한데, UTF-8로 억지로 인코딩 중이었다는 이야기입니다. 이제 EUC-KR로 바꿔주면 문제가 해결될 것 같은 기분이 들죠? 그래서 위처럼 Nokogiri 안에 인코딩을 'euc-kr'로 바꾸어 준 것 입니다. 일본에서도 비슷한 문제가 있어서 포스팅한 내용이 있는데 거기는 'EUC-JP'로 바꿔주었습니다. 어쨋든 이런 식으로 해결해주면 됩니다.

여기서 하나 의문을 가질 수 있습니다. "아 그래? 그럼 한글 사이트는 전부 'euc-kr' 로 옵션을 주어서 넣어주면 되겠구나~" 생각하시는 분도 있을 수 있습니다. 우선 정답은 "아닙니다." 왜냐하면, 한국에서 만들어 졌다고 모두 'EUC-KR'로 인코딩되야 하는건 아닙니다. 구현 방식과 보고 있는 웹 브라우저에 따라서도 달라지는 것이 인코딩이므로 그 때 그 때 나오는 에러 메시지를 보고 판단하시는 것이 맞습니다. 그러므로 가장 많이 사용되는 UTF-8을 기본으로 두고 접근하시기 바랍니다. 아래는 제가 참고한 페이지들 입니다.

(https://www.youtube.com/watch?v=Pej6T_vYCmI) (http://insideflag.blogspot.com/2010/06/rubymechanize.html)

results matching ""

    No results matching ""