Notice
Recent Posts
Recent Comments
관리 메뉴

즐겁게, 코드

교내 게시판 API 서버 분석 기록 본문

👨🏻‍💻 기록/기타

교내 게시판 API 서버 분석 기록

Chamming2 2021. 2. 27. 13:56

이전에 제작한 항공대 종강시계의 공지사항 탭이 죽었습니다.

이유가 뭔가 했더니 방학동안 홈페이지 리모델링이 이루어져, 기존 공지사항 게시판이 사라졌다고 하네요...!! 안돼!!

그래서 새로운 페이지의 공지사항을 크롤링해야 했는데, 페이지 렌더링 방식이 변해 공지사항을 어디선가 불러와 동적으로 렌더링하는걸 알게 되었습니다.

⚙️ 학교 게시판 함수 호출 순서 분석 과정

교내 홈페이지 코드는 확실히 공공기관이라는 보수적인 분위기 때문인지, JQuery와 함께 엄청난 스파게티가 되어 있었습니다.
메서드 호출 순서를 따라가며 교내 홈페이지 분석에 필요한 내용들을 정리해보았습니다.

1. onLoad 시 익명 함수 실행

공지사항을 확인하면 제일 먼저 실행되는 함수입니다.

$(document).ready(function () {
  fnGetBbsDfList();

  $("#srchText").keydown(function (e) {
    gfnEnter(e, "fnGetBbsDfList");
  });

  if (gv_categoryGrpId != "") {
    gfnCodeSelect(gv_categoryGrpId, "selCategory", "전체");
  }
});

2. fnGetBbsDfList 함수 실행

(실제 인자는 주어지지 않습니다. args는 왜 넣은건지 의문이네요)

function fnGetBbsDfList(args) {
  var bbsId = "0119";

  if (args != null) {
    $("#currentPageNo").val(args);
  }

  var currentPageNo = $("#currentPageNo").val();
  if (currentPageNo == "") {
    currentPageNo = 1;
  }

  console.log("args : " + args);
  console.log("selPageSize : " + $("#selPageSize").val());

  gfnGetBbsList(
    bbsId,
    currentPageNo,
    cbMakeBbsDfList,
    $("#selSearch").val(), // sparam
    $("#srchText").val(), // sparamVal
    $("#selPageSize").val(), // pageUnit
    $("#selCategory").val() // stype
  );
}

3. gfnGetBbsList 함수 실행

코드 상단에 달아놓은 주석대로 인자가 주어집니다. (param은 사용되지 않는 인자입니다.)

// 인자 설명
// bbsId: "0119"
// pageIndex: 1
// callback: cbMakeBbsDfList
// sparam: $("#selSearch").val()
// sparamVal: $("#srchText").val()
// pageUnit: $("#selPageSize").val()
// stype: $("#selCategory").val()
// param: undefined

function gfnGetBbsList(bbsId, pageIndex, callback, sparam, sparamVal, pageUnit, stype, param) {
	
	console.log("gfnGetBbsList", bbsId);
	
	var sendMap = new Map();
	sendMap.put("siteFlag", $('#siteFlag').val());
	sendMap.put("bbsId", bbsId);
	sendMap.put("pageIndex", pageIndex);
	sendMap.put("bbsAuth", $("#bbsAuth").val());
	
	if (sparam != null && sparamVal != '') {
		if (sparam == '01') {
			sendMap.put("searchCnd", "0");
			sendMap.put("searchWrd", sparamVal);
		} else if (sparam == '02') {
			sendMap.put("searchCnd", "1");
			sendMap.put("searchWrd", sparamVal);
		} else if (sparam == '03') {
			sendMap.put("searchCnd", "3");
			sendMap.put("searchWrd", sparamVal);
		} 
	}
	
	if (pageUnit != null) {
		sendMap.put("pageUnit", pageUnit);
	}
	
	if (stype != null && stype != '') {
		sendMap.put("categoryCd", stype);
	}

	console.log("gfnGetBbsList sendMap.jsonString()", sendMap.jsonString());
        // sendMap.jsonString() 객체
        // {"siteFlag":"www","bbsId":"0119","pageIndex":1,"bbsAuth":"30"}
	if (param != null) {
		ajaxSend("/web/bbs/bbsListApi.gen", sendMap.jsonString(), callback, param);
	} else {
        // param 없으니 이 로직 수행되나?
		ajaxSend("/web/bbs/bbsListApi.gen", sendMap.jsonString(), callback);
	}
};

4. ajaxSend 함수 실행

ajaxSend 함수는 www.kau.ac.kr/web/bbs/bbsListApi.gen 주소로 POST 요청을 보내고 있는 것을 확인할 수 있었습니다.

이를 커스텀하면 원하는 게시판의 정보를 불러올 수 있습니다.

// 인자 설명
// sendUrl: https://www.kau.ac.kr/web/bbs/bbsListApi.gen
// sendData: {"siteFlag":"www","bbsId":"0119","pageIndex":1,"bbsAuth":"30"} 
// 중요한 점은 sendData의 인수를 JSON으로 파싱해줘야 함.
// callback: cbMakeBbsDfList
// callbackparam:
// callbackparam2:

function ajaxSend(sendUrl, sendData, callback, callbackparam, callbackparam2) {
	
	$.ajax({
	    url:sendUrl
	    , async:true
	    , type:'POST'
	    , dataType:'json'
	    , contentType:'application/json; charset=utf-8'
	    , data: sendData
		, beforeSend : function(xhr){
            xhr.setRequestHeader("AJAX", true);
        }
		, success:function(result) {

	    	//console.log(result);
	    	
	    	if (typeof callback === "function") {
	    		if (callbackparam2 != null) {
		    		callback(result, callbackparam, callbackparam2);
	    		} else if (callbackparam != null && callbackparam2 == null) {
		    		callback(result, callbackparam);
	    		} else {
	    			callback(result);
	    		} 
	    	}

	    }
		, error:function(request, status, error){
		    console.log("code",request.status);
		    console.log("error",error);
		}
		, complete:function(xhr) {

	    }
	});
};

5. 포스트맨 테스트

-> resultList 라는 이름의 게시판 공지사항이 담긴 배열을 획득한 모습입니다.

6. 코딩 & 크롤링 완료

const cheerio = require("cheerio");
const axios = require("axios");

const getSchoolAlarm = async () => {
  const res = await axios.post(
    "https://www.kau.ac.kr/web/bbs/bbsListApi.gen",
    {
      siteFlag: "www",
      bbsId: "0119",
      pageIndex: 1,
      bbsAuth: "30",
    },
    {}
  );

  res.data.resultList.forEach(el => console.log(el.nttSj));
};

getSchoolAlarm();

배열의 각 요소를 순회하면서 nttSJ 라는 이름의 값을 추출하면 공지사항의 제목을 추출할 수 있게 됩니다!

개인적으로 이렇게 데이터만을 관리하는 교내 API 서버를 따로 운영하기 시작했다는 점에서 이번 홈페이지 변화는 긍정적인 변화라고 생각되네요!

한국항공대용 교내 서비스 개발자를 위한 가이드

- 항공대 공지사항 크롤링을 위해서는 https://www.kau.ac.kr/web/bbs/bbsListApi.gen 에 다음 body를 포함해 POST 요청을 보내면 됩니다.

 

일반공지

EndPoint: https://www.kau.ac.kr/web/bbs/bbsListApi.gen
method: POST
body: {
  siteFlag: "www",
  bbsId: "0119",
  pageIndex: 1,
  bbsAuth: "30",
},

학사공지

EndPoint: https://www.kau.ac.kr/web/bbs/bbsListApi.gen
method: POST
body: {
  siteFlag: "www",
  bbsId: "0120",
  pageIndex: 1,
  bbsAuth: "30",
},
반응형

'👨🏻‍💻 기록 > 기타' 카테고리의 다른 글

문자열에 약한 남자  (3) 2021.06.14
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆