반응형

ES5 자바스크립트와 Cobweb 스크래핑 개발 실무 가이드

 

  1. 개요
  2. 연간 교육 계획과 Cobweb 개발 로드맵
  3. Cobweb 아키텍처와 JS 모듈 구조 이해
  4. Cobweb 모듈의 실행 흐름
  5. ES5 자바스크립트 핵심 기능의 실무 적용
  6. 일반적인 스크래핑 패턴 구현
  7. 자바스크립트 강의 내용과 Cobweb 실무 적용
  8. 주요 실무 패턴 분석
  9. 자주 사용되는 ES5 스크래핑 기법
  10. 실무 적용을 위한 개발 팁

 

1. 개요

이 문서는 "웹 프론트엔드를 위한 자바스크립트 첫걸음" 강의와 Cobweb 개발 환경을 연계하여, 실무에서 ES5 자바스크립트를 효과적으로 활용하는 방법을 안내합니다.

Cobweb은 Object-C/Cocoa 기반의 스크래핑 도구로, espiderKit 프레임워크를 통해 자바스크립트 모듈을 실행하는 구조입니다.

이러한 환경에서 ES5 자바스크립트 지식을 어떻게 실제 스크래핑 개발에 적용할 수 있는지 알아보겠습니다.

 

2. 연간 교육 계획과 Cobweb 개발 로드맵

2.1 분기별 교육 및 실무 적용 계획

분기 교육 주제 Cobweb 실무 적용 예상 성과
1분기 웹 프론트엔드를 위한 자바스크립트 첫걸음 • 기초 자바스크립트 문법 및 DOM 활용 방법
• ES5 기반 코드 작성 및 코브웹 개발툴 활용법
스크래핑 모듈 개발의 기본 역량 확보
2분기 보안 인증 우회 및 고급 로그인 처리 기법 • 공동인증서 기반 로그인 시스템 분석 및 대응
• 금융권/공공기관 웹사이트 인증 절차 자동화
• 2FA(이중 인증) 처리 방법
• 세션 관리 및 쿠키 기반 인증 유지
보안 사이트 스크래핑 역량 강화
3분기 데이터 암호화/복호화 및 보안 통신 처리 • HTTPS 통신 패턴 분석 및 처리
• 웹사이트 데이터 암호화 방식 이해 (AES, RSA 등)
• 암호화된 페이로드 분석 및 복호화 기법
• 웹 요청 서명(Signature) 분석 및 재현
• API 요청 암호화 패턴 모방
• 난독화된 JavaScript 코드 분석
복잡한 네트워크 통신 처리 능력 향상
4분기(미정) 분산 아키텍처 기반
대규모 스크래핑 시스템 구축
• IP 차단 대응을 위한 프록시 풀 구현
• 대용량 데이터 처리 및 저장 최적화
• 컨테이너화 및 마이크로서비스 기반 확장성 확보
장애 복구 및 자동화된 운영 체계 구현
4분기(미정) 고급 동적 콘텐츠 스크래핑 및 성능 최적화 • SPA(Single Page Application) 및 동적 웹사이트 스크래핑 기법
• JavaScript 렌더링 엔진 기반 스크래핑 구현
• 웹소켓 통신 감시 및 데이터 추출
• 인피니트 스크롤 및 동적 로딩 처리 전략
• 스크래핑 성능 최적화 및 병목 현상 해결
• 메모리 누수 방지 및 장시간 실행 안정성 확보
리소스 효율적인
스크래핑 시스템 구현

 

 

3. Cobweb 아키텍처와 JS 모듈 구조 이해

3.1 Cobweb의 JavaScript 실행 구조

Cobweb은 Object-C/Cocoa 기반의 스크래핑 도구로, espiderKit 프레임워크를 통해 자바스크립트 모듈을 실행하는 구조입니다.

다음과 같은 구조로 JavaScript 모듈을 실행합니다.

더보기
┌─────────────────────────────────────────┐
│           Cobweb Application            │
│  ┌─────────────────┐  ┌───────────────┐ │
│  │  Cocoa UI Layer │  │ Configuration │ │
│  └─────────────────┘  └───────────────┘ │
│  ┌─────────────────────────────────────┐│
│  │         espiderKit Framework        ││
│  │  ┌─────────────┐   ┌─────────────┐  ││
│  │  │ Spider      │◄──┤ JavaScript  │  ││
│  │  │ Engine      │   │ Interpreter │  ││
│  │  └─────────────┘   └─────────────┘  ││
│  └─────────────────────────────────────┘│
└─────────────────────────────────────────┘

 
 
 
espiderKit 프레임워크는 내부적으로 JavaScript 실행 환경을 포함하고 있으며, 이를 통해 ES5 자바스크립트로 작성된 스크래핑 모듈을 실행합니다. Object-C 코드와 JavaScript 코드는 이 실행 환경을 통해 상호 작용합니다.
 

 

3.2 모듈 상속 구조

Cobweb에서 JavaScript 모듈은 다음과 같은 상속 구조를 가집니다.

Module.prototype.js (기본 모듈)
      ↑
KROM0016.js (사이트 카테고리별 모듈)
      ↑
KROM0016011000.js (무신사 주문 조회 모듈)

 

이 구조에서 각 레벨은 다음과 같은 역할을 담당합니다.

  1. 기본 모듈(Module.prototype.js): 모든 스크래핑 모듈의 기본 기능 제공
  2. 카테고리 모듈(KROM0016.js): 특정 카테고리(예: 쇼핑몰 주문조회)에 공통적인 기능 제공
  3. 사이트별 모듈(KROM0016011000.js): 특정 사이트(예: 무신사)에 맞춘 구체적인 스크래핑 로직 구현

 

4. Cobweb 모듈의 실행 흐름

4.1 모듈 실행 라이프사이클

Cobweb에서 JavaScript 모듈은 다음과 같은 라이프사이클로 실행됩니다.

Init() → GetParam() → Login() → GetData() → Convert() → SetResult()

 

 

각 단계는 다음과 같은 역할을 담당합니다.

  1. Init(): 모듈 초기화, HTTP 객체 생성 및 기본 설정
  2. GetParam(): 실행 파라미터 획득 및 검증
  3. Login(): 대상 사이트 로그인 처리
  4. GetData(): 실제 데이터 스크래핑 수행
  5. Convert(): 스크래핑한 데이터를 표준 형식으로 변환
  6. SetResult(): 최종 결과 반환

각 단계는 boolean 값을 반환하며, 하나라도 false를 반환하면 모듈 실행이 중단됩니다.

 

 

4.2 핵심 코드 패턴 분석

무신사 스크래핑 모듈 코드에서 볼 수 있는 핵심 패턴을 분석해보겠습니다.

모듈 정의와 상속

var KROM0016011000 = function () {
    // 모듈 속성 및 메서드 정의
    this.retData = {}; // 결과 데이터
    this.tempData = {}; // 임시 데이터
    
    // 메서드 구현
    this.Init = function() { /* ... */ }
    // ...
}

// 부모 모듈 상속
KROM0016011000.prototype = new KROM0016();

 

 

HTTP 통신 처리

this.http = new HttpProtocol();
this.http.timeout = 30;
this.http.urlencode = true;
this.http.isSSLHostname = true;

// HTTP 요청 예시
this.http.setRequestHeader("Connection", "Keep-Alive");
resultData = this.httpConnect("", "GET", this.hostURL + getData, "", 4);

 

JSON 데이터 처리

try {
    resultJson = JSON.parse(resultData);
} catch (e) {
    this.userError = (new Error().lineNumber + 1) + "";
    this.error = ERROR_ESPIDER.PAGE_CHANGE;
    this.tracking(resultData, this.debugDate, true);
    return false;
}

// 안전한 데이터 접근
this.safeGet = function(d) {
    d = (d === null || d === undefined) ? "" : d;
    if (typeof d == "number") d = d + "";
    return d;
};

 

오류 처리

this.userError = (new Error().lineNumber + 1) + "";
this.error = ERROR_ESPIDER.PAGE_CHANGE;
this.tracking(resultData, this.debugDate, true);
return false;

 

 

5. ES5 자바스크립트 핵심 기능의 실무 적용

5.1 프로토타입 기반 상속

Cobweb 모듈은 ES5의 프로토타입 상속을 활용하여 코드 재사용성을 높입니다.

// 부모 클래스 정의
var BaseModule = function() {
    this.commonMethod = function() {
        // 공통 기능 구현
    }
}

// 자식 클래스 정의
var ChildModule = function() {
    this.specificMethod = function() {
        // 특화 기능 구현
    }
    
    // 부모 메서드 오버라이드
    this.commonMethod = function() {
        // 기본 구현 확장
        BaseModule.prototype.commonMethod.call(this);
        // 추가 기능 구현
    }
}

// 상속 설정
ChildModule.prototype = new BaseModule();

 

5.2 클로저와 스코프

ES5의 클로저를 활용하여 모듈 내부 상태를 캡슐화할 수 있습니다.

var ScrapeModule = function() {
    // 프라이빗 변수
    var privateData = {};
    var requestCount = 0;
    
    // 프라이빗 함수
    function processData(rawData) {
        // 내부 처리 로직
        requestCount++;
        return /* 처리된 데이터 */;
    }
    
    // 퍼블릭 메서드 (클로저를 통해 프라이빗 변수/함수 접근)
    this.getData = function() {
        var rawData = this.httpConnect(/* ... */);
        return processData(rawData);
    }
    
    this.getRequestCount = function() {
        return requestCount;
    }
}

 

6. 일반적인 스크래핑 패턴 구현

6.1 선택자 시스템 구현

웹사이트 구조 변경에 대응하기 위한 견고한 선택자 시스템 예시

function findElement(container, selectors) {
    if (typeof selectors === 'string') {
        selectors = [selectors];
    }
    
    for (var i = 0; i < selectors.length; i++) {
        var element = container.querySelector(selectors[i]);
        if (element) return element;
    }
    
    return null;
}
// 사용 예시
var priceElement = findElement(productCard, [
    '.product-price',
    '.price',
    '[data-price]',
    'strong.value'
]);

 

6.2 데이터 추출 및 정제

다양한 형식의 데이터를 일관되게 추출하고 정제하는 유틸리티

var DataExtractor = {
    // 텍스트 추출
    getText: function(element, selectors, defaultValue) {
        defaultValue = defaultValue || '';
        var targetEl = findElement(element, selectors);
        return targetEl ? targetEl.textContent.trim() : defaultValue;
    },
    
    // 가격 추출 및 정규화
    extractPrice: function(element, selectors) {
        var priceText = this.getText(element, selectors);
        return priceText.replace(/[^\d]/g, '');
    },
    
    // 날짜 추출 및 변환
    extractDate: function(element, selectors, format) {
        var dateText = this.getText(element, selectors);
        // 날짜 형식 변환 로직 구현
        return formattedDate;
    }
};

 

6.3 동적 콘텐츠 처리

동적으로 로드되는 콘텐츠 처리 전략

function waitForElement(selector, timeout) {
    timeout = timeout || 10000; // 기본 10초 타임아웃
    
    var startTime = new Date().getTime();
    
    function checkElement() {
        var element = document.querySelector(selector);
        
        if (element) {
            return element;
        }
        
        if (new Date().getTime() - startTime > timeout) {
            throw new Error("Element not found within timeout: " + selector);
        }
        
        // 잠시 대기 후 다시 확인
        return null;
    }
    
    // 요소가 나타날 때까지 반복 확인
    while (true) {
        var element = checkElement();
        if (element) return element;
        
        // JavaScript에서는 동기적 대기가 불가능하므로 실제 구현은 다를 수 있음
        // Cobweb 환경에서는 별도의 대기 메커니즘 사용 필요
    }
}

 

6.4 데이터 검증 및 정합성 확인

데이터 검증 및 정합성 확인 패턴

function validateData (data, schema) {
    for (var key in schema) {
        if (schema.hasOwnProperty(key)) {
            var validator = schema[key];
            var value = data[key];
            
            if (!validator(value)) {
                return {
                    valid: false,
                    field: key,
                    value: value
                };
            }
        }
    }
    
    return { valid: true };
}

// 사용 예시
var orderSchema = {
    orderNo: function(v) { return v && v.length > 0; },
    orderDate: function(v) { return /^\d{8}$/.test(v); },
    amount: function(v) { return !isNaN(v) && v >= 0; }
};

var validationResult = validateData(orderData, orderSchema);
if (!validationResult.valid) {
    // 검증 오류 처리
}

 

7. 자바스크립트 강의 내용과 Cobweb 실무 적용

7.1 강의 주제별 Cobweb 실무 연계

강의 주제 Cobweb 모듈 적용 포인트 실제 코드 예시
변수와 상수 데이터 저장 구조 활용 this.retData = {}; this.tempData = {};
자료형과 형변환 문자열 <-> 숫자 변환 Number(this.tempData.searchStDt)
조건문 에러 처리 및 분기 로직 if (!resString) { this.error = ERROR_ESPIDER.LOGIN_PARAMTER; return false; }
함수 모듈화된 스크래핑 로직 this.getOrderData = function(orderItem, orderNo) { ... }
스코프, 호이스팅 변수 범위 관리 모듈 내부 변수와 함수 스코프
객체 데이터 구조화 var orderJson = { orderNo: orderNumber, orderDate: orderDate[0] };
배열과 반복문 목록 데이터 처리 for (var item of orderList) { ... }
DOM API 웹페이지 데이터 추출 실제 스크래핑 로직에서 DOM 요소 선택 및 데이터 추출
JSON 처리 서버 응답 파싱 resultJson = JSON.parse(resultData);
비동기 처리 HTTP 요청 관리 resultData = this.httpConnect(...);

 

7.2 ES5 문법의 실무 활용

// 1. 변수와 스코프 (강의 섹션 2, 7)
var searchStDt = this.tempData.searchStDt;
var searchEndDt = this.tempData.searchEndDt;

// 2. 조건문 (강의 섹션 5)
if (searchStDt == "" && searchEndDt == "") {
    // 조회일자 미입력 시 자동으로 현재일 기준 최근 5년 이내 내역을 조회
    this.tempData.searchStDt = resultJson.startDate.replace(/\-/g, '');
    this.tempData.searchEndDt = resultJson.endDate.replace(/\-/g, '');
}

// 3. 객체 활용 (강의 섹션 10)
var orderJson = {
    orderNo: orderNumber, // 주문번호
    orderDate: orderDate[0].replace(/\./g, ''), // 날짜(일자)
    detailList: [] // 주문내역 목록
};

// 4. 배열과 반복문 (강의 섹션 11, 12)
for (var item of orderOptionList) {
    var detailJson = {};
    detailJson.productName = item.goodsName;
    detailJson.quantity = item.quantity + "";
    // ... 추가 필드
    orderJson.detailList.push(detailJson);
}

// 5. 정규표현식 활용 (자료형 처리)
orderJson.orderDate = orderDate[0].replace(/\./g, '');

 

 

8. 주요 실무 패턴 분석

8.1 데이터 추출 패턴

Cobweb에서 웹사이트 데이터를 추출하는 핵심 패턴입니다.

// HTTP 요청을 통한 데이터 획득
resultData = this.httpConnect(new Error().lineNumber + 1, "GET",
    "/order-service/my/order/get_order_view/" + orderNumber, "", 0);
if (resultData === false) return false;

try {
    // JSON 파싱 (강의 섹션 비동기처리/API 호출)
    resultJson = JSON.parse(resultData);
} catch (e) {
    this.userError = (new Error().lineNumber + 1) + "";
    this.error = ERROR_ESPIDER.PAGE_CHANGE;
    this.tracking(resultData, this.debugDate, true);
    return false;
}

// 데이터 검증 및 안전한 접근 (강의 섹션 조건문/객체)
var orderList = this.safeGet(resultJson.orderList);
if (!orderList || orderList == "") {
    // 에러 처리
    return false;
}

 

8.2 데이터 정제 및 변환

스크래핑한 원시 데이터를 표준 형식으로 가공하는 패턴입니다.

// Convert 메소드의 핵심 패턴
for (var i = 0; i < orderList.length; i++) {
    var rec = orderList[i];

    var orderJson = {};
    orderJson[MODULE_ESPIDER.RES_OM_DATE_KEY] = "" + rec.orderDate;
    orderJson[MODULE_ESPIDER.RES_OM_ORDER_NUMBER_KEY] = "" + rec.orderNo;
    // ... 추가 필드 매핑
    
    orderJson[MODULE_ESPIDER.RES_OM_ORDER_DETAIL_LIST_KEY] = [];
    for (var j = 0; j < rec.detailList.length; j++) {
        var dt_rec = rec.detailList[j];
        
        var orderDetailJson = {};
        orderDetailJson[MODULE_ESPIDER.RES_OM_PRODUCT_NAME_KEY] = "" + dt_rec.productName;
        // ... 추가 필드 매핑
        
        orderJson[MODULE_ESPIDER.RES_OM_ORDER_DETAIL_LIST_KEY].push(orderDetailJson);
    }
    
    this.retData[MODULE_ESPIDER.RES_RESULT_KEY][MODULE_ESPIDER.RES_LISTS_KEY].push(orderJson);
}

 

8.3 안전한 데이터 접근

Cobweb에서 널 체크와 타입 변환을 통한 안전한 데이터 접근 패턴입니다.

// 안전한 데이터 획득 헬퍼 함수
this.safeGet = function(d) {
    d = (d === null || d === undefined) ? "" : d;
    if (typeof d == "number") d = d + ""; //숫자인 경우 문자열로 변경
    return d;
};

// 사용 예
var orderList = this.safeGet(resultJson.orderList);
if (!orderList || orderList == "") {
    // 에러 처리
}

 

 

9. 자주 사용되는 ES5 스크래핑 기법

9.1 데이터 포맷 변환

날짜, 금액 등의 데이터 포맷을 변환하는 기법입니다.

// 날짜 포맷 변환 (YYYY-MM-DD → YYYYMMDD)
searchStDt = this.tempData.searchStDt ? 
    this.tempData.searchStDt.substr(0, 4) + "-" + 
    this.tempData.searchStDt.substr(4, 2) + "-" + 
    this.tempData.searchStDt.substr(6, 2) : "";

// 금액에서 콤마 제거
detailJson.amount = item.receiveAmount.replace(/\,/g, '');

 

9.2 데이터 검증 및 오류 처리

데이터 유효성 검증과 오류 처리 기법입니다. 

// 필수 데이터 검증
if (
    detailJson.productName == "" ||
    detailJson.quantity == "" ||
    detailJson.amount == "" ||
    detailJson.option == "" ||
    detailJson.state == "" ||
    detailJson.lnkUrl == "" || 
    detailJson.productCode == ""
) {
    this.userError = (new Error().lineNumber + 1) + "";
    this.error = ERROR_ESPIDER.PAGE_CHANGE;
    this.tracking(JSON.stringify(item) + "\n\n[resultData]\n" + resultData, this.debugDate, true);
    return false;
}

// 날짜 검증
if (!searchStDt.checkDateString()) {
    this.error = ERROR_ESPIDER.LOGIC_CHECK_DATE;
    this.userError = (new Error().lineNumber + 1) + "";
    return false;
}

 

 

10. 실무 적용을 위한 개발 팁

10.1 ES5 호환성 유지하기

최신 자바스크립트 기능을 사용하지 않고 ES5 호환성을 유지하는 방법:

 

// ❌ 사용하지 않음: let, const (ES6)
let orderList = resultJson.list;
const hostURL = "https://www.musinsa.com";

// ✅ 사용함: var (ES5)
var orderList = resultJson.list;
this.hostURL = "https://www.musinsa.com";

// ❌ 사용하지 않음: 화살표 함수 (ES6)
orderList.forEach(item => {
    // 처리
});

// ✅ 사용함: 함수 표현식 (ES5)
for (var i = 0; i < orderList.length; i++) {
    var item = orderList[i];
    // 처리
}

// ❌ 사용하지 않음: Promise, async/await (ES6+)
async function fetchData() {
    const response = await fetch(url);
}

// ✅ 사용함: 콜백 기반 비동기 처리 (ES5)
this.httpConnect(lineNum, "GET", url, "", 0, function(result) {
    // 응답 처리
});

 

 

10.2 디버깅 및 로깅 최적화

스크래핑 모듈의 디버깅과 로깅을 효과적으로 하는 방법:

// 라인 번호 추적으로 오류 위치 파악
this.userError = (new Error().lineNumber + 1) + "";

// 상세 컨텍스트 정보 포함 로깅
this.tracking(
    JSON.stringify(item) + "\n\n[resultData]\n" + resultData,
    this.debugDate,  // ex) "20251231"
    true
);

// 중요 단계별 로깅
console.info("무신사 모듈 KROM0016011000 class 4.GetData :: module index[", 
    this.index, "] thread index[", this.threadIndex, "]");

 

 


 

 
반응형

+ Recent posts