728x90
반응형

 

현재 진행중인 프로젝트에서 웹페이지 url을 입력받아 Open Graph 정보를 표시하는 작업을 하려고 합니다.

 

카카오톡이나 소셜 sns를 사용할 때 url만 입력해도 이미지와 제목이 뜨는걸 보셨을꺼에요.

 

일반적으로 웹 페이지를 만들때 약속된 meta tag라고 할 수 있는데요, 이런걸 Open Graph 프로토콜이라고 합니다. 

 

https://ogp.me/

 

Open Graph protocol

The Open Graph protocol enables any web page to become a rich object in a social graph.

ogp.me

 

 

 

# og meta tag 확인

쿠팡을 기준으로 작업을 해보겠습니다.

 

쿠팡 사이트에 들어가서 맥북을 검색해 본 뒤 크롬 기준으로 [도구 더보기 -> 개발자 도구] 항목을 클릭합니다.

 

 

 

펼쳐진 개발자 도구에서 'Elements' 탭을 선택하면 HTML요소들어 보여집니다.

 

head tag부분에서 아래와같이 link, meta, script 태그들이 보이네요.

 

 

 

저는 여기서 og: 라고 시작되는 태그들만을 원합니다.

 

보통 다른 쇼핑몰 같은 경우에도 image, title, url, description 항목은 필수적으로 사용하고 있는데요.

 

이 정보들이 소셜 sns나 채팅에 공유될때 나오는 정보들입니다.

 

image - 상품의 이미지

title - 상품 제목

url - 해당 상품 url

description - 간략한 설명

 

 

 

 

# 개발 준비

 

Flutter 프레임워크에서는 특정 패키지가 필요합니다.

 

http 패키지로 사이트의 html문자열을 가져온 다음, html 패키지로 문자열을 html로 파싱파여 원하는 정보를 가져올겁니다.

https://pub.dev/packages/http

 

http | Dart Package

A composable, multi-platform, Future-based API for HTTP requests.

pub.dev

https://pub.dev/packages/html/install

 

html | Dart Package

APIs for parsing and manipulating HTML content outside the browser.

pub.dev

 

 

 

 

# 페이지 정보 읽기

아래처럼 패키지를 import 해줍니다.

import 'package:http/http.dart' as http;
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parse;

 

 

http.get 함수로 웹페이지 주소를 넣어 호출합니다.

 

아래처럼만 작성해도 일반적인 사이트에서는 문제 없이 html 문자열을 응답받습니다.

final String uri = "웹 페이지 주소";
final response = await http.get(Uri.parse(uri));

 

 

 

하지만 쿠팡같은 경우에는 pending이 걸려버리고 response가 오지 않는것을 알 수 있습니다.

 

각종 블로그에서도 해당 문제에 대해서 다루지만 user-agent를 넣는 방법으로는 동작하지 않습니다.

 

 

 

 

해결을 위해 쿠팡 사이트에 들어와 다시 [도구 더보기 -> 개발자 도구] 로 진입해서 웹 페이지 요청 항목을 선택한 뒤 [Network -> Headers] 탭으로 들어가보겠습니다.

 

Request Headers 부분에서 아래와 같이 accept 정보를 넣어주어 압축된 정보를 주고받는걸 알 수 있는데요. 

 

 

 

 

저도 이와 같이 header정보를 추가 해주겠습니다.

 

그리고 만약 동작하지 않을 수 있다는 부분을 위해 timeout 시간을 2초로 주었습니다.

 

아래처럼 작성하시면 쿠팡 사이트의 정보까지 문제없이 html문자열을 응답받을 수 있습니다

final response = await http.get(Uri.parse(uri), headers: {
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
}).timeout(const Duration(seconds: 2));

 

 

 

# og tag 추출

이제 html문자열에서 og tag만 추출하면 되겠네요.

 

위에서 import한 alias를 확인해주시고 코드를 봐주시면 됩니다.

 

response.body에서 html 문자열만을 추출해 html로 변환하면 Document라는 객체로 변환됩니다.

 

이 Document 객체에서 어떻게 정보를 꺼내냐면 meta tag 속성을 살펴보면 됩니다.

<meta property="og:title" content="Apple 2020 맥북 에어 13">

 

 

 

 

[head -> meta 에서 property가 'og:title' 인것의 content라는 속성을 꺼내줘] 라고 한다면 html 패키지에서는 아래처럼 코드를 작성하면 됩니다.

 

정말 간단하게 원하는 tag 정보를 가져올 수 있습니다.

dom.Document document = parse.parse(response.body);

String? title = document.head
    ?.querySelector("meta[property='og:title']")
    ?.attributes['content'];
String? description = document.head
    ?.querySelector("meta[property='og:description']")
    ?.attributes['content'];
String? image = document.head
    ?.querySelector("meta[property='og:image']")
    ?.attributes['content'];
String? url = document.head
    ?.querySelector("meta[property='og:url']")
    ?.attributes['content'];

 

 

 

 

전체 코드 입니다.

 

return type은 원하는 model을 생성해서 응답해주면 딱이겠군요!

import 'package:http/http.dart' as http;
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parse;

static void urlToMeta(String uri) async {
    final response = await http.get(Uri.parse(uri), headers: {
      'accept-encoding': 'gzip, deflate, br',
      'accept-language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
    }).timeout(const Duration(seconds: 2));
    dom.Document document = parse.parse(response.body);

    String? title = document.head
        ?.querySelector("meta[property='og:title']")
        ?.attributes['content'];
    String? description = document.head
        ?.querySelector("meta[property='og:description']")
        ?.attributes['content'];
    String? image = document.head
        ?.querySelector("meta[property='og:image']")
        ?.attributes['content'];
    String? url = document.head
        ?.querySelector("meta[property='og:url']")
        ?.attributes['content'];
 }

 

 

 

# 마무리

Flutter 뿐만 아니라 다른 언어에서도 방법만 안다면 문제없어 원하는 정보를 Crawling 할 수 있습니다.

 

728x90
반응형

+ Recent posts