반응형
웹클리퍼 기능을 구현하면서 발생했던 주요 문제중에 하나는 바로 인코딩/디코딩 문제였다!
이 페이지를 웹클리핑하면
http://news.chosun.com/misaeng/site/data/html_dir/2017/08/21/2017082100911.html
캡쳐에서 보이듯이 웹사이트 정보에 대한 텍스트들이 깨져서 나타났다.
이유를 확인해보니, axios를 이용하여 웹페이지의 html 문서를 가져올 때 utf-8 타입으로 가져오게 되는데, 이 사이트는 content-type이 euc-kr로 되어있어서 한글이 제대로 가져와지지 않았기 때문이었다.
이런 오류를 반복하지 않기 위해서는 페이지마다 다른 content-type에 대해 문자열로 디코딩하는 과정이 필요했다.
그래서 arraybuffer와 TextDecoder 함수를 이용하였다.
TextDecoder 함수를 사용하기 위해서는 axios 요청시 데이터를 binary 형식으로 가져와야 한다.
따라서 다음 코드와 같이 axios 요청을 해주었다.
const getHTML = async url => {
try {
const response = await axios.request({
url: url,
method: 'GET',
responseType: 'arraybuffer',
responseEncoding: 'binary'
});
const decoded = await convert(response.data);
return decoded;
} catch (error) {
console.log('[GET HTML] ERROR: ', error);
}
};
responseType으로 arraybuffer을 사용하는 이유는 arraybuffer가 일반 고정 길이 binary 데이터 버퍼를 나타내는 데 사용되는 데이터 형식이기 때문이다.
convert()가 바로 데이터를 디코딩하는 함수이다.
이 함수의 코드는 다음과 같다.
const convert = async html => {
// arraybuffer -> string
var enc = new TextDecoder('utf-8');
// 'euc-kr'찾기
const $ = cheerio.load(enc.decode(html));
let charsetNormal = $("meta[http-equiv='Content-Type']").attr('content');
let charsetUpper = $("meta[http-equiv='CONTENT-TYPE']").attr('content');
let charsetLower = $("meta[http-equiv='content-type']").attr('content');
let charset = (charsetNormal? charsetNormal : (charsetUpper? charsetUpper : charsetLower));
// decoding
if(charset!==undefined){
if(charset.toLowerCase().indexOf('euc-kr') > -1){
enc = new TextDecoder("euc-kr");
return enc.decode(html);
}
}
return enc.decode(html);
};
먼저 axios 요청을 통해 얻은 html 문서가 utf-8 형식이라고 가정하고 TextDecoder를 사용하여 디코딩을 한다.
그 후 cheerio 라이브러리를 통해 사이트의 content-type을 찾아 charset 변수에 저장하는 과정을 거친다.
charset의 값이 euc-kr이면 TextDecoder를 사용하여 euc-kr 타입의 html 문서를 디코딩하여 반환한다.
반응형
'웹개발 > 크롬 익스텐션' 카테고리의 다른 글
크롬 익스텐션 개발기(3) : storage (0) | 2021.02.12 |
---|---|
크롬 익스텐션 개발기(2) : webclipper (0) | 2021.01.25 |
크롬 익스텐션 개발기 (1) : 기본 설정 (0) | 2021.01.17 |
댓글