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

[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との相性もいいし、色々と面白い遊び方ができそうな気もする。 時間があればもっとじっくりといじくり回してみたいものだ。

キーワード
C# Web
シェアする
サイトマップ SITEMAP 写真データ販売中! STOCKPHOTO 写真のデータ販売について 広告 写真 PHOTO
虹雲舞う
黄金雲
曙光
お山の初詣
元旦
雪の夜明かし峠
冬の大峰山脈
朝の冬富士
未明の富士
写真の一覧へ
エリア
ネパール 北海道 東北 屋久島 沖縄 北アルプス 石鎚山系 剣山地 鳥取大山 くじゅう連山 丹沢・大山 富士山
被写体
河川・湖沼 森林 湿原・草原 雲・霧 石・岩 雪・氷 生物 植物 街・集落 鉄道 神社 寺院 人物 生活
季節
時間
夕方 マジックアワー
オレンジ・黄 ピンク・紫 茶色 虹色
キーワード
石鎚神社
販売
Aflo PIXTA imagemart
タグ
トップ画像 傑作選
JOURNEY
2020年 冬の屋久島歩き旅
旅立ち
01. 龍神杉と縄文杉
02. 雪の宮之浦岳
他7ページ
2019年 厳冬期北海道徒歩横断
旅立ち
01. 北海道の首
02. 豪雪地帯を歩く
他6ページ
旅の一覧へ
コラム PHOTO BLOG
よもやま話
登山とパニック発作
写真撮影
逆光で撮る
コラムの一覧へ
カテゴリ
写真撮影 被写体 撮影機材 旅の道具 よもやま話
開発室 DEVELOPMENT BLOG
開発室の一覧へ
カテゴリ
ASP.NET Core C# WordPress PHP TypeScript JavaScript Web
広告
サイトマップ SITEMAP
スタジオ旅路
https://tabiji.gallery
渡邊 佑
tabiji.gallery (c) 2020 Yu Watanabe サイトマップ SITEMAP 写真データ販売中! STOCKPHOTO 写真のデータ販売について 写真 PHOTO
虹雲舞う
黄金雲
曙光
お山の初詣
元旦
雪の夜明かし峠
冬の大峰山脈
朝の冬富士
未明の富士
写真の一覧へ
エリア
ネパール 北海道 東北 屋久島 沖縄 北アルプス 石鎚山系 剣山地 鳥取大山 くじゅう連山 丹沢・大山 富士山
被写体
河川・湖沼 森林 湿原・草原 雲・霧 石・岩 雪・氷 生物 植物 街・集落 鉄道 神社 寺院 人物 生活
季節
時間
夕方 マジックアワー
オレンジ・黄 ピンク・紫 茶色 虹色
キーワード
石鎚神社
販売
Aflo PIXTA imagemart
タグ
トップ画像 傑作選
JOURNEY
2020年 冬の屋久島歩き旅
旅立ち
01. 龍神杉と縄文杉
02. 雪の宮之浦岳
他7ページ
2019年 厳冬期北海道徒歩横断
旅立ち
01. 北海道の首
02. 豪雪地帯を歩く
他6ページ
旅の一覧へ
コラム PHOTO BLOG
よもやま話
登山とパニック発作
写真撮影
逆光で撮る
コラムの一覧へ
カテゴリ
写真撮影 被写体 撮影機材 旅の道具 よもやま話
開発室 DEVELOPMENT BLOG
開発室の一覧へ
カテゴリ
ASP.NET Core C# WordPress PHP TypeScript JavaScript Web