写真 ブログ 開発室
HOME開発室[C#] ウィキペディアのOGPを取得したい
キーワード
Web C#

[C#] ウィキペディアのOGPを取得したい

[C#] ウィキペディアのOGPを取得したい

ウィキペディアには一部しかOGPタグが指定されていない

ウィキペディアからOGPタグの内容を取得しようとすると、一部の項目しか取得できないことがわかる。 以下はウィキペディアのHTMLソースからOGP情報の部分を抜粋したものだ。

HTML
<meta property="og:image" content="https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Double-alaskan-rainbow.jpg/1200px-Double-alaskan-rainbow.jpg"/> <meta property="og:image:width" content="1200"/> <meta property="og:image:height" content="630"/> <meta property="og:image" content="https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Double-alaskan-rainbow.jpg/800px-Double-alaskan-rainbow.jpg"/> <meta property="og:image:width" content="800"/> <meta property="og:image:height" content="420"/> <meta property="og:image" content="https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Double-alaskan-rainbow.jpg/640px-Double-alaskan-rainbow.jpg"/> <meta property="og:image:width" content="640"/> <meta property="og:image:height" content="336"/> <meta property="og:title" content="虹 - Wikipedia"/> <meta property="og:type" content="website"/>

これを見てわかるようにウィキペディアのページではOGPの情報として画像、ページタイトル、ページ種別の3つしか記述されていない。

多くのサイトでは以下のように説明やサイト名などの項目も記述してあることが多く、ブログカードを作成するときなどはそれらの情報をそのまま表示すれば良いようになっている。

HTML
<meta property="og:url" content="https://tabiji.gallery" /> <meta property="og:type" content="website" /> <meta property="og:title" content="旅路 - さぁ、旅に出よう" /> <meta property="og:description" content="旅の中で出会った風景の写真や、写真に関するコラムを公開しています。写真データの販売や額装もおこなっております。" /> <meta property="og:site_name" content="旅路" /> <meta property="og:image" content="https://tabiji.gallery/_content/Tabiji.Core/image/logo-ogp.png" /> <meta property="og:locale" content="ja_JP" />

ウィキペディアのページ情報はAPIで取得できる

ではウィキペディアのページごとの説明などは取得できないのかというと、きちんと手段が用意されている。 ウィキペディアでは各ページの情報を取得するAPIを公開しており、それを通じて取得できるようになっている。

この中に、タイトルを指定してその記事の概要を取得できるAPIがある。 以下のようなURLを作成してAPIにアクセスすると、指定したタイトルから記事を検索してその概要をJSON形式で返してくれる。

https://ja.wikipedia.org/api/rest_v1/page/summary/虹

ここではというタイトルを指定してAPIを呼び出してみた。 このURLにアクセスすると以下のようなレスポンスが得られる。

JSON
{ "type": "standard", "title": "虹", "displaytitle": "<span class=\"mw-page-title-main\">虹</span>", "namespace": { "id": 0, "text": "" }, "wikibase_item": "Q1052", "titles": { "canonical": "虹", "normalized": "虹", "display": "<span class=\"mw-page-title-main\">虹</span>" }, "pageid": 255181, "thumbnail": { "source": "https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Double-alaskan-rainbow.jpg/320px-Double-alaskan-rainbow.jpg", "width": 320, "height": 168 }, "originalimage": { "source": "https://upload.wikimedia.org/wikipedia/commons/5/5c/Double-alaskan-rainbow.jpg", "width": 1919, "height": 1008 }, "lang": "ja", "dir": "ltr", "revision": "92137478", "tid": "d87f0d70-553b-11ed-869e-934fcce27b25", "timestamp": "2022-10-26T14:38:20Z", "description": "光が大気中に浮遊する水滴の中を通過する際に屈折・反射することで様々な色が見られる大気工学現象", "description_source": "central", "content_urls": { "desktop": { "page": "https://ja.wikipedia.org/wiki/%E8%99%B9", "revisions": "https://ja.wikipedia.org/wiki/%E8%99%B9?action=history", "edit": "https://ja.wikipedia.org/wiki/%E8%99%B9?action=edit", "talk": "https://ja.wikipedia.org/wiki/%E3%83%8E%E3%83%BC%E3%83%88:%E8%99%B9" }, "mobile": { "page": "https://ja.m.wikipedia.org/wiki/%E8%99%B9", "revisions": "https://ja.m.wikipedia.org/wiki/Special:History/%E8%99%B9", "edit": "https://ja.m.wikipedia.org/wiki/%E8%99%B9?action=edit", "talk": "https://ja.m.wikipedia.org/wiki/%E3%83%8E%E3%83%BC%E3%83%88:%E8%99%B9" } }, "extract": "虹 とは、大気中に浮遊する水滴の中を光が通過する際に、分散することで特徴的な模様が見られる大気光学現象である。", "extract_html": "<p><b>虹</b> とは、大気中に浮遊する水滴の中を光が通過する際に、分散することで特徴的な模様が見られる大気光学現象である。</p>" }

主要なものをいくつか列挙してみる。

titleタイトル
thumbnail.sourceサムネイル画像のURL
description説明
content_urls.desktop.page記事のURL
extract抜粋

この辺りが一般にOGPの情報として使用されるものたちだ。

後はこうして得られたJSON文字列を元に好みのプログラム言語で処理してやればよい。

C#でウィキペディアのOGPと同等のデータを取得する

参考までにC#でウィキペディアのOGPと同等のデータを取得するコードをざっくりと紹介したい。

C#
var apiUrl = "https://ja.wikipedia.org/api/rest_v1/page/summary/虹"; var client = new HttpClient(); var response = await client.GetAsync(apiUrl); var result = JsonNode.Parse(response.Content.ReadAsStream()); var siteName = "Wikipedia"; var url = result["content_urls"]["desktop"]["page"].ToString(); var title = result["titles"]["canonical"].ToString(); var description = result["extract"].ToString(); var imageUrl = result["thumbnail"]["source"].ToString();

これで一般的にOGPで必要とされる主要な項目を取得できる。

なお細かいチェックなどは省略しているので必要に応じて実装してもらいたい。

JsonSerializer.Deserialize<TValue>()で独自のクラスにマッピングする

あるいは手間を惜しまないのであれば、ウィキペディアのAPIが返すJSONの形式に合わせたクラスを定義して、そこへJsonSerializer.Deserialize<TValue>()を使いデータをマッピングするという手もある。

例えばウィキペディアのページ概要を取得するAPIのレスポンスデータに合わせた以下のようなクラスを定義する。 なお以下のサンプルはほぼ最低限のプロパティしか定義していないので、他に必要なデータがある場合は適宜プロパティを追加する必要がある。

C#
class WikipediaPageSummary { public class Thumbnail { public string source { get; set; } public int width { get; set; } public int height { get; set; } } public class ContentUrls { public class ContentUrlItem { public string page { get; set; } } public ContentUrlItem desktop { get; set; } } public string title { get; set; } public Thumbnail thumbnail { get; set; } public ContentUrls content_urls { get; set; } public string extract { get; set; } }

これを以下のように使用する。

C#
var apiUrl = "https://ja.wikipedia.org/api/rest_v1/page/summary/虹"; var client = new HttpClient(); var response = await client.GetAsync(apiUrl); var result = JsonNode.Parse(response.Content.ReadAsStream()); var json = await response.Content.ReadAsStringAsync(); var summary = JsonSerializer.Deserialize<WikipediaPageSummary>(json); var imageUrl = summary.thumbnail.source;

これは想定通りにデータを取得することができる。

imageUrl: https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Double-alaskan-rainbow.jpg/320px-Double-alaskan-rainbow.jpg

マッピング用のクラスを定義するのが若干面倒ではあるが、コードとしては最もわかりやすいものになるだろう。

JsonSerializer.Deserialize<ExpandoObject>()はうまくいかない

ちなみに自分もそうだったのだが、中にはJsonSerializer.Deserialize<ExpandoObject>()を使ってデータを取得しようとする人がいるかもしれない。 しかしこれはほとんどの人にとって想定通りの動作をしてくれないことだろう。

C#
var apiUrl = "https://ja.wikipedia.org/api/rest_v1/page/summary/虹"; var client = new HttpClient(); var response = await client.GetAsync(apiUrl); var result = JsonNode.Parse(response.Content.ReadAsStream()); var json = await response.Content.ReadAsStringAsync(); dynamic obj = JsonSerializer.Deserialize<ExpandoObject>(json); // これは想定したようには動かない var imageUrl = obj.thumbnail.source;

これを実行すると以下のような例外が発生する。

'System.Text.Json.JsonElement' does not contain a definition for 'source'

JsonSerializer.Deserialize<ExpandoObject>(json)の処理自体は成功するのだが、そこで得られたExpandoObjectのインスタンスが保持する各プロパティの値はJsonElementというクラスのインスタンスで表現されている。 理想を言えば文字列ならstringに、整数値ならintに、階層構造を持っていたらそこもExpandoObjectにしてくれればアクセスしやすいのだが、残念ながらそのような結果を返すようにはなっていない。

ひとりごと

なぜウィキペディアのOGPはタイトルと画像だけという中途半端な状態になっているのだろうか。 何か理由があるのかもしれないが、それが何なのか気になるところだ。

それはそうとこのウィキペディアに用意されている各種APIはなかなか興味深いものがある。 レスポンスがJSON形式なのでJavaScriptとの相性もいいし、色々と面白い遊び方ができそうな気もする。 時間があればもっとじっくりといじくり回してみたいものだ。

キーワード
Web C#
シェアする
サイトマップ SITEMAP 広告 写真 PHOTO
年度
2024 2023 2022 2021 2020 2019 2018 2017 ~2016
アルバム
傑作選 北海道 石鎚山系 ネパール 屋久島 北アルプス
写真の一覧へ
ストックフォトで作品を探す
JOURNEY
2020年 冬の屋久島歩き旅
2019年 厳冬期北海道徒歩横断
旅の一覧へ
ブログ BLOG
カテゴリ
写真 よもやま話
タグ
スポット 道具 心得
ブログの一覧へ
開発室 DEVELOPMENT
カテゴリ
ASP.NET Core C# WordPress PHP TypeScript JavaScript Web
開発室の一覧へ
広告
サイトマップ SITEMAP
スタジオ旅路
https://tabiji.gallery
渡邊 佑
tabiji.gallery (c) 2020 Yu Watanabe サイトマップ SITEMAP 写真 PHOTO
年度
2024 2023 2022 2021 2020 2019 2018 2017 ~2016
アルバム
傑作選 北海道 石鎚山系 ネパール 屋久島 北アルプス
写真の一覧へ
ストックフォトで作品を探す
JOURNEY
2020年 冬の屋久島歩き旅
2019年 厳冬期北海道徒歩横断
旅の一覧へ
ブログ BLOG
カテゴリ
写真 よもやま話
タグ
スポット 道具 心得
ブログの一覧へ
開発室 DEVELOPMENT
カテゴリ
ASP.NET Core C# WordPress PHP TypeScript JavaScript Web
開発室の一覧へ