Jsoup이란?
자바로 만들어진 HTML 파서. 즉, URL, 파일, 문자열을 소스로 하여 HTML을 파싱 할 수 있는 자바 라이브러리이다.
jar 파일을 다운로드 받아 라이브러리에 직접 추가해도 되고, 아래와 같이 gradle에 추가해도 된다.
implementation 'org.jsoup:jsoup:1.11.3'
인터넷을 통해 데이터를 가져올 것이기 때문에 Manifest 부분에 아래 퍼미션을 추가한다.
<uses-permission android:name="android.permission.INTERNET"/>
1. XML 정의
jsoup을 알게되었을 때 이론보다는 실습을 통해 먼저 공부했다. 이후 여러 블로그들을 다니면서 jsoup의 개념을 알게 되었지만 실습을 통해 알게 된 부분이 더 많았으므로 실습을 바로 해보겠다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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/number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
|
cs |
- activity_main.xml에 크롤링한 숫자를 띄어줄 TextView를 간단하게 만들어준다.
2. 크롤링할 웹페이지 선정
그 다음 크롤링할 동행 복권 사이트를 들어가서 우리가 원하는 당첨번호가 Elements의 어느 부분에 있는지 확인해준다. 우리가 원하는 당첨번호들은 span태그에 id가 drwtNo1 ~ drwtNo6에 적혀있었고, 보너스 번호는 bnusNo으로 id를 가지고 있었다. 우리는 이 부분을 가져올 것이다.
3. MainActivity - 1
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
|
String nums; //복권 번호을 저장할 변수
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.number);
Document doc = null;
try {
doc = Jsoup.connect("https://dhlottery.co.kr/common.do?method=main").get();
Elements contents = doc.select("#lottoDrwNo"); //회차 id값 가져오기
nums += contents.text() +"회 :";
for(int i = 1; i < 7; i++){
contents = doc.select("#drwtNO"+i); //복권 번호 6개 가져오기
nums += " "+contents.text();
}
nums += doc.select("#bnusNo").text(); //보너스 번호 contents 변수를 사용하지 않고 가져오는 방법
} catch (IOException e) {
e.printStackTrace();
}
textView.setText(nums);
}
|
cs |
위와 같이 Jsoup을 이용해 동행 복권 사이트에 연결하여 우리가 원하는 값들을 가져올 수 있다.
하지만 이렇게만 하고 코드를 끝내면 아래와 같은 엄청난 에러가 뜬다.
이유는 프로그램 단에서는 네트워크에서 데이터를 받아오려면 별도의 Thread가 필요하기 때문이다. 만약 메인 Thread에서 네트워크를 통해 데이터를 받아오는 과정에서 오류가 발생한다면 앱 전체 실행에 영향을 줄 수 있고, 추가로 많은 양의 데이터를 받아오는 과정에서 하나의 Thread로만 프로그램이 실행된다면 긴 시간을 데이터를 받아오는 데 사용하기 때문이다. 이를 방지하기 위함인 것으로 보인다.
4. Thread를 적용한 MainActivity
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
new Thread(){
@Override
public void run() {
Document doc = null;
try {
doc = Jsoup.connect("https://dhlottery.co.kr/common.do?method=main").get();
Elements contents = doc.select("#lottoDrwNo"); //회차 id값 가져오기
nums += contents.text() +"회 :";
for(int i = 1; i < 7; i++){
contents = doc.select("#drwtNo"+i); //복권 번호 6개 가져오기
nums += " "+contents.text();
}
nums += doc.select("#bnusNo").text(); //보너스 번호 contents 변수를 사용하지 않고 가져오는 방법
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
|
cs |
크롤링을 하는 부분을 이렇게 Thread()로 묶어주면 메인 쓰레드가 아닌 또 다른 쓰레드에서 크롤링을 담당하게 된다.
하지만 이렇게 해도 우리는 직접적으로 View에 UI를 건드리지 못한다.
무슨말이냐면 View에 데이터를 뿌려주는 역할은 메인 쓰레드에서 담당한다. 만약 Thread() 안에서 textView.setText()를 사용하면 오류가 뜰 것이다. 이는 Handler(핸들러)를 통해 Thread() 내부에서 메인 쓰레드로 데이터를 보내주어야 한다.
5. Handler 기능을 추가한 MainActivity (전체 코드)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public class MainActivity extends AppCompatActivity {
String nums; //복권 번호을 저장할 변수
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.number);
final Bundle bundle = new Bundle();
new Thread(){
@Override
public void run() {
Document doc = null;
try {
doc = Jsoup.connect("https://dhlottery.co.kr/common.do?method=main").get();
Elements contents = doc.select("#lottoDrwNo"); //회차 id값 가져오기
nums += contents.text() +"회 :";
for(int i = 1; i < 7; i++){
contents = doc.select("#drwtNo"+i); //복권 번호 6개 가져오기
nums += " "+contents.text();
}
nums += doc.select("#bnusNo").text(); //보너스 번호 contents 변수를 사용하지 않고 가져오는 방법
bundle.putString("numbers", nums); //핸들러를 이용해서 Thread()에서 가져온 데이터를 메인 쓰레드에 보내준다.
Message msg = handler.obtainMessage();
msg.setData(bundle);
handler.sendMessage(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
textView.setText(bundle.getString("numbers")); //이런식으로 View를 메인 쓰레드에서 뿌려줘야한다.
}
};
}
|
cs |
6. 결과화면
여기까지 Jsoup을 이용해 동행 복권 사이트에서 이번 주 당첨번호를 가져오는 실습을 해보았다.
Jsoup은 안드로이드 프로젝트를 시작하면서 웹에서 데이터를 가져와야 하는 상황이 생겨 알게 되었다.
Jsoup을 이용한 웹 크롤링을 알아보면서 다양한 지식들을 얻을 수 있었다. 동적 웹페이지를 크롤링하는 Selenium, WebView를 통한 웹 크롤링, 파이썬으로 웹 크롤링하는 방법, 유저 에이전트, REST API 사용 방법, 크롬 개발자 도구로 Request, Response 활용하기 등 다양한 지식들을 알게 되었다.
시간이 된다면 다음에는 파이썬으로 웹 크롤링하는 예제도 한번 올려보겠다.
'Mobile > 안드로이드' 카테고리의 다른 글
[안드로이드/android] 파파고 API 안드로이드에서 사용하기(papago api) (0) | 2020.07.21 |
---|---|
[안드로이드/android] 리사이클러뷰(RecyclerView)로 메모장 만들기 (0) | 2020.07.09 |
[안드로이드/android] 레이아웃과 속성 (0) | 2020.06.18 |
[안드로이드/android] 시작하기 (1) | 2020.06.16 |