ソーシャル共有画像と Open Graph タグを抽出する
Bun の HTMLRewriter API は、HTML コンテンツからソーシャル共有画像と Open Graph メタデータを効率的に抽出するために使用できます。これは、リンクプレビュー機能、ソーシャルメディアカード、または Web スクレイパーの構築に特に役立ちます。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 メタタグを抽出
.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 メタタグを抽出
.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;
}
}
},
})
// 通常のメタタグにフォールバック
.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 を絶対 URL に変換
if (metadata.image && !metadata.image.startsWith("http")) {
try {
metadata.image = new URL(metadata.image, url).href;
} catch {
// 解析に失敗した場合は元の URL を保持
}
}
return metadata;
}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
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
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",
// ...
// }1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10