본문 바로가기
오늘은 뭘 배울까?/Android

Retrofit으로 html response 얻기 (webView 사용 아님)

by Kim Juhwan 2021. 3. 16.

1. 웹 페이지의 종류
2. 크롤링
   2-1. 준비해야 할 것
   2-2. html 요청 및 처리
3. 시도해본 방법들
   3-1. JSON으로 받기
   3-2. html 요청 및 처리
   3-3. webView

 

 

 


 

 

 

시간 낭비하지 말고 해당되지 않으면 돌아가세요!

 

나는 정적 페이지를 크롤링하고 싶다 -> '안드로이드 jsoup 파싱' 검색

나는 동적 페이지를 크롤링 할건데 JSON으로 결과를 받을 거다 -> '안드로이드 retrofit' 검색

나는 동적 페이지를 크롤링 할건데 HTML으로 결과를 받을 거다 -> 계속 읽으세요

나는 뭔소린지 1도 모르겠다 -> [목차 1]까지 읽어보세요

retrofit response html, android javascript parse, call.enqueue not working 등 이런 키워드로 검색해서 들어왔다

-> 저랑 같은 문제를 겪고 계실지도..? 계속 읽어보세요

 

 

1. 웹 페이지의 종류

우선 웹 페이지의 종류에 대해 알아야 한다. 종류에 따라 크롤링 방법을 달리 해야 하기 때문이다.

웹 페이지는 크게 2가지로 분류할 수 있다.

  • 정적 페이지
  • 동적 페이지

그리고 요청을 보내서 받게 되는 값도 2가지로 분류할 수 있다. (더 있긴 함)

  • HTML
  • JSON

이 요청을 보내는 대상(정적 페이지 or 동적 페이지)과 받게 되는 값(HTML or JSON)에 따라 방법을 다르게 써야 한다.

웹 알못인 나는 이것 때문에 삽질을 얼마나 했는지 모른다 후

모든 방법을 다 기록하기엔 글이 너무 길어질 것 같고 또 다른 블로그 글도 많아서

이 게시물에서는 내가 삽질한 동적 페이지 + html 케이스 경우만 다루려고 한다.

 

정적 페이지가 무엇인지에 대해서는 여기 게시물의 [목차 5-2]에 적어두었다.

 

https://www.postman.com/downloads/

 

돌려주는 값이 HTML인지 JSON인지는 Postman이라는 프로그램에 돌려보면 알 수 있다.

 

2. 크롤링

2-1. 준비해야 할 것

<uses-permission android:name="android.permission.INTERNET"/> // 인터넷 사용 권한

android:usesCleartextTraffic="true" // HTTP 접근 허용

Manifest 파일에 위 두 속성을 추가한다.

permission은 <Manifest> 태그 안에 넣으면 되고

usesCleartextTraffic은 <application> 태그 안에 넣으면 된다.

 

    // coroutine
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'

    // Retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.6.2'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'

비동기 실행을 위해 코루틴을, POST request를 위해 Retrofit을 gradle에 추가하자.

 

2-2. html 요청 및 처리

interface JsonPlaceHolderApi {

    @FormUrlEncoded
    @POST("여기는 맨 끝에 있는 '/' 뒤에 꺼")
    fun boardListPost(@FieldMap fields: MutableMap<String, String>): Call<ResponseBody>
}

object NoticeNetwork {
    private const val baseUrl = "여기에는 베이스 url"

    private val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

    fun getJsonApi(): JsonPlaceHolderApi {
        return retrofit.create(JsonPlaceHolderApi::class.java)
    }
}
ResponseBody는 받아온 데이터를 가공 없이 출력하기 위한 자료형이다.

 

        val call = NoticeNetwork.getJsonApi().boardListPost(parameter)

        call.enqueue(object : Callback<ResponseBody> {
            override fun onResponse(
                call: Call<ResponseBody>,
                response: Response<ResponseBody>
            ) {
                if(response.isSuccessful) {
                    try {
                        response.body()!!.string() // <- 여기에 결과가 들어있음
                    } catch (e: Exception) {

                    }
                }
            }

            override fun onFailure(call: Call<ResponseBody>, t: Throwable) {

            }
        })
body에는 인스턴스의 주소값이 들어있으므로 그냥 사용하면 안 된다.

parameter에 필수 파라미터 값을 넣어서 post요청을 보내고 (get이면 get을 해야겠쥬?)

최종적으로 body()에 결과가 담겨 나오는데 string()으로 메서드를 사용하면 데이터를 얻을 수 있다.

(toString 아님!!) 이제 얻은 데이터를 Jsoup으로 원하는 대로 파싱 해서 사용하면 된다.

 

결론은 일반적인 retrofit 사용방법에서 <ResponseBody>를 사용하고 string()만 사용하면 된다는 거

나는 이걸 몰라서 몇 시간 동안 헛짓거리 하고 다녔다는 거

 

        lifecycleScope.launch(Dispatchers.IO){
            var rep = NoticeRepository()
            rep.requestPost()
        }

액티비티에서 비동기 실행을 해야 함을 잊지 말자.

이것저것 시도해보다가 예제 코드 구조가 약간 개떡같이 됐지만 잘 돌아간다.

 

3. 시도해본 방법들

3-1. gson

    var gson = GsonBuilder().setLenient().create() // 이걸

    private val retrofit = Retrofit.Builder()
            .baseUrl(baseUrl)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create(gson)) // 여기다가 넣음
            .build()

이렇게 하면 된다고 해서 이렇게도 해봄

 

3-2. webView

webView를 이용해 해결하신 분의 글은 여기에서 볼 수 있다.

웹뷰를 통해 실제로 해당 페이지에 들어가서 크롤링하는 방법도 있었다.

왜인지 모르겠지만 난 이 방법도 먹히질 않았다. 정적인 부분은 잘 긁어와 지는데 동적인 부분은 가져오질 못했다.

관련 글이 많이 있는 게 아닌 걸로 봐서 정석 방법은 아닌 것 같다. 약간 야매 느낌?

 

그 외에 다양하게 이것저것 시도해봤는데 진짜 너무 엉뚱한 방향으로 삽질을 해서.. 안 적어야겠다.. 부끄러움...

 


💡 느낀 점

  • 앱 개발자가 꿈이지만 웹에 대해서도 공부가 많이 필요할 것 같다.
  • 파이썬에서 셀레니움을 이용하는 것처럼 안드로이드에서 웹뷰를 이용해 크롤링을 할 수 있다니.. 흥미로웠다.
  • okhttp가 retrofit의 베이스라는 걸 공부해놓고 망각하고 있었다. 리마인드 하게 됨

📘 참고한 자료


반응형

댓글