Skip to content

소셜 공유 이미지 및 Open Graph 태그 추출하기

Bun 의 HTMLRewriter API 는 HTML 콘텐츠에서 소셜 공유 이미지와 Open Graph 메타데이터를 효율적으로 추출하는 데 사용할 수 있습니다. 이는 링크 미리보기 기능 소셜 미디어 카드 또는 웹 스크래퍼를 구축하는 데 특히 유용합니다. HTMLRewriter 를 사용하여 처리하려는 HTML 요소 텍스트 및 속성과 일치하는 CSS 선택자를 사용할 수 있습니다.

ts
interface SocialMetadata {
  title?: string;
  description?: string;
  image?: string;
  url?: string;
  siteName?: string;
  type?: string;
}

async function extractSocialMetadata(url: string): Promise<SocialMetadata> {
  const metadata: SocialMetadata = {};
  const response = await fetch(url);

  const rewriter = new HTMLRewriter()
    // Open Graph meta 태그 추출
    .on('meta[property^="og:"]', {
      element(el) {
        const property = el.getAttribute("property");
        const content = el.getAttribute("content");
        if (property && content) {
          // "og:image" 를 "image" 등으로 변환
          const key = property.replace("og:", "") as keyof SocialMetadata;
          metadata[key] = content;
        }
      },
    })
    // 폴백을 위한 Twitter Card meta 태그 추출
    .on('meta[name^="twitter:"]', {
      element(el) {
        const name = el.getAttribute("name");
        const content = el.getAttribute("content");
        if (name && content) {
          const key = name.replace("twitter:", "") as keyof SocialMetadata;
          // OG 데이터가 없는 경우에만 Twitter Card 데이터 사용
          if (!metadata[key]) {
            metadata[key] = content;
          }
        }
      },
    })
    // 일반 meta 태그로 폴백
    .on('meta[name="description"]', {
      element(el) {
        const content = el.getAttribute("content");
        if (content && !metadata.description) {
          metadata.description = content;
        }
      },
    })
    // title 태그로 폴백
    .on("title", {
      text(text) {
        if (!metadata.title) {
          metadata.title = text.text;
        }
      },
    });

  // 응답 처리
  await rewriter.transform(response).blob();

  // 상대 이미지 URL 을 절대로 변환
  if (metadata.image && !metadata.image.startsWith("http")) {
    try {
      metadata.image = new URL(metadata.image, url).href;
    } catch {
      // 파싱에 실패하면 원래 URL 유지
    }
  }

  return metadata;
}
ts
// 사용 예시
const metadata = await extractSocialMetadata("https://bun.com");
console.log(metadata);
// {
//   title: "Bun — A fast all-in-one JavaScript runtime",
//   description: "Bundle, transpile, install and run JavaScript & TypeScript projects — all in Bun. Bun is a fast all-in-one JavaScript runtime & toolkit designed for speed, complete with a bundler, test runner, and Node.js-compatible package manager.",
//   image: "https://bun.com/share.jpg",
//   type: "website",
//   ...
// }

Bun by www.bunjs.com.cn 편집