API를 이용하여 학원정보를 가져와야 하는데 난 당연히 json형태로 return 해줄줄 알았다. 그런데 웬걸 xml이라니! json만 쓰다보니까 xml은 까먹은지 오래였고,, 결국 구글링했서 구현했다🤣
사용할 API는 HRD-net에서 제공하는 구직자훈련과정 목록 API와 구직자훈련과정 과정/기관정보 API이다. 학원 정보 및 강좌에 대한 정보를 얻을 수 있다.
구직자훈련과정 목록 API (전체 과정의 정보 출력) 구직자훈련과정 과정/기관정보 API (한 과정의 상세정보를 출력)Url 준비
String url = " https://www.hrd.go.kr/jsp/HRDP/HRDPO00/HRDPOA60/HRDPOA60_1.jsp?returnType=XML&"
//사이트에서 발급받은 인증키
+"authKey=gV6TA7Ep5JFP66lYZgtEip3bkBl6av4s"
//요청 parameters
+"&pageNum=1&pageSize=10&srchTraStDt=20210524&srchTraEndDt=20210824&outType=1&sort=ASC&sortCol=TR_STT_DT&crseTracseSe=C0055,C0054,C0059&srchKeco1=20";
Document객체 생성
<HRDNet>
이 최상위 TAG 값이다.Document documentInfo = null;
documentInfo = (Document) DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(url);
documentInfo.getDocumentElement().normalize();
//Root: HRDNet
System.out.println("Root: " + documentInfo.getDocumentElement().getNodeName());
파싱할 데이터가 있는 tag에 접근하기
Element root = documentInfo.getDocumentElement();
NodeList nList = root.getElementsByTagName("srchList").item(0).getChildNodes();
nList에 담긴 데이터 꺼내오기
List<Map<String, String>> list = new ArrayList<>();
for (int i = 0; i < nList.getLength(); i++) {
Map<String, String> map = new HashMap<>();
Node nNode = nList.item(i);
Element eElement = (Element) nNode;
map.put("trainCd", getTagValue("trprId", eElement)); // 과정코드
map.put("trainTitle", getTagValue("title", eElement)); // 과정명
map.put("acadCd", getTagValue("instCd", eElement)); // 학원코드
map.put("acadTitle", getTagValue("subTitle", eElement)); // 학원명
map.put("telNo", getTagValue("telNo", eElement)); // 학원 전화번호
map.put("startDate", getTagValue("traStartDate", eElement)); // 훈련시작일자
map.put("endDate", getTagValue("traEndDate", eElement)); // 훈련종료일자
map.put("target", getTagValue("trainTarget", eElement)); // 훈련대상
map.put("yardMan", getTagValue("yardMan", eElement)); // 정원
map.put("courseMan", getTagValue("courseMan", eElement)); // 수강비
map.put("realMan", getTagValue("realMan", eElement)); // 실제 수강비
map.put("trainDegr", getTagValue("trprDegr", eElement)); // 회차
list.add(map);
}
}
요청 parameter에 페이지수가 나눠져 있기 때문에 총 페이지 갯수를 구하여 반복문을 이용해 모든 페이지에 접근해 가져왔다!
또, 각 과정을 진행하는 학원에 대한 상세 주소와 홈페이지 url은 과정/기관정보API에서 가져와야 했기 때문에
- 목록 API를 읽어서
List<Map<String, String>>
형태로 저장- 다시 반복문을 돌려 과정/기관정보API 읽어서 상세 주소 / 홈페이지 url 데이터 Map에 넣기
- mapper로 Map을 보내서 DB에 데이터 저장/업데이트!
private static final Logger logger = LoggerFactory.getLogger(AcadScheduler.class);
@Autowired
private AcademyMapper academyMapper;
public static int PAGE_SIZE = 100;
public static String URL = "https://www.hrd.go.kr/jsp/HRDP/HRDPO00/HRDPOA60/HRDPOA60_1.jsp";
public static String URL2 = "https://www.hrd.go.kr/jsp/HRDP/HRDPO00/HRDPOA60/HRDPOA60_2.jsp";
public static String SERVICE_KEY = "gV6TA7Ep5JFP66lYZgtEip3bkBl6av4s";
public void update() throws Exception {
int result = 0;
List<Map<String, String>> list = new ArrayList<>();
try {
// 학원 목록 읽어오기
createDocument(list);
for (Map<String, String> acadInfo : list) {
createDetailInfo(acadInfo);
result += academyMapper.createAcademy(acadInfo);
}
} catch (Exception e) {
e.printStackTrace();
}
logger.info("총 학원 갯수:" + result);
}
//tag값 정보를 가져오는 메소드
private static String getTagValue(String tag, Element eElement) {
NodeList nList = null;
Node nValue = null;
try {
nList = eElement.getElementsByTagName(tag).item(0).getChildNodes();
nValue = (Node) nList.item(0);
} catch (Exception e) {
e.printStackTrace();
}
if (nValue == null)
return null;
return nValue.getNodeValue();
}
private void createDetailInfo(Map<String, String> acadInfo) {
Document documentInfo = null;
// 파싱할 url 지정
String parseUrl =
URL2 + "?returnType=XML&authKey=" + SERVICE_KEY + "&srchTrprId=" + acadInfo.get("trainCd")
+ "&srchTrprDegr=" + acadInfo.get("trainDegr") + "&outType=2&srchTorgId=default";
try {
documentInfo =
(Document) DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(parseUrl);
//root tag
documentInfo.getDocumentElement().normalize();
// 과정,기관정보 데이터 파싱
parseDetailXml(documentInfo.getDocumentElement(), acadInfo);
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
private void parseDetailXml(Element root, Map<String, String> map) {
Node nNode = root.getElementsByTagName("inst_base_info").item(0);
Element eElement = (Element) nNode;
map.put("address", getTagValue("addr1", eElement)); // 상세주소
map.put("url", getTagValue("hpAddr", eElement)); // 학원홈페이지url
}
private void parseXml(Element root, List<Map<String, String>> list) {
NodeList nList = root.getElementsByTagName("srchList").item(0).getChildNodes();
for (int i = 0; i < nList.getLength(); i++) {
Map<String, String> map = new HashMap<>();
Node nNode = nList.item(i);
Element eElement = (Element) nNode;
map.put("trainCd", getTagValue("trprId", eElement)); // 과정코드
map.put("trainTitle", getTagValue("title", eElement)); // 과정명
map.put("acadCd", getTagValue("instCd", eElement)); // 학원코드
map.put("acadTitle", getTagValue("subTitle", eElement)); // 학원명
map.put("telNo", getTagValue("telNo", eElement)); // 학원 전화번호
map.put("startDate", getTagValue("traStartDate", eElement)); // 훈련시작일자
map.put("endDate", getTagValue("traEndDate", eElement)); // 훈련종료일자
map.put("target", getTagValue("trainTarget", eElement)); // 훈련대상
map.put("yardMan", getTagValue("yardMan", eElement)); // 정원
map.put("courseMan", getTagValue("courseMan", eElement)); // 수강비
map.put("realMan", getTagValue("realMan", eElement)); // 실제 수강비
map.put("trainDegr", getTagValue("trprDegr", eElement)); // 회차
list.add(map);
}
}
private void createDocument(List<Map<String, String>> list) {
Document documentInfo = null;
int pageNum = 1;
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
Date currentDate = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(currentDate);
// 현재날짜로부터 3개월뒤 날짜 설정
cal.add(Calendar.MONTH, 3);
String stDt = formatter.format(currentDate);
String endDt = formatter.format(cal.getTime());
// URL 설정
String parseUrl = URL + "?returnType=XML&authKey=" + SERVICE_KEY + "&pageSize=" + PAGE_SIZE
+ "&srchTraStDt=" + stDt + "&srchTraEndDt=" + endDt
+ "&outType=1&sort=ASC&sortCol=TR_STT_DT&crseTracseSe=C0055,C0054,C0059&srchKeco1=20&pageNum=";
try {
int tot = 0, num = 1;
while (true) {
if (pageNum > num)
break;
documentInfo = (Document) DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(parseUrl + pageNum);
documentInfo.getDocumentElement().normalize();
if (pageNum == 1) {
// 총 학원 갯수
tot = Integer.parseInt(getTagValue("scn_cnt", documentInfo.getDocumentElement()));
num = (tot / PAGE_SIZE) + 1;
}
// 목록 정보 데이터 파싱하기
parseXml(documentInfo.getDocumentElement(), list);
pageNum++;
}
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
DB에 저장하는 코드는 다음 시간에 ... 총총 ...👀