[Android/Kotlin] 공공데이터 XML 파싱 및 크롤링으로 데이터 가져오기

Falco·2022년 5월 8일
0

Android

목록 보기
6/55
post-thumbnail
post-custom-banner

코로나 확진 현황 및 근황을 긁어 모아서 출력해주는 앱을 만들으면서 진행했던 과정이다.

GitHub 링크

XML 파싱

공공데이터 포털에서 제공하는 API로 서울의 최근 일주일동안 코로나 확진자 수를 파싱하였다.

파싱했던 데이터 구조

<body>
<items>
....
<item>
<createDt>2020-04-10 09:00:00.000</createDt>
<deathCnt>208</deathCnt>
<defCnt>10450</defCnt>
<gubun>합계</gubun>
<gubunCn>合计</gubunCn>
<gubunEn>Total</gubunEn>
<incDec>27</incDec>
<isolClearCnt>6871</isolClearCnt>
<localOccCnt>17</localOccCnt>
<overFlowCnt>10</overFlowCnt>
<qurRate>20.16</qurRate>
<seq>1558</seq>
<stdDay>2020년 04월 10일 00시</stdDay>
<updateDt>2021-09-16 10:11:33.897</updateDt>
</item>

반복 ....

incDec -> 신규확진자

Android Developer에서 소개하는 XmlPullParserFactory을 사용하여 파싱을 진행하였다.

private fun xmlParse2(result: String) : ArrayList<String> {
		// XmlPullParser 인스턴스 생성
        val factory = XmlPullParserFactory.newInstance()
        factory.isNamespaceAware = true
        val xpp = factory.newPullParser()
        // xml String을 넣어준다.
        xpp.setInput(StringReader(result))

        // 신규 확진자
        var incDec = false
        var incDec_num = ""
        // 서울인지 체크
        var isSeoul = false
        // 지역 명
        var gubun = false
        // 7일치 신규 확진자 값을 넣을 배열
        var resultArray = ArrayList<String>()

        try {
            var eventType = xpp.eventType
            while (eventType != XmlPullParser.END_DOCUMENT) {
                if (eventType == XmlPullParser.START_DOCUMENT) { // 0
                } else if (eventType == XmlPullParser.START_TAG) { // 1 ...
                	// START_TAG일때 <inDec>, <pubDate>....
                    if (xpp.name == "incDec") {
                        incDec = true
                    }else if (xpp.name == "gubun") {
                        gubun = true
                    }else if (xpp.name == "updateDt") {
                    // updateDt가 incDec보다 후에 있음으로,
                    // 한번 다 돌았을 때 incDec값을 어레이에 넣어준다.
                        if (isSeoul) {
                            resultArray.add(incDec_num)
                        }
                        isSeoul = false
                    }
                } else if (eventType == XmlPullParser.END_TAG) {
                // TEXT에 태그안의 내용이 온다.
                } else if (eventType == XmlPullParser.TEXT) {
                    if (incDec) {
                        incDec_num = xpp.text
                        incDec = false
                    } else if (gubun) {
                        if (xpp.text == "서울") {
                            isSeoul = true
                        }
                        gubun = false
                    }
                }
                // 다음줄로 가기
                eventType = xpp.next()
            }
        } catch (e: Exception) {
            Log.e("Network APi Error", "getSeoulCovidMain2 Error")
        }
        return resultArray
    }

그다지 어렵지는 않고 데이터 형식에 소스를 맞추는 거라 너무 귀찮고 복잡했다.

Jsoup을 사용한 크롤링

결과 이미지

서울시 코로나 사이트에 있는 연령대별 확진자 현황 표에서 데이터를 긁어왔다.

		// 연령별 확진자 크롤링
        
        // 크롤링 URL
        val crollingUrl = "https://www.seoul.go.kr/coronaV/coronaStatus.do"
        
        CoroutineScope(Dispatchers.IO).launch {
        
            // URL 웹사이트에 있는 html 코드를 다 끌어오기, Jsoup 라이브러리 사용
            val doc: Document = Jsoup.connect(crollingUrl).get()
            
            // cssQuery로 원하는 부분 가져오기
            val temele: Elements =
                doc.select(".table-scroll .tstyle-status tbody tr td") 
             
             //빼온 값 null체크
            val isEmpty = temele.isEmpty()
            
            //null값이 아니면 크롤링 실행
            if (!isEmpty) {
                val covidnumage = ArrayList<String>()
                for (i in 1..8) {
                    covidnumage.add(temele[i].text())
                }
                // UI건드리는 부분은 메인쓰레드에서만 가능
                requireActivity().runOnUiThread {
                	// PieChart 그리기
                    setPieChart(covidnumage)
                }
            }
        }

크롬 개발자모드에서 위치 확인

profile
강단있는 개발자가 되기위하여
post-custom-banner

0개의 댓글