티스토리 뷰

Jsoup : HTML 파싱 자바 라이브러리


Jsoup은 웹 사이트의 내용을 쉽게 파싱하여 가져올 수 있도록 만들어진 자바 라이브러리이다.


Jsoup을 이용하여 로또 당첨사이트의 당첨 번호와 이미지를 가져오는 예제를 실습해보았다.

http://www.nlotto.co.kr/common.do?method=main     에서 



이것과 비슷하게 만들어보았다.



레이아웃 만들기

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.ktds.jmj.mybeaconapplication.CouponActivity">

<TextView
android:id="@+id/tvLatestLotto"
android:gravity="center"
android:textSize="30dp"
android:textStyle="bold"
android:textColor="#0054FF"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="20dp"
android:orientation="horizontal">

<ImageView
android:id="@+id/ivNumber1"
android:layout_width="40dp"
android:layout_height="40dp" />
<ImageView
android:id="@+id/ivNumber2"
android:layout_width="40dp"
android:layout_height="40dp" />
<ImageView
android:id="@+id/ivNumber3"
android:layout_width="40dp"
android:layout_height="40dp" />
<ImageView
android:id="@+id/ivNumber4"
android:layout_width="40dp"
android:layout_height="40dp" />
<ImageView
android:id="@+id/ivNumber5"
android:layout_width="40dp"
android:layout_height="40dp" />
<ImageView
android:id="@+id/ivNumber6"
android:layout_width="40dp"
android:layout_height="40dp" />
<TextView
android:text=" + "
android:textSize="30dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/ivNumber7"
android:layout_width="40dp"
android:layout_height="40dp" />
</LinearLayout>

<TextView
android:id="@+id/tvWinGameCount"
android:gravity="center"
android:paddingTop="20dp"
android:textSize="18dp"
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/tvWinGameMoney"
android:gravity="center"
android:paddingTop="20dp"
android:textSize="18dp"
android:textStyle="bold"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>



인터넷 권한

인터넷 권한을 얻기 위해 AndroidManifest.xml 에 INTERNET permission 코드를 추가한다.

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


인터넷권한을 위한 PermissionRequester 클래스 파일 만들기


package com.ktds.jmj.mybeaconapplication;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;

/**
* Created by Minchang Jang on 2016-06-12.
*/
public class PermissionRequester {

/**
* 요청 AndroidOS의 버젼이 마쉬멜로우 이상 버젼이 아닐 경우
*/
public static final int NOT_SUPPORT_VERSION = 2;

/**
* 요청 권한을 이미 가지고 있을 경우
*/
public static final int ALREADY_GRANTED = -1;

/**
* 권한을 System에게 요청한 경우
* ActivityonRequestPermissionsResult() 로 결과 리턴됨.
*/
public static final int REQUEST_PERMISSION = 0;

private Activity context;
private Builder builder;

private void setBuilder(Builder builder) {
this.builder = builder;
}

private PermissionRequester(Activity context) {
this.context = context;
}

public int request(final String permission, final int requestCode, final OnClickDenyButtonListener denyAction) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
/*
* 해당 App이 특정 권한을 가지고 있는지 검사함.
* 리턴결과는 PackageManager.PERMISSION_DENIED PackageManager.PERMISSION_GRANTED로 나눠짐.
* PackageManager.PERMISSION_DENIED : 권한이 없음
* PackageManager.PERMISSION_GRANTED : 권한이 있음.
*/
int permissionCheck = ContextCompat.checkSelfPermission(context, permission);

/*
* 해당 권한이 없을 경우 처리 방법
*/
if (permissionCheck == PackageManager.PERMISSION_DENIED) {

/*
* 권한을 취득할 때 사용자로부터 확인을 받아야 하는지 확인
* 여기서 true가 나올 경우는 해당 앱에서 한번이라도 권한을 Deny한 경우일 때 말고는 없음.
* 권한에 대해서 허가하지 않은 경우 다시 한번 권한의 취득을 위해 사용자에게 이유를 고지해야 함.
* Marshmellow 버젼 이상부터 사용가능함.
*/
if (context.shouldShowRequestPermissionRationale(permission)) {

/*
* 권한 취득해야 하는 이유를 Dialog 등을 통해서 알린다.
*/
AlertDialog.Builder dialog = new AlertDialog.Builder(context);
dialog.setTitle(builder.getTitle())
.setMessage(builder.getMessage())
.setPositiveButton(builder.getPositiveButtonName(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
/*
* 권한의 취득을 요청한다.
* 취득하고자 하는 권한을 배열에 넣고 요청한다.
* 뒤에 들어가는 파라미터(requestCode) onRequestPermissionsResult() 에서 권한 취득 결과에서 사용된다.
* startActiviryForResult Request Code와 유사함.
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
context.requestPermissions(new String[]{permission}, requestCode);
}
}
})
.setNegativeButton(builder.getNegativeButtonName(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
denyAction.onClick(context);
}
}).create().show();

return REQUEST_PERMISSION;
} else {
/*
* 권한의 취득 요청을 처음 할 때
* 권한의 취득을 요청한다.
* 취득하고자 하는 권한을 배열에 넣고 요청한다.
* 뒤에 들어가는 파라미터(1000) onRequestPermissionsResult() 에서 권한 취득 결과에서 사용된다.
* startActiviryForResult Request Code와 유사함.
*/
context.requestPermissions(new String[]{permission}, requestCode);
return REQUEST_PERMISSION;
}

} else {
/*
* 이미 권한을 가지고 있을 경우
* 해야할 일을 수행한다.
*/
return ALREADY_GRANTED;
}

}

return NOT_SUPPORT_VERSION;
}

public static class Builder {

private PermissionRequester requester;

public Builder(Activity context) {
requester = new PermissionRequester(context);
}

private String title = "권한 요청";
private String message = "기능의 사용을 위해 권한이 필요합니다.";
private String positiveButtonName = "";
private String negativeButtonName = "아니요";

public String getTitle() {
return title;
}

public Builder setTitle(String title) {
this.title = title;
return this;
}

public String getMessage() {
return message;
}

public Builder setMessage(String message) {
this.message = message;
return this;
}

public String getPositiveButtonName() {
return positiveButtonName;
}

public Builder setPositiveButtonName(String positiveButtonName) {
this.positiveButtonName = positiveButtonName;
return this;
}

public String getNegativeButtonName() {
return negativeButtonName;
}

public Builder setNegativeButtonName(String negativeButtonName) {
this.negativeButtonName = negativeButtonName;
return this;
}

public PermissionRequester create() {
this.requester.setBuilder(this);
return this.requester;
}

}

public interface OnClickDenyButtonListener {

public void onClick(Activity activity);

}

}



Jsoup Dependency 추가하기

Jsoup을 사용하기 위해 Gradle Scripts 에서 build.gradle 에 Jsoup Dependency 를 추가한다.

compile 'org.jsoup:jsoup:1.9.2'



MainActivity에 TextView, ImageView 선언하기

private TextView tvLatestLotto;
private ImageView ivNumber1;
private ImageView ivNumber2;
private ImageView ivNumber3;
private ImageView ivNumber4;
private ImageView ivNumber5;
private ImageView ivNumber6;
private ImageView ivNumber7;

private TextView tvWinGameCount;
private TextView tvWinGameMoney;


또한 위에서 생성한 PermissionRequester 클래스를 이용하여 인터넷 권한을 요청하는 코드를 작성한다.

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

PermissionRequester.Builder request = new PermissionRequester.Builder(this);
request.create().request(Manifest.permission.INTERNET, 10000, new PermissionRequester.OnClickDenyButtonListener() {
@Override
public void onClick(Activity activity) {
Toast.makeText(activity, "인터넷 권한이 필요합니다.", Toast.LENGTH_SHORT).show();
activity.finish();
}
});

tvLatestLotto = (TextView) findViewById(R.id.tvLatestLotto);
tvWinGameCount = (TextView) findViewById(R.id.tvWinGameCount);
tvWinGameMoney = (TextView) findViewById(R.id.tvWinGameMoney);

ivNumber1 = (ImageView) findViewById(R.id.ivNumber1);
ivNumber2 = (ImageView) findViewById(R.id.ivNumber2);
ivNumber3 = (ImageView) findViewById(R.id.ivNumber3);
ivNumber4 = (ImageView) findViewById(R.id.ivNumber4);
ivNumber5 = (ImageView) findViewById(R.id.ivNumber5);
ivNumber6 = (ImageView) findViewById(R.id.ivNumber6);
ivNumber7 = (ImageView) findViewById(R.id.ivNumber7);
}



AsyncTask를 이용하여 웹으로 접근


먼저 로또 번호를 가져오는 AsyncTask

private class GetLottoNumberTask extends AsyncTask<Void, Void, Map<String,String>> {


@Override
protected Map<String, String> doInBackground(Void... params) {
Map<String,String> result = new HashMap<String,String>();
try {
Document document = Jsoup.connect("http://nlotto.co.kr/common.do?method=main").get();
Elements elements = document.select(".lotto_area #lottoDrwNo");
result.put("latestLottoCount", elements.text());

for( int i = 1; i < 7; i++ ) {
elements = document.select(".lotto_area #numView #drwtNo" + i );
result.put("number" + i, elements.attr("src"));
}

elements = document.select(".lotto_area #numView #bnusNo");
result.put("number7", elements.attr("src"));

elements = document.select(".lotto_area .winner_num #lottoNo1Su");
result.put("winGameCount", elements.text());

elements = document.select(".lotto_area .winner_money #lottoNo1SuAmount");
result.put("winGameMoney", elements.text());

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

@Override
protected void onPostExecute(Map<String, String> map) {

tvLatestLotto.setText(map.get("latestLottoCount") + " 회 당첨번호");
tvWinGameCount.setText(" " + map.get("winGameCount") + " 게임 당첨");
tvWinGameMoney.setText("1 : " + map.get("winGameMoney") + " ");

for( int i = 1; i < 8; i++) {
GetImageTask task1 = new GetImageTask();
task1.execute(map.get("number" + i), "number" + i);
}
}
}


로또번호 이미지를 가져오는 AsyncTask

private class GetImageTask extends AsyncTask<String, Void, Bitmap> {

private String numberType;

@Override
protected Bitmap doInBackground(String... params) {

numberType = params[1];

Bitmap bitmap = null;

try {
URL url = new URL("http://www.nlotto.co.kr" + params[0]);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);

conn.connect();

bitmap = BitmapFactory.decodeStream(conn.getInputStream());

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}

@Override
protected void onPostExecute(Bitmap bitmap) {

if ( numberType.equals("number1")) {
ivNumber1.setImageBitmap(bitmap);
}
else if (numberType.equals("number2")){
ivNumber2.setImageBitmap(bitmap);
}
else if (numberType.equals("number3")){
ivNumber3.setImageBitmap(bitmap);
}
else if (numberType.equals("number4")){
ivNumber4.setImageBitmap(bitmap);
}
else if (numberType.equals("number5")){
ivNumber5.setImageBitmap(bitmap);
}
else if (numberType.equals("number6")){
ivNumber6.setImageBitmap(bitmap);
}
else if (numberType.equals("number7")){
ivNumber7.setImageBitmap(bitmap);
}

}
}



생성한 AsycnTask를 onResume에서 실행하기

@Override
protected void onResume() {
super.onResume();

GetLottoNumberTask task = new GetLottoNumberTask();
task.execute();
}



MainAcitivty.java 전체 코드

package com.ktds.jmj.mybeaconapplication;

import android.Manifest;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

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

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class CouponActivity extends AppCompatActivity {

private TextView tvLatestLotto;
private ImageView ivNumber1;
private ImageView ivNumber2;
private ImageView ivNumber3;
private ImageView ivNumber4;
private ImageView ivNumber5;
private ImageView ivNumber6;
private ImageView ivNumber7;

private TextView tvWinGameCount;
private TextView tvWinGameMoney;

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

PermissionRequester.Builder request = new PermissionRequester.Builder(this);
request.create().request(Manifest.permission.INTERNET, 10000, new PermissionRequester.OnClickDenyButtonListener() {
@Override
public void onClick(Activity activity) {
Toast.makeText(activity, "인터넷 권한이 필요합니다.", Toast.LENGTH_SHORT).show();
activity.finish();
}
});

tvLatestLotto = (TextView) findViewById(R.id.tvLatestLotto);
tvWinGameCount = (TextView) findViewById(R.id.tvWinGameCount);
tvWinGameMoney = (TextView) findViewById(R.id.tvWinGameMoney);

ivNumber1 = (ImageView) findViewById(R.id.ivNumber1);
ivNumber2 = (ImageView) findViewById(R.id.ivNumber2);
ivNumber3 = (ImageView) findViewById(R.id.ivNumber3);
ivNumber4 = (ImageView) findViewById(R.id.ivNumber4);
ivNumber5 = (ImageView) findViewById(R.id.ivNumber5);
ivNumber6 = (ImageView) findViewById(R.id.ivNumber6);
ivNumber7 = (ImageView) findViewById(R.id.ivNumber7);
}

@Override
protected void onResume() {
super.onResume();

GetLottoNumberTask task = new GetLottoNumberTask();
task.execute();
}

private class GetLottoNumberTask extends AsyncTask<Void, Void, Map<String,String>> {


@Override
protected Map<String, String> doInBackground(Void... params) {
Map<String,String> result = new HashMap<String,String>();
try {
Document document = Jsoup.connect("http://nlotto.co.kr/common.do?method=main").get();
Elements elements = document.select(".lotto_area #lottoDrwNo");
result.put("latestLottoCount", elements.text());

for( int i = 1; i < 7; i++ ) {
elements = document.select(".lotto_area #numView #drwtNo" + i );
result.put("number" + i, elements.attr("src"));
}

elements = document.select(".lotto_area #numView #bnusNo");
result.put("number7", elements.attr("src"));

elements = document.select(".lotto_area .winner_num #lottoNo1Su");
result.put("winGameCount", elements.text());

elements = document.select(".lotto_area .winner_money #lottoNo1SuAmount");
result.put("winGameMoney", elements.text());

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

@Override
protected void onPostExecute(Map<String, String> map) {

tvLatestLotto.setText(map.get("latestLottoCount") + " 회 당첨번호");
tvWinGameCount.setText(" " + map.get("winGameCount") + " 게임 당첨");
tvWinGameMoney.setText("1 : " + map.get("winGameMoney") + " ");

for( int i = 1; i < 8; i++) {
GetImageTask task1 = new GetImageTask();
task1.execute(map.get("number" + i), "number" + i);
}
}
}

private class GetImageTask extends AsyncTask<String, Void, Bitmap> {

private String numberType;

@Override
protected Bitmap doInBackground(String... params) {

numberType = params[1];

Bitmap bitmap = null;

try {
URL url = new URL("http://www.nlotto.co.kr" + params[0]);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);

conn.connect();

bitmap = BitmapFactory.decodeStream(conn.getInputStream());

} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}

@Override
protected void onPostExecute(Bitmap bitmap) {

if ( numberType.equals("number1")) {
ivNumber1.setImageBitmap(bitmap);
}
else if (numberType.equals("number2")){
ivNumber2.setImageBitmap(bitmap);
}
else if (numberType.equals("number3")){
ivNumber3.setImageBitmap(bitmap);
}
else if (numberType.equals("number4")){
ivNumber4.setImageBitmap(bitmap);
}
else if (numberType.equals("number5")){
ivNumber5.setImageBitmap(bitmap);
}
else if (numberType.equals("number6")){
ivNumber6.setImageBitmap(bitmap);
}
else if (numberType.equals("number7")){
ivNumber7.setImageBitmap(bitmap);
}

}
}
}


결과화면




댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함