프로그래밍/Android

안드로이드 URL에서 메타데이터 얻기 (Android get metadata from url)

Lou Park 2019. 4. 6. 22:20

오늘 할 것은 유저가 URL을 입력했을때 사이트 메타데이터를 얻어와서 표시하는 작업이다.

아래처럼 유튜브 URL을 입력하면 저렇게 간단한 사진과, 내용이 보인다.

시작하기 전에...

Jsoup 라이브러리를 이용할것이니 build.gradle에
implementation 'org.jsoup:jsoup:1.11.1' 한 줄을 추가!

1. Validator.java : URL 검사 클래스 만들기

URL 파싱에 앞서서 URL이 진짜 맞는 URL인지 검사하는 클래스인 Validator를 만든다.
Validator.isUrl()를 하면 URL이 맞는지 간단히 검사할 수 있다.

public class Validator {
    public static boolean isUrl(String text) {
        Pattern p = Pattern.compile("^(?:https?:\\/\\/)?(?:www\\.)?[a-zA-Z0-9./]+$");
        Matcher m = p.matcher(text);
        if  (m.matches()) return true;
        URL u = null;
        try {
            u = new URL(text);
        } catch (MalformedURLException e) {
            return false;
        }
        try {
            u.toURI();
        } catch (URISyntaxException e) {
            return false;
        }
        return true;
    }
}

2. Util.java : 텍스트에서 대표 URL을 추출하는 메소드와, URL에서 메타데이터를 추출하는 메소드를 가진 클래스

- 첫번째 extractUrlFromText에서는 일반 텍스트에서 대표 URL 하나 추출해낸다.
"안녕하세요 여기는https://naver.com에서 긁어왔어요 [https://google.com](https://google.com)ㅋㅋ"라는 문자가 있다면 첫번째로 등장하는 유효한 URL인 https://naver.com만을 반환한다.

- 두번째 getMetadataFromUrl에서는 웹에서 meta-data를 가져올 수 있도록 한다.

자세히보면 meta[property=og:title]이라는 부분이있는데, 자신이가져올 항목을 정확히 알려면, 웹브라우저의 개발자도구로 가서 <head> 태그를 자세히 살펴보면 된다. 네이버의 경우 아래와 같다. Metadata는 내가 임의로 생성한 간단한 객체다.

내가 긁어온건 og: 부분!

public class Util {
    // URL에서 메타데이터를 추출하는 메소드
    public static Metadata getMetadataFromUrl(String url) {
        try {
            Metadata metadata = new Metadata();
            metadata.url = url;
            Document doc = Jsoup.connect(url).get();
            metadata.title = doc.select("meta[property=og:title]").first().attr("content");
            metadata.description = doc.select("meta[property=og:description]").get(0).attr("content");
            metadata.imageUrl = doc.select("meta[property=og:image]").get(0).attr("content");
            return metadata;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 텍스트에서 대표 URL을 추출하는 메소드
    public static String extractUrlFromText(String text) {
        String urlRegex = "((https?|ftp|gopher|telnet|file):((//)|(\\\\))+[\\w\\d:#@%/;$()~_?\\+-=\\\\\\.&]*)";
        Pattern pattern = Pattern.compile(urlRegex, Pattern.CASE_INSENSITIVE);
        Matcher urlMatcher = pattern.matcher(text);

        ArrayList<String> urls =  new ArrayList<>();
        while (urlMatcher.find()) {
            urls.add(text.substring(urlMatcher.start(0), urlMatcher.end(0)));
        }

        String resultUrl = null;
        for (String url : urls) {
            if (Validator.isUrl(url)) {
                resultUrl = url;
                break;
            }
        }
        return resultUrl;
    }
}

3. EditText 글자가 바뀔때마다 체크하고 URL이 있다면 저장 해두고, 메타데이터 정보를 가져와서 보여준다!

public class WritePungActivity extends AppCompatActivity {
    private String url; // metadata를 가져올 url
    private EditText etComment;

    protected void onCreate(...) {
        TextWatcher textWatcher = new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // 텍스트 변경시 URL이 있는지 체크
                checkUrl();
            }

            @Override
            public void afterTextChanged(Editable s) {

            }
        };
        etComment.addTextChangedListener(textWatcher);
    }

    private void checkUrl() {
        String content = etComment.getText().toString();
        url = Util.extractUrlFromText(content);
        if (url != null) {
            Metadata metadata = Util.getMetadataFromUrl(url);
            // TODO: 메타데이터를 가져왔으니 여기에 메타데이터를 보여주는 뷰 보이게!
        }
    }
}
  • NetworkOnMainThreadException 에러를 피하기 위해서는?

    public class MetadataTask extends AsyncTask<String, Metadata, Metadata> {
         private final PostAdapter.ViewHolder holder;
    
         public MetadataTask(PostAdapter.ViewHolder holder) {
             this.holder = holder;
         }
         @Override
         protected Metadata doInBackground(String... params) {
             return Util.getMetadataFromUrl(params[0]);
         }
    
         @Override
         protected void onPostExecute(Metadata metadata) {
             super.onPostExecute(metadata);
             // TODO ... 가져온 메타데이터로 뭘 할지 적어주면됨
             Glide.with(context).load(metadata.imageUrl).into(holder.ivMetadataImage);
             holder.tvMetadataTitle.setText(metadata.shorten(metadata.title));
             holder.tvMetadataUrl.setText(metadata.shorten(metadata.url));
             holder.rlMetadata.setVisibility(View.VISIBLE);
         }
     }