Spring

공공데이터 Springboot로 파싱

쭈녁 2024. 4. 13. 02:37

 

부트캠프 3차 프로젝트의 데이터 세팅을 위해 공공 데이터를 활용하였다.

공공데이터의 제공 방식이 각각 다르다

어떤 경우엔 CSV로 row data를 모두 제공하는 경우가 있고 OpenAPI를 통해 조회가 가능하게 열어두는 경우가 있었다.

 

내가 활용할 데이터는 후자의 경우였는데 심지어 한 번에 1000건밖에 조회가 되지 않았다.... (파싱 하는데 루프를 돌려야 했다.. 아오)

 

공공데이터 활용을 정리해보았다.

 

1. 원하는 공공데이터 포탈에 방문하여 데이터 제공 방식을 확인

2. OpenAPI 이용 신청

 

 

3. 나의 경우엔 식품의약품안전처에 회원가입하여 인증키를 받았다.

 

 

 

4. API 요청 URL에 인증키를 넣어 요청하는 방식이었다.

 

5. 데이터 파싱

 

아래는 json 타입으로 받은 데이터를 파싱 하는 코드이다.

나의 경우엔 비정형화되어 있는 데이터의 카테고리를 구분하고 검색을 위한 해쉬태그도 빼내고 싶어서 추가 코드를 작성하였다. (해쉬태그를 뽑아내는 정상적인 방법은 아니지만.. 현재 내가 할 수 있는 최선...)

@RestController
@RequiredArgsConstructor
public class InitController {
    private final MedicineRepository medicineRepository;
    private final CategoryRepository categoryRepository;
    private final CustomHashTagRepository hashTagRepository;

    @GetMapping("/init")
    public ResponseEntity<String> init() throws IOException, ParseException {
        HashMap<String, Integer> categoryHM = new HashMap<>();
        HashMap<String, Integer> hashtagHM = new HashMap<>();


        for (int i = 37; i >= 1; i--) {
            setDB(i, categoryHM, hashtagHM);
        }

        List<Category> categoryList = categoryHM.keySet().stream().map(s -> Category.builder().displayName(this.toCategoryDisplayName(s)).detailName(s).itemCount(categoryHM.get(s)).build()).toList();
        categoryRepository.saveAll(categoryList);

        List<CustomHashTag> hashTagList = hashtagHM.keySet().stream().map(s -> CustomHashTag.builder().displayName(this.toHashTagDisplayName(s)).detailName(s).itemCount(hashtagHM.get(s)).build()).toList();
        hashTagRepository.saveAll(hashTagList);

        return new ResponseEntity<>("ok", HttpStatus.OK);
    }

    private String toCategoryDisplayName(String s) {
                String str1 = s.replaceAll(" ", "");
                String str = str1.replaceAll("제품", "");
                int index = str.indexOf("(");
                if (index != -1) {
                    str = str.substring(0, index);
                }
                return str;
    }
    private String toHashTagDisplayName(String s) {
                String str = s.replaceAll(" ", "");
                int index = str.indexOf("(");
                if (index != -1) {
                    str = str.substring(0, index);
                }
                return str;
    }

    private void setDB(int k, HashMap<String, Integer> set, HashMap<String ,Integer>hashtagHM) throws IOException, ParseException {
        int end = k * 1000;
        int start = end - 999;

        String urlStr = "https://openapi.foodsafetykorea.go.kr/api/privateKey/I0030/json/" + start + "/" + end;

        URL url = new URL(urlStr);
        BufferedReader br;
        br = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));

        String result = br.readLine();
        JSONParser jsonParser = new JSONParser();
        JSONObject jsonObject = (JSONObject) jsonParser.parse(result);

        JSONObject i0030 = (JSONObject) jsonObject.get("I0030");

        JSONArray array = (JSONArray) i0030.get("row");

        for (int i = 0; i < array.size(); i++) {
            JSONObject tmp = (JSONObject) array.get(i);

            String rawmtrlNm = (String) tmp.get("RAWMTRL_NM");
            String iftknAtntMatrCn = (String) tmp.get("IFTKN_ATNT_MATR_CN");

            Medicine entity = Medicine.builder()
                    .BSSH_NM((String) tmp.get("BSSH_NM"))
                    .CAP_RAWMTRL_NM((String) tmp.get("CAP_RAWMTRL_NM"))
                    .DISPOS((String) tmp.get("DISPOS"))
                    .ETC_RAWMTRL_NM((String) tmp.get("ETC_RAWMTRL_NM"))
                    .FRMLC_MTRQLT((String) tmp.get("FRMLC_MTRQLT"))
                    .CSTDY_MTHD((String) tmp.get("CSTDY_MTHD"))
                    .INDUTY_CD_NM((String) tmp.get("INDUTY_CD_NM"))
                    .HIENG_LNTRT_DVS_NM((String) tmp.get("HIENG_LNTRT_DVS_NM"))
                    .LCNS_NO((String) tmp.get("LCNS_NO"))
                    .IFTKN_ATNT_MATR_CN(iftknAtntMatrCn)
                    .POG_DAYCNT((String) tmp.get("POG_DAYCNT"))
                    .INDIV_RAWMTRL_NM((String) tmp.get("INDIV_RAWMTRL_NM"))
                    .LAST_UPDT_DTM((String) tmp.get("LAST_UPDT_DTM"))
                    .NTK_MTHD((String) tmp.get("NTK_MTHD"))
                    .PRDLST_CDNM((String) tmp.get("PRDLST_CDNM"))
                    .PRDLST_NM((String) tmp.get("PRDLST_NM"))
                    .PRMS_DT((String) tmp.get("PRMS_DT"))
                    .PRDLST_REPORT_NO((String) tmp.get("PRDLST_REPORT_NO"))
                    .RAWMTRL_NM(rawmtrlNm)
                    .PRDT_SHAP_CD_NM((String) tmp.get("PRDT_SHAP_CD_NM"))
                    .PRIMARY_FNCLTY((String) tmp.get("PRIMARY_FNCLTY"))
                    .PRODUCTION((String) tmp.get("PRODUCTION"))
                    .STDR_STND((String) tmp.get("STDR_STND"))
                    .DISPOS((String) tmp.get("DISPOS"))
                    .heartCount(0)
                    .build();

            medicineRepository.save(entity);


            exCategory(set, rawmtrlNm);

            exHashtag(hashtagHM, iftknAtntMatrCn);
        }

    }

    private static void exCategory(HashMap<String, Integer> set, String rawmtrlNm) {
        String[] split = rawmtrlNm.split(", ");

        for (String s : split) {
            set.put(s, set.getOrDefault(s, 0) + 1);
        }
    }

    private static void exHashtag(HashMap<String, Integer> hashtagHM, String iftknAtntMatrCn) {
        String[] ifsplit = iftknAtntMatrCn.replaceAll("[^ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z]", " ").split(" ");
        for (String s : ifsplit) {
            if(s.equals(" ")|| StringUtils.isEmpty(s)) continue;
            char last = s.charAt(s.length() - 1);
            if (last == '을' || last == '는' || last == '이' || last == '가' || last == '은'|| last == '에'|| last == '의'|| last == '와') {
                s = s.substring(0, s.length() - 1);
            }
            hashtagHM.put(s, hashtagHM.getOrDefault(s, 0) + 1);
        }
    }

}

 

6. 데이터베이스 저장 결과물

 

해쉬태그 테이블

 

카테고리 테이블

 

영양제 테이블

 

 

'Spring' 카테고리의 다른 글

Spring boot 의 내장 톰캣  (0) 2024.04.21
서블릿 컨테이너, 애플리케이션 초기화  (1) 2024.04.20
Security CORS 설정  (0) 2024.03.17
Security 인가(Authorization) 적용  (1) 2024.03.16
Mappstruct 사용  (0) 2024.03.11