관리 메뉴

막내의 막무가내 프로그래밍 & 일상

[코틀린] Jsoup 파싱 라이브러리 사용 기록 본문

안드로이드/코틀린 & 아키텍처 & Recent

[코틀린] Jsoup 파싱 라이브러리 사용 기록

막무가내막내 2020. 5. 21. 20:05
728x90

 

 

[2021-04-13 업데이트]

 

 

https://jsoup.org/

 

jsoup Java HTML Parser, with the best of HTML5 DOM methods and CSS selectors.

jsoup: Java HTML Parser jsoup is a Java library for working with real-world HTML. It provides a very convenient API for fetching URLs and extracting and manipulating data, using the best of HTML5 DOM methods and CSS selectors. jsoup implements the WHATWG H

jsoup.org

 

학교 공지사항 불러오는 앱을 아키텍처 공부용으로 간단하게 시간날때 해보고 있습니다. 

 

 

https://github.com/florent37/RxRetroJsoup

 

florent37/RxRetroJsoup

A simple API-like from html website (scrapper) for Android, RxJava2 ready ! - florent37/RxRetroJsoup

github.com

처음에 RxJsoup 이라고 위 라이브러리를 사용해봤었습니다. RxJava 와 Jsoup 을 연결해준 라이브러리라고 보면 됩니다.

그런데 하라는대로 다했는데 안되고 여기의 샘플 프로젝트의 주소로도 했는데 안되길래 기본 Jsoup을 사용하기로 했습니다.

 

Jsoup 은 처음 사용해봤는데 나중에도 간단한 파싱을 하기 위해 기록용 포스팅을 남깁니다.

주석으로 설명을 달았습니다.

 

 

[학교 공지 html 입니다]

 

 

 

[코틀린 Jsoup 구현입니다. ]

위와 같이 tr class 가 "" 로  class 이름이 없어 번호, 공지제목, 링크 를 한번에 갖고 올 수 가 없어 어쩔 수 없이 각각 두개로 나눠서 가져왔습니다. 이 때 withIndex() 코틀린 반복문 함수를 사용했는데 알고리즘을 할 때 안뒤로 유용하게 잘 사용하고 있습니다. ㅎㅎ

package com.mtjin.cnunoticeapp.data.bachelor.source.remote

import android.util.Log
import com.mtjin.cnunoticeapp.data.bachelor.BachelorNotice
import io.reactivex.Single
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.select.Elements


class BachelorNoticeRemoteDataSourceImpl : BachelorNoticeRemoteDataSource {
    override fun requestNotice(): Single<List<BachelorNotice>> {

        val bachNoticeList: ArrayList<BachelorNotice> = ArrayList()
        val doc: Document =
            Jsoup.connect("https://computer.cnu.ac.kr/computer/notice/bachelor.do").get() // Base Url
        val contentElements: Elements = doc.select("div[class=b-title-box]").select("a") // title, link 
        val idElements: Elements = doc.select("td[class=b-num-box]") // id값
        for ((i, elem) in contentElements.withIndex()) {
            Log.d("APPTEST", "" + idElements[i].text()) // 아이디
            Log.d("APPTEST", elem.text()) // 제목
            Log.d("APPTEST", "" + elem.attr("href")) // 링크
            bachNoticeList.add(BachelorNotice(idElements[i].text(), elem.text(), elem.attr("href")))
        }
        return Single.just(bachNoticeList)
    }

    override fun requestNotice(offset: Int): Single<List<BachelorNotice>> {
        TODO("Not yet implemented")
    }

}

 

참고로 위와 같이 메인스레드에서 Jsoup 통신을하면 에러가난다

그러므로 밑과 같이 rxjava2 를 사용하거나 코루틴 , Asynctask 를 통해서 구현하도록하자

package com.mtjin.cnunoticeapp.data.bachelor.source.remote

import com.mtjin.cnunoticeapp.data.bachelor.BachelorNotice
import io.reactivex.Observable
import io.reactivex.Single
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.select.Elements

class BachelorNoticeRemoteDataSourceImpl : BachelorNoticeRemoteDataSource {
    override fun requestNotice(): Single<List<BachelorNotice>> {
        return Single.fromObservable(
            Observable.create {
                val bachNoticeList: ArrayList<BachelorNotice> = ArrayList()
                val doc: Document =
                    Jsoup.connect("https://computer.cnu.ac.kr/computer/notice/bachelor.do")
                        .get() // Base Url
                val contentElements: Elements =
                    doc.select("div[class=b-title-box]").select("a") // title, link
                val idElements: Elements = doc.select("td[class=b-num-box]") // id값
                for ((i, elem) in contentElements.withIndex()) {
                    bachNoticeList.add(
                        BachelorNotice(
                            idElements[i].text(),
                            elem.text(),
                            elem.attr("href")
                        )
                    )
                }
                it.onNext(bachNoticeList)
                it.onComplete()
            }
        )
    }

    override fun requestMoreNotice(offset: Int): Single<List<BachelorNotice>> {
        return Single.fromObservable(
            Observable.create {
                val bachNoticeList: ArrayList<BachelorNotice> = ArrayList()
                val doc: Document =
                    Jsoup.connect("https://computer.cnu.ac.kr/computer/notice/bachelor.do?mode=list&&articleLimit=10&article.offset=$offset")
                        .get() // Base Url
                val contentElements: Elements =
                    doc.select("div[class=b-title-box]").select("a") // title, link
                val idElements: Elements = doc.select("td[class=b-num-box]") // id값
                for ((i, elem) in contentElements.withIndex()) {
                    if (idElements[i].text() != "공지") { // 공지는 매 페이지마다 있으므로 중복제거
                        bachNoticeList.add(
                            BachelorNotice(
                                idElements[i].text(),
                                elem.text(),
                                elem.attr("href")
                            )
                        )
                    }
                }
                it.onNext(bachNoticeList)
                it.onComplete()
            }
        )
    }

}

 

[로그 결과]

제대로 파싱이 되는걸 볼 수 있다.

 

 

댓글과 공감은 큰 힘이 됩니다. 감사합니다. !!!!

 

 

 

728x90
Comments