[안드로이드] URL의 메타데이터 크롤링하기

박서현·2021년 6월 3일
1

안드로이드

목록 보기
5/9
post-custom-banner

이번에는 URL 공유 시, 미리보기 정보가 보이는 기능을 만들어 보았다.


원리

URL이 인식되면, 크롤러가 해당 웹사이트의 HTML head 의 메타 데이터를 크롤링하여 미리보기 화면을 생성한다.

프로토콜

대부분 페이스북의 Open Graph 프로토콜을 사용한다.
공식 페이지: The Open Graph protocol

Jsoup을 이용하여 URL 크롤링하기

ArrayList<String> urlList, urlImage, urlTile, urlDescription;
Disposable backgroundTask;

...

// URL 크롤링하는 메소드
private void urlCrawling(String url) {
	// 크롤링한 메타데이터 정보를 담아 반환할 Hashmap
        HashMap<String, String> map = new HashMap<>();

        backgroundTask = Observable.fromCallable(() -> {
            try {
                Connection con = Jsoup.connect(url);
                Document doc = con.get();
                Elements ogTags = doc.select("meta[property^=og:]");
                if (ogTags.size() <= 0) {
                    return map; // 아무것도 안 들은 map 반환
                }
                // 필요한 OGTag
                for (int i = 0; i < ogTags.size(); i++) {
                    Element tag = ogTags.get(i);
                    String text = tag.attr("property");
                    if("og:url".equals(text)) {
                        map.put("url", tag.attr("content"));

                    } else if ("og:title".equals(text)) {
                        map.put("title", tag.attr("content"));

                    } else if ("og:image".equals(text)) {
                        map.put("image", tag.attr("content"));

                    } else if ("og:description".equals(text)) {
                        map.put("description", tag.attr("content"));
                    }
                }
                return map;

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

        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<HashMap<String, String>>() {
            @Override
            public void accept(HashMap<String, String> map) {
                if(map != null && map.get("title") != null) {
                    // 미리보기 화면 생성
                    LayoutInflater layoutInflater = getLayoutInflater();
                    View urlBox = layoutInflater.inflate(R.layout.item_url_crawling, urlLayout, false);

                    // 내용 채우기
                    if(map.get("image") != null) {
                        Glide.with(getApplicationContext()).load(map.get("image")).into((RoundedImageView)urlBox.findViewById(R.id.image));
                        urlImage.add(map.get("image"));
                    }
                    if(map.get("title") != null) {
                        ((TextView)urlBox.findViewById(R.id.txt_title)).setText(map.get("title"));
                        urlTile.add(map.get("title"));
                    }
                    if(map.get("url") != null) {
                        ((TextView)urlBox.findViewById(R.id.txt_url)).setText(map.get("url"));
                        urlList.add(map.get("url"));
                    }
                    if(map.get("description") != null) {
                        ((TextView)urlBox.findViewById(R.id.txt_description)).setText(map.get("description"));
                        urlDescription.add(map.get("description"));
                    }
                    // 삭제 버튼
                    urlBox.findViewById(R.id.btn_deleteUrl).setOnClickListener(
                    	v -> {
                        	urlLayout.removeView(urlBox);
                        	// url 리스트에서도 삭제
                        	urlImage.remove(map.get("image"));
                        	urlTile.remove(map.get("title"));
                        	urlList.remove(map.get("url"));
                        	urlDescription.remove(map.get("description"));
                             }
                    });
                    
                    // 미리보기 화면 붙이기
                    urlLayout.addView(urlBox);

                } else {
                    Toast.makeText(getApplicationContext(), "미리보기 정보를 가져올 수 없습니다.", Toast.LENGTH_SHORT).show();
                }

                backgroundTask.dispose();
            }
      });
}
profile
차곡차곡 쌓아가기
post-custom-banner

0개의 댓글