| XML데이터 파싱부터 DB 저장까지! - 1
API를 이용하여 학원정보를 가져와야 하는데 난 당연히 json형태로 return 해줄줄 알았다. 그런데 웬걸 xml이라니! json만 쓰다보니까 xml은 까먹은지 오래였고,, 결국 구글링했서 구현했다🤣
xml 파싱해보자
사용할 API는 HRD-net에서 제공하는 구직자훈련과정 목록 API와 구직자훈련과정 과정/기관정보 API이다. 학원 정보 및 강좌에 대한 정보를 얻을 수 있다.
구직자훈련과정 목록 API (전체 과정의 정보 출력) 구직자훈련과정 과정/기관정보 API (한 과정의 상세정보를 출력)-
Url 준비
- 각 사이트에서 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객체 생성
- document객체를 통해 파싱할 url의 데이터를 읽어온다.
- documentInfo.getDocumentElement().getNodeName()을 출력하면 XML의 최상위 TAG 값을 가져온다 여기서는
<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에 접근하기
- 목록 API 기준으로 파싱할 데이터가 있는 TAG는 srchList이다.
- nList에 srchList안에 있는 태그들이 담기게 된다.
Element root = documentInfo.getDocumentElement(); NodeList nList = root.getElementsByTagName("srchList").item(0).getChildNodes();
-
nList에 담긴 데이터 꺼내오기
- for문을 이용해 파싱한 데이터를 map에 저장하고, 새로운 list에 저장한다.
- getTagValue("tagName",element) : "tagName"에 해당하는 데이터 가져오는 메소드 (아래 전체 소스코드에 있음)
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에 저장하는 코드는 다음 시간에 ... 총총 ...👀
Author And Source
이 문제에 관하여(| XML데이터 파싱부터 DB 저장까지! - 1), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yeonii/Spring-XML데이터-파싱부터-DB-저장까지-1저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)