Today's

길을 나서지 않으면 그 길에서 만날 수 있는 사람을 만날 수 없다

모바일 앱(안드로이드)

안드로이드 앱 만들기 Jsoup 파싱을 해 볼까 ?

Billcorea 2021. 6. 30. 23:18
반응형

python 이나, java 에서 소스를 이용해서 jsoup 파싱을 해 보기는 했으나,  android 폰에서 구현하는 파싱은 이번이 처음이다. 

예전에 lotto 당첨 결과를 얻어오는 앱을 만들어 본 적이 있는데, 

그때는 정말 날코딩으로 html 페이지를 분석해서 쪼개여 왔는데, 이제 그 보다 쉬운 방법이 있다는 것이다. 

동행복권 페이지에서 회차별 당첨 결과를 조회하는 페이지를 열어서 F12(개발자도구)을 이용해서 페이지에서 얻어와야 하는 html tag 을 찾아보자. 

다음은 android studio 에서 새 프로젝트를 하나 만들고... 제일 먼저 그래드 설정에 다음과 같이 jsoup 사용을 위해 추가해 본다. (2021.06.30 기준 버전은 1.13.1)

dependencies {

    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'org.jsoup:jsoup:1.13.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

그 다음은 manifast 파일을 열어서 인터넷 사용을 위한 권한 설정을 한다.

    <uses-permission android:name="android.permission.INTERNET" />

그리고 다음은 화면을 그릴껀데, 이건 예제 이므로 단순하게  버튼 하나와 textView 하나만 담았다.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@+id/button"
        android:scrollbars="vertical"
        android:text="" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentBottom="true"
        android:layout_marginEnd="22dp"
        android:layout_marginBottom="43dp"
        android:text="HTML 가져오기" />

</RelativeLayout>

 

그리고 이번에는 MainActivity 구현을 해 본다.

소스에서 살펴볼 부분은 AsyncTask 을 이용해서 비동기 통신을 해야 한다는 것과  어떻게 하면 결과 숫자값만 뽑아올 수 있는 가 하는 부분이다.  위에 html 결과에서 span tag 을 값을 받아와야 하는 데 class 만 표시 되어 있어서 그 class 의 공통적인 종류를 이용해서 필요한 부분이 결과만 추출해 오면 된다.

package com........;

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.Arrays;

public class MainActivity extends AppCompatActivity {

    private String drwNoUrl = "https://dhlottery.co.kr/gameResult.do?method=byWin";
    private TextView textviewHtmlDocument;
    private String htmlContentInStringFormat = "";
    private String nowCnt = "" ;
    String TAG = "Lotto" ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textviewHtmlDocument = (TextView) findViewById(R.id.textView);
        textviewHtmlDocument.setMovementMethod(new ScrollingMovementMethod());

        Button htmlTitleButton = (Button) findViewById(R.id.button);
        htmlTitleButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                nowCnt = "969"; // 2021.06.30 기준 마지막 회차
                JsoupAsyncTask jsoupAsyncTask = new JsoupAsyncTask();
                jsoupAsyncTask.execute(drwNoUrl, nowCnt);

            }
        });
    }

    // 백그라운드 호출을 해야 하는 것은 실시간으로 답을 받아올 수 없기 때문에
    private class JsoupAsyncTask extends AsyncTask<String, Void, Void> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Void doInBackground(String... params) {
            Log.i(TAG, Arrays.toString(params));
            try {
                // 파라미터로 넘어온 값을 이용해서 url 와 회차를 설정한다.
                String callUrl = params[0] + "&drwNo=" + params[1];
                Document doc = Jsoup.connect(callUrl).get();
                // 위의 html tag에서 결과숫자를 싸고 있는 span tag 을 class명을 이용함.
                Elements links = doc.select(".ball_645");
                Log.e(TAG, "links=" + links.size());
                htmlContentInStringFormat += "회차=" + nowCnt ;
                for(Element el : links) {
                    Log.e(TAG, el.text()) ;
                    htmlContentInStringFormat += " " + el.text() ;
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            textviewHtmlDocument.setText(htmlContentInStringFormat);
        }
    }    
}

AsyncTask를 사용하면 UI 스레드를 적절하고 쉽게 사용할 수 있다. 이 클래스를 사용하면 스레드 및 / 또는 핸들러를 조작하지 않고도 백그라운드 작업을 수행하고 UI 스레드에 결과를 게시 할 수 있다.

AsyncTask는 Thread and Handler에 대한 도우미 클래스로 설계되었으며 일반적인 스레딩 프레임 워크를 구성하지 않는다. AsyncTasks는 짧은 작업 (최대 몇 초)에 이상적으로 사용되어야 한다.

화면의 결과가 초라해(?) 보이기는 해도 쉽게 그 결과를 얻어올 수 있었다.

 

살펴보고 궁금한 것이 있으시다면.  댓글을 달아 주세요.

반응형