안수찬 블로그

Node.js 에서 한글 인코딩 문제 해결하기

Introduction

안수찬 @dobestan

서울대학교에서 컴퓨터공학을 전공하고, 오랜 기간 서비스 기획 및 개발을 해 왔습니다. 이러한 전문성을 인정받아 미래부 소프트웨어 마에스트로에 선정된 바 있습니다. 현재는 모바일 방송국, 퍼스트캔버스에서 컨텐츠로 새로운 가치를 그리고 있습니다. 나는 안수찬이다. 그러므로 나는 할 수 있다. me@ansuchan.com


nodejs

Node.js 에서 한글 인코딩 문제 해결하기

Posted by 안수찬 @dobestan on .
Featured

nodejs

Node.js 에서 한글 인코딩 문제 해결하기

Posted by 안수찬 @dobestan on .

며칠 전에 "Node.js 를 이용한 웹 데이터 수집하기" 라는 글을 작성을 했었는데, 특정 사이트의 정보를 수집하는데 한글 인코딩 관련해서 문제가 생긴다고 말씀해주신 몇 분이 계셨다. 그래서 Node.js 에서 한글 인코딩 ( EUC-KR ) 관련된 문제를 해결하는 방법에 대해서 공유한다.

이번 포스트에서는 연세대학교 수강편람 사이트의 교과목 정보를 크롤링하는 것 부터 시작을 해서, 인코딩 문제를 해결하는 과정에 대해서 다룬다. 나는 연세대학교와 그 어떠한 관계도 없다. 다른 분들의 프로젝트를 도와드릴 뿐이다.

연세대학교 수강편람

꽤 아름답게 만들어져 있다. 굳이 블로그에 쓰려고 하나 찾아서 작성을 했는데, 사이트가 문닫지 않기를 바랄 뿐이다.

tl;dr

// node-iconv 를 이용한 방법
var Iconv = require('iconv').Iconv;  
var iconv = new Iconv('euc-kr', 'utf-8//translit//ignore');

iconv.convert([Buffer])  
  • request 를 사용하고 있다면, request.get 옵션에서 encoding: null 을 주면 결과를 String 이 아닌 Buffer 로 받을 수 있다. ( 블로그 쓰면서 저도 처음 알았습니다 )
var options = {  
  url: "...",
  encoding: null
};

request.get(options, function(error, response, body) {  
  var data = iconv.convert(body).toString();
});

데이터 수집하기

HTTP Request

크롬 개발자 도구의 Network 탭에서 어떤 HTTP 요청들이 오가는지 확인하면 쉽게 확인할 수 있다.

크롬 개발자 도구의 "Network" 탭에 들어가보면 모든 Network Request/Response 에 대한 기록들이 남게 된다. 어떤 HTTP Request 를 통해서 실제 학과목 정보들을 가져왔는지 살펴볼 수 있다. 기록된 HTTP Request 중 실제 수강 편람에 대한 정보가 담겨있는 링크를 클릭해보면 GET 요청으로 데이터가 들어오니 새 창으로 한번 들어가서 확인해보자.

<ERROR>  
비인가 사용자의 직접접근 및 비정상적인 사용은 금지되어 있습니다. 인가를 원하시면 정보화추진팀(02-2123-4241)로 연락해주시기 바랍니다.
</ERROR>  

그렇다. 이런 사이트는 크롤링하지 말자. 특히나, 혹시 당신이 비인가 사용자라면, 혹은 비정상적인 사용을 하려고 있다면 정보화추진팀 으로 연락을 해보자. 그렇다면 여기서 생각해봐야할 부분은 "대체 무엇 떄문에, 우리가 정상적인 접근이 아니라, 비정상적인 접근이라고 판단하였는가?" 이다.

Request Headers 를 살펴보자.

실제로 HTTP Request 를 보내면서, 다음과 같은 정보들을 Header 에 포함하고 있다.

사이트에서 이를 체크하는 방법은 다양할 수 있다. 일반적으로는, Referer, Host, Custom Headers ( X-... ) 등이 있을 수 있는데, 이 사이트의 경우에는 Referer, Host 로 판단을 하고 있었다. 따라서, 다음과 같이 HTTP Request 를 보내면서 Header 에 정상적인(원래의) 헤더 정보를 포함해서 보내면 정상적으로 데이터를 불러올 수 있었다.

var http = require("http");


var options = {  
  host: "ysweb.yonsei.ac.kr",
  path: "/DataAgent?pgm=/curri120601/curri_Data&DmlGb=get_list&ocode0=s1&ocode1=s1101000H1&s2=all&schHakjum=all&hy=2016&hg=2&lang=0&filterscount=0&groupscount=0&pagenum=0&pagesize=15&recordstartindex=0&recordendindex=10&_=1469671606827",
  port: 8888,
  headers: {
    "Host": "ysweb.yonsei.ac.kr:8888",
    "Referer": "http://ysweb.yonsei.ac.kr:8888/curri120601/curri_new.jsp"
  }
};

var request = http.request(options, function(response) {  
  var data = "";

  response.on("data", function(chunk) {
    data += chunk;
  });

  response.on("end", function() {
    console.log(data);
  });
});


request.end();  

이렇게 스크립트를 실행해보면 정상적으로 서버로 부터 데이터를 받아올 수 있기는 하지만, 현재는 인코딩이 깨지는 상태로 한글 데이터를 알아볼 수 없는 상태로 출력이 된다. 그렇다면, 이제는 우리가 "가지고 있는 데이터" 는 어떤 인코딩으로 되어 있는지 살펴보자.

인코딩 변환하기

Response Headers 를 살펴보자.

서버에서는 한글 데이터의 인코딩을 EUC-KR 로 보내고 있다.

아까의 Network 탭에 Response Headers 를 살펴보면, 위의 사진에서 알 수 있다시피 EUC-KR 이라는 인코딩을 사용하고 있다. 제대로 출력되도록 ( 혹은 추후에 우리가 사용할 수 있도록 ) 이 데이터를 UTF8 로 변경해보자. 이런 인코딩 변환 작업은 iconv 를 이용해서 해결할 수 있다.

var Iconv = require('iconv').Iconv;  
var iconv = new Iconv('euc-kr', 'utf-8//translit//ignore');

...
  response.on("data", function(chunk) {
    data += iconv.convert(chunk);
  });
...

new Iconv('euc-kr', 'utf-8//translit//ignore') 를 통해서 만든 Iconv 객체가 EUC-KR 인코딩으로 되어 있는 Buffer 를 UTF8 로 변경해주는 역할을 한다. 옵션은 각각 다음의 의미를 가진다 (출처):

  • //TRANSLIT - 음역("transliteration") 된다. 즉, 정확하게 문자가 매칭되지 않는다면, 비슷한 문자로 변경된다.
  • //IGNORE - 올바르게 인코딩 되지 않는 문자열은 버린다.

request + iconv

이 경우에는 우리가 http 모듈의 http.request 를 사용하고 있기 때문에 이렇게 chunk(Buffer) 를 바로 iconv 를 이용해서 변환해줄 수 있지만 만약 request 를 이용해서는 어떻게 할 수 있을까?

request.get 의 콜백 함수에서 세번째 인자로 받는 body 는 기본적으로 String Type 으로 받게 된다. 하지만 옵션으로 encoding: null 을 주게 되면, Buffer Type ( binary ) 으로 받을 수 있게 된다. 이를 이용하면 최종 데이터를 binary 로 바로 받아서 변경할 수도 있다.

var request = require("request");

var Iconv = require('iconv').Iconv;  
var iconv = new Iconv('euc-kr', 'utf-8//translit//ignore');


var options = {  
  url: "http://ysweb.yonsei.ac.kr:8888/DataAgent?pgm=/curri120601/curri_Data&DmlGb=get_list&ocode0=s1&ocode1=s1101000H1&s2=all&schHakjum=all&hy=2016&hg=2&lang=0&filterscount=0&groupscount=0&pagenum=0&pagesize=15&recordstartindex=0&recordendindex=10&_=1469671606827",
  headers: {
    "Host": "ysweb.yonsei.ac.kr:8888",
    "Referer": "http://ysweb.yonsei.ac.kr:8888/curri120601/curri_new.jsp"
  },
  encoding: null
};


request.get(options, function(error, response, body) {  
  var data = iconv.convert(body).toString();
  console.log(data);
});

안수찬 @dobestan

https://ansuchan.com/

서울대학교에서 컴퓨터공학을 전공하고, 오랜 기간 서비스 기획 및 개발을 해 왔습니다. 이러한 전문성을 인정받아 미래부 소프트웨어 마에스트로에 선정된 바 있습니다. 현재는 모바일 방송국, 퍼스트캔버스에서 컨텐츠로 새로운 가치를 그리고 있습니다. 나는 안수찬이다. 그러므로 나는 할 수 있다. me@ansuchan.com

View Comments...