- javascript 바코드스캔
- 타임피커
- ASP.Net Core 404
- 강제이동
- 하드 마이그레이션
- XSS방어
- 바코드 생성하기
- 맥 오라클설치
- asp.net Select
- jquery 바코드
- 404에러페이지
- django 엑셀불러오기
- javascript redirection
- ViewBag
- XSS PHP
- jquery 바코드생성
- ViewData
- asp.net dropdownlist
- 바코드 스캔하기
- SSD 복사
- php 캐쉬제거
- javascript 바코드 생성
- asp.net core Select
- Mac Oracle
- 말줄임표시
- 파일업로드 체크
- TempData
- javascript 유효성체크
- 하드 윈도우 복사
- 파일업로드 유효성체크
웹개발자의 기지개
사이트 내용 추출 실습 2 - 크롤링하기 (로또 당첨번호, 네이버/다음 실시간 검색어 조회) , RecylerView 활용 본문
사이트 내용 추출 실습 2 - 크롤링하기 (로또 당첨번호, 네이버/다음 실시간 검색어 조회) , RecylerView 활용
http://portfolio.wonpaper.net 2019. 7. 28. 23:49앞전의 포스팅중에 [ 사이트 내용 추출 실습 1 - 크롤링하기 ] https://wonpaper.tistory.com/111
그 다음 버전이다.
일단 실행 화면부터 살펴보자.
위에서 네이버랑 다음은 거의 소스상 프로그램 패턴은 동일하다.
일단 jsoup 이라는 웹사이트의 태그를 추출해오는 라이브러리 함수부터 추가하도록 하자
자세한 방법은 [ jar 라이브러리 추가하기 ] https://wonpaper.tistory.com/109
그다음 전체적인 소스 관련해서 대략 나타내면 다음과 같다.
앞전 포스팅에서 [ 사이트 내용 추출 실습 1 - 크롤링하기 ] https://wonpaper.tistory.com/111
앞전 포스팅을 그대로 이용하는 소스들과 함께 어우러 진다.
등장하는 관련 소스들 정리
(기존 소스)
activity_main.xml - 초기화면 썰렁한(?) 버튼3개만 있는 화면페이지
LottoNum.java - 로또당첨 번호 조회
NaverSearch.java - 네이버 실시간 검색어 기본 클래스
NaverSearchManager.java - 네이버 실시간 검색어 얻어오는 매니저 클래스
DaumSearch.java - 다음 실시간 검색어 기본 클래스
DaumSearchManager.java - - 다음 실시간 검색어 얻어오는 매니저 클래스
(추가된 소스)
NaverActivity.java - 네이버 실시간 검색어 WebView 화면 activity
activicy_naver.xml - 네이버 실시간 검색어 WebView 화면 xml
NaverRecyclerAdapter.java - 네이버쪽 RecyclerView 이용을 위한 Adapter 소스
NaverRecyclerViewActivity.java - 네이버쪽 RecyclerView 목록 화면을 위한 activicy
activity_naver_recycler_view.xml - 네이버쪽 RecyclerView 목록 화면을 위한 xml
item.xml - RecycleView에 한줄한줄 각 item에 대한 디자인 xml
DaumActivity.java - 다음 실시간 검색어 WebView 화면 activity
activicy_daum.xml - 다음 실시간 검색어 WebView 화면 xml
DaumRecyclerAdapter.java - 다음쪽 RecyclerView 이용을 위한 Adapter 소스
DaumRecyclerViewActivity.java - 다음쪽 RecyclerView 목록 화면을 위한 activicy
activity_daum_recycler_view.xml - 다음쪽 RecyclerView 목록 화면을 위한 xml
[ MainActivity.java ]
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
|
package com.chat.wonpa.mujimakjicrawling;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import java.util.ArrayList;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
Button button1, button2, button3;
ArrayList<String> arrayList;
ArrayList<NaverSearch> arrayList2;
ArrayList<DaumSearch> arrayList3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("크롤링 실습하기");
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
button3 = (Button) findViewById(R.id.button3);
final Bundle bun = new Bundle();
// 최신 로또 번호 확인
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Thread 로 웹서버에 접속
new Thread() {
@Override
public void run() {
//super.run();
bun.clear();
LottoNum lotto = new LottoNum();
arrayList = lotto.getNumber();
bun.putStringArrayList("lottoNum",arrayList);
Message msg = handler.obtainMessage();
msg.setData(bun);
handler.sendMessage(msg);
}
}.start();
}
});
// 네이버 실시간 검색어 조회
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
//super.run();
bun.clear();
NaverSearchManager naverSearchManager = new NaverSearchManager();
arrayList2 = naverSearchManager.naverSearchProcess();
bun.putSerializable("naverSearch",arrayList2);
Message msg = handler.obtainMessage();
msg.setData(bun);
handler.sendMessage(msg);
}
}.start();
}
});
// 다음 실시간 검색어 조회
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
//super.run();
bun.clear();
DaumSearchManager daumSearchManager = new DaumSearchManager();
arrayList3 = daumSearchManager.DaumSearchProcess();
bun.putSerializable("daumSearch",arrayList3);
Message msg = handler.obtainMessage();
msg.setData(bun);
handler.sendMessage(msg);
}
}.start();
}
});
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//super.handleMessage(msg);
Bundle bun = msg.getData();
//Set<String> keys = bun.keySet();
//Log.d("Handler",keys.size() + "개");
String str = "";
for (String key : bun.keySet()) {
switch (key) {
case "lottoNum" :
str = "";
ArrayList<String> arrayList = bun.getStringArrayList(key);
AlertDialog.Builder dlg = new AlertDialog.Builder(MainActivity.this);
dlg.setTitle("제" + arrayList.get(0) + "회 로또당첨번호");
dlg.setIcon(R.mipmap.ic_launcher);
for (int i=1;i<6;i++) {
str += i + "번 : "+ arrayList.get(i) +" \n";
}
str += "\n보너스번호 : " + arrayList.get(7);
dlg.setMessage(str);
dlg.setPositiveButton("확인", null);
dlg.show();
break;
case "naverSearch" :
ArrayList<NaverSearch> array1 = (ArrayList<NaverSearch>) bun.getSerializable(key);
Intent intent = new Intent(getApplicationContext(),NaverRecyclerViewActivity.class);
intent.putExtra("NaverSearch",array1);
startActivity(intent);
break;
case "daumSearch" :
ArrayList<DaumSearch> array2 = (ArrayList<DaumSearch>) bun.getSerializable(key);
Intent intent2 = new Intent(getApplicationContext(),DaumRecyclerViewActivity.class);
intent2.putExtra("DaumSearch",array2);
startActivity(intent2);
break;
}
}
}
};
}
|
cs |
이전 포스팅의 MainActivity.java와 흐름은 같이 간다.
다만 139 라인과 148라인의 네이버 / 다음코너의 내용이 달라진 부분이다.
3가지 버튼 (로또, 네이버, 다음) 마다 클릭 이벤트로 인해 각각의 쓰레드 방식으로 개별 처리되는데, 이 쓰레드는 handler 라는 놈을 가지고 실제 작업이 이루어지는데, 이 handler 놈으로 처리할때 넘어온 메세지를 Bundle 객체형태로 그 데이터를 받아서 Intent 처리하도록 구성하였다. 그리고, 이 Intent 를 가지고 각각 NaverRecyclerViewActivity.java 를 띠우는 방식으로 진행이 된다.
라인 111 에서 각 쓰레드를 처리할때 받아온 메세지 값을
Bundle bun = msg.getData(); 메세지내용을 받으면 Bundle 객체가 리턴된다.
라인 141 에서
ArrayList<NaverSearch> array1 = (ArrayList<NaverSearch>) bun.getSerializable(key); 처럼
NaverSearch 객체들이 모인 ArrayList를 get해서 받아온다.
다만 주의할점은
라인73 bun.putSerializable("naverSearch",arrayList3); 처럼 put 으로 naverSearch객체를 넘기고,
라인141 ArrayList<NaverSearch> array1 = (ArrayList<NaverSearch>) bun.getSerializable(key); 처럼 get 으로 그 객체를 받기 위해서는
NaverSearch 기본클래스를 Serializable 로 상속해 주어야한다는 점을 잊지 말자.
DaumSearch 또한 마찬가지로 하면 된다.
그다음 내용은 RecyclerView 와 이 Adapter, 그리고, 각 List 항목을 클릭했을때, WebView를 만들어 여기에 실제 그 검색어의 웹사이트를 띠우는 작업을 해보자.
일단 [ item.xml ] 이라고 RecyclerView의 item 디자인 구성화면은 다음과 같이 심플하게 얼른 만들었다.
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
|
<?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="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
|
cs |
[ NaverRecyclerViewActivity.java ]
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
|
import java.util.ArrayList;
public class NaverRecyclerViewActivity extends AppCompatActivity {
private NaverRecyclerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_naver_recycler_view);
setTitle("네이버 실시간 검색어 순위 조회");
RecyclerView recyclerView1 = (RecyclerView) findViewById(R.id.naver_recyclerView1);
// recyclerView1의 layoutManger 형식을 지정한다. Grid형식도 설정가능하다.
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView1.setLayoutManager(linearLayoutManager);
adapter = new NaverRecyclerAdapter();
recyclerView1.setAdapter(adapter);
getData();
}
public void getData() {
Intent intent = getIntent();
ArrayList<NaverSearch> array1 = (ArrayList<NaverSearch>) intent.getSerializableExtra("NaverSearch");
for (int i=0;i<array1.size();i++) {
// adapter에 방금 만든 Data 객체를 추가해 넣는다.
adapter.addItem(array1.get(i));
}
// adapter 내용의 값이 변경되었음을 알려준다. 이 함수를 쓰지않으면 data가 노출안된다.
adapter.notifyDataSetChanged();
}
}
|
cs |
RecyclerView 는 Adaper 에서 관련 item들을 담고 이를 setAapter 하여 작동시킨다.
[ activity_naver_recycler_view.xml ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".NaverRecyclerViewActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/naver_recyclerView1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
|
cs |
[ NaverRecyclerAdapter.java ]
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
public class NaverRecyclerAdapter extends RecyclerView.Adapter<NaverRecyclerAdapter.ItemViewHolder> {
ArrayList<NaverSearch> arrayList = new ArrayList<NaverSearch>();
int num = 1;
@NonNull
@Override
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// item.xml 을 parent ViewGroup 위에 Inflate 시켜 새로운 ViewHolder를 하나 만든다.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
return new ItemViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ItemViewHolder itemViewHolder, int position) {
itemViewHolder.onBind(arrayList.get(position));
}
@Override
public int getItemCount() {
return arrayList.size();
}
public void addItem(NaverSearch naverSearch) {
arrayList.add(naverSearch);
}
class ItemViewHolder extends RecyclerView.ViewHolder {
private TextView textView1;
private TextView textView2;
public ItemViewHolder(@NonNull final View itemView) {
super(itemView);
textView1 = (TextView) itemView.findViewById(R.id.textView1);
textView2 = (TextView) itemView.findViewById(R.id.textView2);
// 해당 각각의 item 클릭시 Naver WebView를 이용하여 각 아이템의 url로 새창띠운다.
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(itemView.getContext(),NaverActivity.class);
intent.putExtra("NaverSearchName",textView1.getText().toString());
intent.putExtra("NaverSearchUrl",textView2.getText().toString());
// 해당 View v 에서 getContext() 를 읽어와서 startActivity 띄운다.
v.getContext().startActivity(intent);
}
});
}
void onBind(NaverSearch naver) {
textView1.setText(num + "위 : " + naver.getName());
textView2.setText(naver.getUrl());
num++;
}
}
}
|
cs |
RecyclerAdapter 는 또 다시 ViewHolder 놈으로 각각의 아이템내용들인 item.xml 의 세부 view들을 1:1 바인딩하는 처리를 한다. 세부내용들을 쏙쏙 데이터를 넣어주고 채워줘서 개별 View 들을 담은 그릇이라 보면 되겠다.
여기 까지 구성하면 Naver 나 Daum 의 경우 RecyclerView 형태로 리스트 결과화면으로 뽑을수 있는데, 이 각 한줄 아이템을 클릭했을때, 처리되는 라인이 위 소스상의 49번 줄부분이다.
그리고, 검색어와 관련된 url 값 대로 WebView를 띄워 해당 검색어와 관련된 웹사이트로 새로운 창을 띄우는 작업을 해보도록 하자.
[ NaverActivity.java ]
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class NaverActivity extends AppCompatActivity {
WebView webView1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_naver);
Intent intent = getIntent();
String name = intent.getStringExtra("NaverSearchName");
String url = intent.getStringExtra("NaverSearchUrl");
setTitle("네이버 실시간 검색어 " + name);
webView1 = (WebView) findViewById(R.id.webView1);
webView1.getSettings().setJavaScriptEnabled(true);
webView1.setWebChromeClient(new WebChromeClient());
webView1.loadUrl(url);
// 새창 관련 관리클래스
webView1.setWebViewClient(new WebViewClientClass());
}
// 웹뷰에서 뒤로가기 버튼을 누르기
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView1.canGoBack()) {
webView1.goBack();
finish();
return true;
}
return super.onKeyDown(keyCode, event);
}
private class WebViewClientClass extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Log.d("Naver check url : ", request.getUrl().toString());
Uri uri = request.getUrl();
if (uri.toString() != null) {
return false; // 현재 창에서 브라우저로 바로 본다.
} else {
// 새창으로 띄우는데, 암시적 인텐트로 여러개의 브라우저가 설치되어있을 경우
// 이중에서 선택가능하다.
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri.toString()));
startActivity(intent);
return true; // 새로운 창으로 띄운다.
}
// return super.shouldOverrideUrlLoading(view, request);
}
}
}
|
cs |
[ activity_naver.xml ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".NaverActivity">
<WebView
android:id="@+id/webView1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
|
cs |
자아~ 그리고 Daum 실시간 검색어 관련 소스들도 Naver 쪽의 소스와 쌍동이처럼 일치한다.
이름만 Daum 으로 시작해서 동일하게 RecyclerView 와 Adapter 등을 만들어 주면된다.
'안드로이드' 카테고리의 다른 글
API 'variant.getMergeResources()' is obsolete and has been replaced with 'variant.getMergeResourcesProvider()' (0) | 2019.08.10 |
---|---|
Manifest merger failed 병합 에러 (0) | 2019.08.08 |
Log 의 유형 정리 (0) | 2019.07.24 |
RecyclerView 기본 예제2 - onclick 이벤트 (0) | 2019.07.12 |
RecyclerView 기본 예제1 (0) | 2019.07.10 |