(Node.js) XLSX 모듈 사용 / 행렬 파싱 및 조건에 맞는 데이터만 추출

요번에는 Node.js로 아래와 같이
KRX에서 코스피/코스닥 상장사 정보를 취득한 후 네이버에서 원하는 조건에 맞는 정보만 크롤링하는 모듈을 만들어보려고 합니다! 그러면 주식하는 친구들은 조건식을 걸어놓기만 해도 손 안대고 틈틈히 자동으로 수집된 정보를 확인할 수 있게 되겠네요! 

(이후에는 자동 메일링까지 추가할 건데 우선은 크롤링해서 유의미한 XLSX로 Export하는 것 까지를 먼저 만들려고 합니다!)



네이버 주식에서 페이지를 확인해보니 종목코드를 기준으로 페이지 주소가 매칭이 되고,
그 유니크한 종목 코드에 유니크한 Selector를 확인하면 데이터 크롤링이 되겠네요!

-----
저는 KRX 사이트에서 업체리스트를 xls로 받아온 뒤에 추출된 결과를 중간에 result.xls로 먼저 저장해놨다가 크롤링할 때 다시 리딩해서 쓰는 방식을 구현해보려고 합니다.
VBA / C++ 데이터 처리 방식이 익숙하기도 하고 나중에 불필요하면 떼버리면 되니까요?

XLSX Import하는 모듈은 앞서 설명을 드렸었고요,
데이터를 Readfile한 뒤에 조건에 맞는거만 옮겨담는 작업이 필요한데요,
이를 위해 stackoverflow에서 parsing하는 알고리즘을 참고해서 아래와 같이 변형합니다!

https://stackoverflow.com/questions/30859901/parse-xlsx-with-node-and-create-json

원본은 data[row][headers[col]] = value인데,
XLSX에서 가상의 sheet에 데이터를 넣어주려면
array of arrays 방식이 되어야 하기 때문에, 아래와 같이 우선 빈 배열을 선언하고,
row / column을 동적할당(new array()) 후 push 하는 방식으로 처리해줘야 합니다.
제가 아는 방법 중엔 이게 제대로 동작을 하기 때문에 이렇게 바꿔서 사용했습니다.

조건식은 나중에 입력받겠지만,
column index === 업종코드 column / 회사명 column 일 때 데이터를 push 한다는 의미입니다.


그리고 지난 번 사용했던 XLSX Export 모듈을 아래와 같이 붙여준다면 
앞서 말씀드린 바와 같이 중간에 result.xls라는 파일로 생성이 되겠네요!

※ 위의 알고리즘을 실행하면 빈 행이 두 줄 생기니까 shift()로 삭제해주라고 stack overflow에 적혀있네요! ㅎㅎ; 그렇게 하도록 합시다.

그러면 1차적으로 파일명/추출부분설정 -> 원본xls파일 -> 크롤링에 필요한 정보 추출을 구현할 수 있게 됩니다! 
-----

그럼 잘 되는지, 위의 코드를 어떻게 써먹어야 하는지 확인을 해봐야겠네요.
지금까지의 결과를 정리해보면 아래와 같이 되겠네요!!


위의 함수 입력부분을 보면 optionsSeperator에서 파일명, index업종코드, index회사명을 받기 위해 변수 set을 let으로 선언해놨습니다! 혹시 다른 정보가 받고 싶어질 수도 있으니까요! ㅎ

-----


이제 테스트를 해봅니다 ! KRX에서 데이터를 받으면 data.xls일 거에요
아래의 엑셀버튼을 누르면 바로 뜨지요!



그리고 실행해보니까 잘 동작을 하네요! 
이제 이걸가지고 전에 만들었던 크롤링 모듈과 합쳐버리면 바로 원하는 조건에 따른 결과를 수집할 수 있겠네요!!! ㅎㅎㅎ



다음에는 금번 XLSX Export 결과 + 네이버 주식 크롤링 후 XLSX Export하는 단계까지 하도록 하겠습니다!! 업종코드 분리하는게 생각보다 어려웠기 때문에 크롤링은 selector만 잘 다루면 되서 뒷부분은 더 쉬울 것 같네요!!

----- Data seperator module (ReqModule.js)
// ----- XLSX Initialization part ----- //
const XLSX = require('xlsx');
/* Initializing a free workbook & worksheet name*/
// ----- End of XLSX Initialization part ----- //

module.exports = Shims_sheetSeperator;

// 'https://stackoverflow.com/questions/30859901/parse-xlsx-with-node-and-create-json'
function Shims_sheetSeperator(optionsSeperator) {
    let {
        importFileName
        , indexDataCode
        , indexCompanyName
    } = optionsSeperator;
    
    let wb = XLSX.readFile(optionsSeperator.importFileName);
    let ws_list = wb.SheetNames;

    ws_list.forEach(function(y){
        let worksheet = wb.Sheets[y];
        //let headers = {};
        //let data = [];
        let dataExport = [];
        for(z in worksheet) {
            if(z[0] === '!') continue;
            //parse out the column, row, and value
            var tt = 0;
            for (var i = 0; i < z.length; i++) {
                if (!isNaN(z[i])) {
                    tt = i;
                    break;
                }
            };
            var col = z.substring(0,tt);
            var row = parseInt(z.substring(tt));
            var value = worksheet[z].v;
            /*store header names
            if(row == 1 && value) {
                headers[col] = value;
                result[row].push(value);   
                continue;
            }*/
            /* Entire data load part - not used for this module
                if(!data[row]) data[row]=new Array();
                data[row].push(value);
            */
            if(!dataExport[row]) dataExport[row]=new Array();
            if (col === optionsSeperator.indexDataCode || col === optionsSeperator.indexCompanyName){
                dataExport[row].push(value);
            };   
        };
        //drop those first two rows which are empty
        console.log(dataExport);
        //data.shift();
        //data.shift();
        dataExport.shift();
        dataExport.shift();
        /* Add the worksheet to the workbook */
        let wb_result = XLSX.utils.book_new();
        let ws_result = XLSX.utils.aoa_to_sheet(dataExport);
        XLSX.utils.book_append_sheet(wb_result, ws_result, 'sheet1');
        /* Write workbook into XLSX File*/
        XLSX.writeFile(wb_result, 'result.xls');   
    });
}
----- Test part (TestGarden.js)
let dataExtractor = require('./ReqModule');

let optionsSeperator = {
    importFileName : 'data.xls'
    , indexDataCode : 'B'
    , indexCompanyName : 'C'
};
dataExtractor(optionsSeperator)



댓글

이 블로그의 인기 게시물

(Node.js) XLSX로 결과 출력하기 / 모듈 디자인 Exporting / Node.js modular design

(VBA) 009 - 닫힌 파일에서 데이터 읽어오기 (ExecuteExcel4Macro)

(Node.js) EUC-KR을 Cheerio - Iconv-lite로 불러올 때